Assembly 为什么这是胡言乱语输出?

Assembly 为什么这是胡言乱语输出?,assembly,x86,Assembly,X86,我正在学习一门x86汇编编程课(这是我专业的必修课),出于某种原因,这段代码输出的是胡言乱语。我上班时间去了,教授看了我的代码也不知道为什么 基本上,教授希望我们使用idiv并将东西放入堆栈中,以便将它们从一个地方传递到另一个地方 我这么做了,但选择某些数字会和数字一起输出胡言乱语,或者只是简单的胡言乱语 我完全不知道该怎么办 我们将不胜感激 .model flat, stdcall .stack 4096 ExitProcess PROTO ,dwExitCode:DWORD INCLUDE

我正在学习一门x86汇编编程课(这是我专业的必修课),出于某种原因,这段代码输出的是胡言乱语。我上班时间去了,教授看了我的代码也不知道为什么

基本上,教授希望我们使用idiv并将东西放入堆栈中,以便将它们从一个地方传递到另一个地方

我这么做了,但选择某些数字会和数字一起输出胡言乱语,或者只是简单的胡言乱语

我完全不知道该怎么办

我们将不胜感激

.model flat, stdcall
.stack 4096
ExitProcess PROTO ,dwExitCode:DWORD
INCLUDE c:\irvine\Irvine32.inc      ;Change path if necessary
include c:\irvine\macros.inc
includelib c:\irvine\irvine32.lib
includelib c:\irvine\kernel32.lib
includelib c:\irvine\user32.lib

.data
X DWORD 0
Y DWORD 0
A DWORD 90
B DWORD 0
W SDWORD ?                      ;W can be + or - 
inputX BYTE "input X =", 0          ;IrvineLib WriteString expects null terminated string
inputY BYTE "input Y =", 0
outputW BYTE "output W=", 0
newline BYTE 0dh, 0ah, 0
calcW BYTE "calculating W....", 0
continue BYTE "Press Any Any key to continue or q to QUIT", 0
;
.code
main proc
    
   call CrLf
topMain:
  mov  esi, offset InputX   ;inputX=?
  call getInput
  mov X,eax
  call CrLf
;  
  mov esi, offset InputY    ;inputY=?
  call getInput
  mov Y, eax
  call CrLf

  mov edx, offset calcW     ;print calculating W
   call WriteString
   call CrLf            ; added this myself
  push Y                ; pass input PARAMETERS Right to left on STACK 
  push X
  call calculateW
  ;Caller Cleans up the Stack
  add esp,8         ;deallocate two 4Byte input parameters from stack
  mov W,eax         ;output parameter returned in register

  mov edx, offset outputW   ;Print "OutputW=""
  call WriteString
  push W                ;input parameter on STACK
  call outW
  ;Caller cleans up the Stack
  add esp, 4            ;deallocate one 4-Byte input parameter from Stack
   
   call CrLf
  mov edx, offset continue  ;prompt to continue or quit
  call WriteString
   
   call CrLf
  call readchar             ;this procedure does not echo
  cmp al,'q'
  jne topMain   
  invoke exitprocess,0
main endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 getinput proc
;Get Decimal Number from the keyboard and press enter key when done. 
; ENTER key is CR = 0Dh
;This procedure calculates the binary equivalent of the decimal number it is typed and puts the result in a register.
;The Number is assumed to be positive, ie. Unsigned
;This procedure is the same as in Lab7.  
;Entry: esi = address to string which prompts for input.
;Exit: eax = Result of the calculated number.
    mov edx, esi ; Prompt user for xinput
    call writestring

    mov edi,0           ; initialize edi to 0
    xLoop:
        mov ecx, edi    ; move edi into ecx 
        mov eax,10      ; move 10 to eax
        imul edi            ; multiply x by eax 
        mov edi, eax    ; move eax to x

        call readchar   ; read and echo input
        call WriteChar  

        cmp al, 0dh     ; If al contains enter key, exit loop, else continue.
        je outOfLoop    

        sub al,30h      ; convert to interger
        movzx ebx, al   ; move from al to ebx

        add edi, ebx    ; add ebx to edi
    
        jmp xLoop       

        outOfLoop:      ;Where user goes when they hit enter to exit loop
        
        mov eax,ecx
        

    ret
    getinput endp

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CalculateW proc
;Calculates a value based on X and Y inputs
;INPUT:  X and Y . Y was pushed first
;OUTPUT: eax contains result.
;THIS VERSION USES LOCAL VARIABLES ALLOCATED ON STACK
;local variables are loc1,loc2,loc3,and sum
;All the local variables are 4 bytes (DWORD) and are
;explicitly allocated on the stack and accessed from the stack.
    
    push ebp        ; save ebp
    mov ebp, esp
    sub esp,16      ; Allocate stack space
    
    ;do loc 1
    mov eax, 160    ; set eax to 160
    imul DWORD PTR [ebp+12] ; multiply y by eax
    mov ebx,eax     ; Move eax to ebx to save y * 160   ----- EBX is Intermediary
    mov eax, 2      ; now set eax to 2
    imul DWORD PTR [ebp+8]      ; multiply x times eax
    add eax, ebx    ; eax =  Y * 160 + X * 2 ---------------ebx is now free
    mov DWORD PTR [ebp-4], eax  ; move eax to ebx which is our loc1. 

    ;do loc2
    mov eax, 950    ; Set eax to 950
    mov edi, 90     ; since we're just using registers, and x is already done A = edi = 90
    imul edi            ; multiply a by eax
    mov DWORD PTR [ebp-8], eax  ; copy eax to edi which is our loc2. 

    ;do loc3
    mov ebx, DWORD PTR [ebp-4]  ; Put loc 1 into a register so I can do math.
    mov edi, DWORD PTR [ebp-8]  ; Put loc 2 into a register so I can do math
    sub edi,ebx     ; Subtract loc1 from loc2.
    mov DWORD PTR [ebp-12],edi  ; move loc2-loc1 to loc3.

    ;do y
    mov DWORD PTR [ebp+12],3000 ; set y to 3000
    sub DWORD PTR [ebp+12],1        ;subtract 1 from y
 
    ;do sum
    mov eax, DWORD PTR [ebp-12]     ; move loc3 into eax
    cdq
    mov edi,16          ; move 16 into edi
    idiv edi 

    mov [ebp-16],eax            ; move loc3/16 somewhere so we don't lose it.

    mov eax, DWORD PTR [ebp+12]
    cdq
    mov edi,4
    idiv edi

    add DWORD PTR [ebp-16],eax          ; sum= loc3/16 + y/4

    mov eax, DWORD PTR [ebp+12] 
    cdq
    mov edi,200
    idiv edi

    add DWORD PTR [ebp-16],eax          ; sum= loc3/16 + y/4 + y/200.

    mov eax, DWORD PTR [ebp+12] ;put y into register

    add DWORD PTR [ebp-16],eax      ; sum= loc3/16 + y/4 + y/200 +y.

    mov eax,DWORD PTR [ebp-16]
    cdq
    mov edi,3907    
    idiv edi            ; divide by 3907 per professor's office hour feedback

    add edx,3       ; Add 3 to modulus. 
    mov eax,edx     ; move the modulus from to eax. 

    mov esp,ebp
    pop ebp


   ret
   calculateW endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
outW proc
;This procedure outputs MULTIPLE DECIMAL DIGITS on the screen.
;The algorithm is based on repeated division of quotient by 10  
;REMAINDERs are kept on the Stack and retrived in the reverse order.
; The number to be printed can be positive or negative.
;This procedure must print "-" sign if the number is negative.   
;INPUT parameter:W=number to be printed in binary. Caller Pushed W on Stack before this procedure is called. 
;OUTPUT parameter: None

 COMMENT &
ALGORITHM FOR CHECKING IF NUMBER IS NEGATIVE AND CONVERTING AND PRINTING NEGATIVE SIGN AS NEEDED.
  1. Get parameter (W=number) to be printed from the stack
  2. Check if number is negative or positive
  3. If it is positive  Go to Step 8 to ConvertToDec and Print
  4. If not, it is negative. Convert to positive (Use NEG instruction)before converting to decimal
  5. save it temporarily
  6. Display Negative Sign
  7. get Number back into eax. It will be the dividend in the division below
8. Convert to Decimal. This step is exactly the same as the code you used in Lab 7
&

    push ebp
    mov ebp,esp

    ; Figure out if number is positive or negative
    mov eax, DWORD PTR [ebp+8]      ; Get W result value
    cmp eax,0           ; Check if number is negative or positive
    jge ConvertToDec    ; If number is positive, convert to decimal else...
    neg eax             ; If number is negative, convert it to positive. 
    mov ebx,eax         ; Temporarily save the number. 
    mov al, "-"         ; Put negative sign in al register for printing. 
    call WriteChar      ; Print negative sign. 
    mov eax,ebx         ; Put number back into eax. 

    
    mov ecx,0           ;set ecx counter to 0

    ConvertToDec:
        mov edi, 10     
        cdq
        idiv edi            ; divide eax / edi
        add edx,30h     ; convert to ascii by adding 30h.
        push edx
        add ecx, 1
        cmp eax,0
        jne ConvertToDec

        printingLoop:   ; LOOP TO POP STACK TO EAX ONE BY ONE
        pop eax
        call WriteChar      ; print eax.
        loop printingLoop

        call CrLf           ; add an extra line to make it pretty.

        mov esp,ebp
        pop ebp


  ret
outW endp
;;;;;;;;;;;;;;;;;;;;;;;;

end main```

在循环中递增之前,在
out
中使用未初始化的
ecx
寄存器。只有当
W
的值为正值时,错误才会出现

请参阅以下代码:

mov eax, DWORD PTR [ebp+8]      ; Get W result value
cmp eax,0           ; Check if number is negative or positive
jge ConvertToDec    ; If number is positive, convert to decimal else... (1)
neg eax             ; If number is negative, convert it to positive. 
mov ebx,eax         ; Temporarily save the number. 
mov al, "-"         ; Put negative sign in al register for printing. 
call WriteChar      ; Print negative sign. 
mov eax,ebx         ; Put number back into eax. 


mov ecx,0           ;set ecx counter to 0 (2)

ConvertToDec:
您有一个计数器(2)的初始化,但请注意,只有在没有执行第(1)行中的跳转时,才会执行该计数器。如果该值为正值,则跳过初始化。 要修复此问题,您的跳转(1)也必须使用
mov ecx,0
执行该行

因此,修复可能是这样的:

mov eax, DWORD PTR [ebp+8]      ; Get W result value
cmp eax,0           ; Check if number is negative or positive
jge go              ; If number is positive, convert to decimal else... (1)
neg eax             ; If number is negative, convert it to positive. 
mov ebx,eax         ; Temporarily save the number. 
mov al, "-"         ; Put negative sign in al register for printing. 
call WriteChar      ; Print negative sign. 
mov eax,ebx         ; Put number back into eax. 

go:
mov ecx,0           ;set ecx counter to 0 (2)

ConvertToDec:

或者,如果
WriteChar
没有破坏
ecx
(未检查),则可以在跳转之前将
ecx的零位移动到公共代码。

Irvine32函数使用自定义调用约定,保留所有寄存器,因此可以在该块之前简单地执行
xor ecx,ecx
。但是为了可读性,最好在使用它的循环之前设置它,即使这意味着一个单独的标签。不要只盯着你的代码和它的输出,用调试器单步执行。这应该让波维尔的答案所指出的问题变得显而易见。