Loops 汇编错误A2075:跳转目标太远:循环指令上的25字节

Loops 汇编错误A2075:跳转目标太远:循环指令上的25字节,loops,assembly,x86,Loops,Assembly,X86,我从以下位置获得此错误: loop AdderLoop 错误A2075:跳转目标太远:25字节 这是一个加法器程序 我仍在学习pop和push,所以可能我没有做正确的事情,但我的可变数组大小似乎没有正确存储 我在过程开始时将寄存器推入存储数组_大小的位置,并在过程结束时将其弹出 .386 ;identifies minimum CPU for this program .MODEL flat,stdcall ;flat - protected mode program

我从以下位置获得此错误:

loop    AdderLoop
错误A2075:跳转目标太远:25字节

这是一个加法器程序

我仍在学习
pop
push
,所以可能我没有做正确的事情,但我的可变数组大小似乎没有正确存储

我在过程开始时将寄存器推入存储数组_大小的位置,并在过程结束时将其弹出

.386      ;identifies minimum CPU for this program

.MODEL flat,stdcall    ;flat - protected mode program
                       ;stdcall - enables calling of MS_windows programs

;allocate memory for stack
;(default stack size for 32 bit implementation is 1MB without .STACK directive 
;  - default works for most situations)

.STACK 4096            ;allocate 4096 bytes (1000h) for stack

;*******************MACROS********************************

;mPrtStr
;usage: mPrtStr nameOfString
;ie to display a 0 terminated string named message say:
;mPrtStr message

;Macro definition of mPrtStr. Wherever mPrtStr appears in the code
;it will  be replaced with 

mPrtStr  MACRO  arg1    ;arg1 is replaced by the name of string to be displayed
         push edx
         mov edx, offset arg1    ;address of str to display should be in dx
         call WriteString        ;display 0 terminated string
         pop edx
ENDM

;*************************PROTOTYPES*****************************

ExitProcess PROTO,
    dwExitCode:DWORD    ;from Win32 api not Irvine to exit to dos with exit code

ReadChar PROTO          ;Irvine code for getting a single char from keyboard
                        ;Character is stored in the al register.
                        ;Can be used to pause program execution until key is hit.

WriteDec PROTO          ;Irvine code to write number stored in eax
                        ;to console in decimal

WriteString PROTO       ;Irvine code to write null-terminated string to output
                        ;EDX points to string

WriteChar PROTO         ;write the character in al to the console

;************************  Constants  ***************************

    LF         equ     0Ah                   ; ASCII Line Feed

;************************DATA SEGMENT***************************

.data
    carryIn    byte 0,0,0,0,1,1,1,1
    inputA     byte 0,0,1,1,0,0,1,1
    inputB     byte 0,1,0,1,0,1,0,1
    ARRAY_SIZE equ $ - inputB  

    ;The '$' acts as a place maker where you are currently in memory
    ;which at the end of the carryInNum array.
    ;The ending address of the carryInNum array minus the beginning
    ;address equals the total bytes of the carryInNum array
    ;which is stored in the ARRAY_SIZE constant.
    ;NOTE: there can be no other variables between the 
    ;declation of the ARRAY_SIZE constant and the declaration
    ;of the array you are trying to calculate the size of.

    ;You can add LFs to the strings below for proper output line spacing
    ;but do not change anything between the quotes "do not change".

    ;I will be using a comparison program to compare your output to mine and
    ;the spacing must match exactly.

    endingMsg           byte "Hit any key to exit!",0

    ;Change my name to your name
    titleMsg            byte "Program 4 by ",LF,0

    testingAdderMsg     byte " Testing Adder",0

    inputA_Msg           byte "   Input A: ",0
    inputB_Msg           byte "   Input B: ",0
    carryin_Msg          byte "  Carry in: ",0
    sum                  byte "       Sum: ",0
    carryout             byte " Carry Out: ",0

    dashes              byte LF," ------------",LF,0

;************************CODE SEGMENT****************************

.code

main PROC

    mov ecx, ARRAY_SIZE         ;ecx = ARRAY_SIZE
    mov esi, 0                  ;esi = 0

    mPrtStr titleMsg            ;print "Program 4 by"

AdderLoop:
    mPrtStr inputA_Msg          ;print "   Input A: "
    movzx   eax, inputA[esi]    ;eax = inputA[esi]
    INVOKE  WriteDec            ;write decimal stored in eax
    mov     al, LF              ;al = ASCII Line Feed
    INVOKE  WriteChar           ;write the character stored in al

    mPrtStr inputB_Msg          ;print "   Input B: "
    movzx   eax, inputB[esi]    ;eax = inputB[esi]
    INVOKE  WriteDec            ;write decimal stored in eax
    mov     al, LF              ;al = ASCII Line Feed
    INVOKE  WriteChar           ;write the character stored in al

    mPrtStr carryin_Msg         ;print "  Carry in: "
    movzx   eax, carryIn[esi]   ;eax = carryIn[esi]
    INVOKE  WriteDec            ;write decimal stored in eax
    mov     al, LF              ;al = ASCII Line Feed
    INVOKE  WriteChar           ;write the character stored in al

    call    adder               ;call the adder procedure

    mPrtStr dashes              ;print " ------------"

    mPrtStr sum                 ;print "       Sum: "
    mov     al, LF              ;al = ASCII Line Feed
    INVOKE  WriteChar           ;write the character stored in al

    mPrtStr carryout            ;print " Carry Out: "
    mov     al, LF              ;al = ASCII Line Feed
    INVOKE  WriteChar           ;write the character stored in al

    add     esi, 4              ;add 4 to esi to go to next element in the arrays
    loop    AdderLoop           ;ARRAY_SIZE--, if ARRAY_SIZE = 0 then end, else loop

    mPrtStr endingMsg           ;print "Hit any key to exit!"
    call    ReadChar            ;Pause program execution while user inputs a non-displayed char
    INVOKE  ExitProcess,0       ;Exit to dos: like C++ exit(0)

main ENDP

;IMPORTANT: Do not delete the function comment block below.
;           Every function should have a similar comment block
;           specifying what the function is about including:
;           - Description
;           - Input (Entry)
;           - Output (Exit)
;           - Registers used (REGS)

;************** Adder – Simulate a full Adder circuit  
;  Adder will simulate a full Adder circuit that will add together 
;  3 input bits and output a sum bit and a carry bit
;
;    Each input and output represents one bit.
;
;  Note: do not access the arrays in main directly in the Adder function. 
;        The data must be passed into this function via the required registers below.
;
;       ENTRY - EAX = input bit A 
;               EBX = input bit B
;               ECX = Cin (carry in bit)
;       EXIT  - EAX = sum bit
;               ECX = carry out bit
;       REGS  - EAX, EBX, ECX, ESI
;
;       For the inputs in the input columns you should get the 
;       outputs in the output columns below:
;
;        input                  output
;     eax  ebx   ecx   =      eax     ecx
;      A  + B +  Cin   =      Sum     Cout
;      0  + 0 +   0    =       0        0
;      0  + 1 +   0    =       1        0
;      1  + 0 +   0    =       1        0
;      1  + 1 +   0    =       0        1
;      0  + 0 +   1    =       1        0
;      0  + 1 +   1    =       0        1
;      1  + 0 +   1    =       0        1
;      1  + 1 +   1    =       1        1
;
;   Note: the Adder function does not do any output. 
;         All the output is done in the main function.
;
;Do not change the name of the Adder function.
;
;See additional specifications for the Adder function on the 
;class web site.
;
;You should use AND, OR and XOR to simulate the full adder circuit.
;
;You should save any registers whose values change in this function 
;using push and restore them with pop.
;
;The saving of the registers should
;be done at the top of the function and the restoring should be done at
;the bottom of the function.
;
;Note: do not save any registers that return a value (ecx and eax).
;
;Each line of the Adder function must be commented and you must use the 
;usual indentation and formating like in the main function.
;
;Don't forget the "ret" instruction at the end of the function
;
;Do not delete this comment block. Every function should have 
;a comment block before it describing the function. FA17


Adder proc

    push ecx                ;store ARRAY_SIZE for later

    movzx eax, inputA[esi]  ;eax = inputA[esi]
    movzx ebx, inputB[esi]  ;ebx = inputB[esi]
    movzx ecx, carryIn[esi] ;ecx = carryIn[esi]

    push eax                ;store inputA[esi] for later
    xor eax, ebx            ;eax = inputA[esi] XOR inputB[esi]
    push eax                ;store inputA[esi] XOR inputB[esi] for later
    xor eax, ecx            ;eax = (inputA[esi] XOR inputB[esi]) XOR carryIn[esi] (this is the sum)

    pop eax                 ;pop inputA[esi] XOR inputB[esi] into eax
    and ecx, eax            ;eax = (inputA[esi] XOR inputB[esi]) AND carryIn[esi]
    pop eax                 ;pop inputA[esi] into eax
    and eax, ebx            ;eax = inputA[esi] AND inputB[esi]
    or ecx, eax             ;ecx = ((inputA[esi] XOR inputB[esi]) AND carryIn[esi]) OR (inputA[esi] AND inputB[esi]) (this is the carry out)

    pop ecx                 ;pop ARRAY_SIZE into ecx

    ret                     ;return

Adder endp

END main

问题是
循环
最多只能向任一方向跳转128字节。您的标签似乎太远了,
loop adderLoop
够不着。考虑用<代码> DEC ECX替换<代码>循环<代码>,然后<代码> JNZ ADDROLUL>/代码>。jnz的一个变体可以跳得更远,解决了这个问题。一般来说,我建议避免使用
循环
指令,因为它比可以替换它的
dec ecx/jnz
对慢。

哪一行是第149行?我糟糕的lol,添加了这一行。你应该将
循环
视为那些奇怪的遗留指令之一,比如或不再值得用于任何东西,特别是如果你还在学习asm。没听说过吗?我的观点完全正确。请参阅,了解其缓慢原因的一些历史背景。(如果
loop
很快,那么它在优化时会有用处,但作为初学者,忽略它不会有任何损失。)好的,谢谢,它现在可以工作了。我在网上看到解决方案也说了同样的话,但一开始我不太明白解决方案的意思。我想人们会说循环中比较的值不能大于128字节,而不是跳转量。有一个问题,你不需要在dec之后使用cmp?@Justin
dec
将以与
sub?,1
相同的方式设置除CF以外的所有标志(CF保持不变),因此如果你感兴趣的是零值,ZF已经对应于
dec cx
之后的
cx
的新值(
ZF=(cx==0);
)。@Justin如果
dec
减小一个值,结果为零,则设置
ZF
。事实上,几乎所有算术指令(除了一些深奥的指令,如
adox
)都是这样设置
ZF