2017-09-20 28 views
3

我收到此錯誤:大會錯誤A2075:跳轉目標太遠:通過在LOOP指令25字節(S)

loop AdderLoop 

錯誤A2075:跳轉目標太遠:25字節( s)

這是一個加法器程序。

我還在學習poppush所以也許我沒有做正確的事情,但是好像我的變量ARRAY_SIZE沒有被正確存儲?

我在過程開始時將ARRAY_SIZE存儲在哪個寄存器中,並在過程結束時將其彈回。

.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 
+0

哪條線是149線? – fuz

+0

我的壞大聲,增加了行。 – Justin

+0

你應該將'loop'視爲像''xlatb'](http://felixcloutier.com/x86/XLAT:XLATB.html)或['aad'](http:// felixcloutier)這些古怪的遺留指令之一。 com/x86/AAD.html)不再值得使用,特別是如果你還在學習asm。從來沒有聽說過這些?我的確切點。查看https://stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-implemented-it-efficiently有些歷史背景爲什麼它很慢。 (如果'循環'很快,它會在優化時使用,但作爲初學者,您忽略它並不會丟失任何東西。) –

回答

5

問題是loop只能在任一方向上跳躍多達128個字節。看起來您的標籤距離loop adderLoop太遠。考慮用dec ecx替換loop,然後jnz adderLoop。有一個變種jnz可以跳得更遠,解決這個問題。通常,我建議避免使用loop指令,因爲它比可以替換它的dec ecx/jnz對慢。

+0

好吧,謝謝它現在可以使用。我在網上看到了解決方案,說同樣的事情,但最初並不完全明白解決方案的含義。我認爲人們說你在循環中比較的值不能大於128字節,而不是跳躍量。 – Justin

+0

有一個問題,你不需要在dec之後使用cmp? – Justin

+1

@Justin'dec'將會像'sub?,1'(CF保持不變)那樣設置除CF之外的所有標誌,所以如果您感興趣的是零值,則ZF已經對應於新值'cx'('ZF =(cx == 0);')之後的'cx'。 – Ped7g