为什么如果我输入的数字变高,它返回错误的数字

时间:2016-04-15 15:57:59

标签: winapi assembly x86 masm

我有以下代码,但我无法理解为什么如果我输入的数字太高,它会返回错误的数字。这可能是因为数据类型和分割和乘法,但我无法确切地解释为什么。如果你知道为什么我会感激你的帮助。

.586
.model flat, stdcall
option casemap :none
.stack 4096
extrn ExitProcess@4: proc

GetStdHandle proto :dword
ReadConsoleA  proto :dword, :dword, :dword, :dword, :dword
WriteConsoleA proto :dword, :dword, :dword, :dword, :dword
STD_INPUT_HANDLE equ -10
STD_OUTPUT_HANDLE equ -11

.data

    bufSize = 80
    inputHandle DWORD ?
    buffer db bufSize dup(?)
    bytes_read  DWORD  ?
    sum_string db "The number was ",0
    outputHandle DWORD ?
    bytes_written dd ?
    actualNumber dw 0
    asciiBuf db 4 dup (0)
.code
  main:

    invoke GetStdHandle, STD_INPUT_HANDLE
    mov inputHandle, eax
    invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr bytes_read,0
    sub bytes_read, 2   ; -2 to remove cr,lf
    mov ebx,0

    mov al, byte ptr buffer+[ebx] 
    sub al,30h
    add [actualNumber],ax
getNext:
    inc bx
    cmp ebx,bytes_read
    jz cont
    mov ax,10
    mul [actualNumber]
    mov actualNumber,ax
    mov al, byte ptr buffer+[ebx] 
    sub al,30h
    add actualNumber,ax

    jmp getNext
cont:


    invoke GetStdHandle, STD_OUTPUT_HANDLE
    mov outputHandle, eax
    mov eax,LENGTHOF sum_string ;length of sum_string
    invoke WriteConsoleA, outputHandle, addr sum_string, eax, addr bytes_written, 0
    mov ax,[actualNumber]
    mov cl,10
    mov bl,3
nextNum:
    xor edx, edx
    div cl
    add ah,30h
    mov byte ptr asciiBuf+[ebx],ah
    dec ebx
    mov ah,0
    cmp al,0
    ja nextNum

    mov eax,4

    invoke WriteConsoleA, outputHandle, addr asciiBuf, eax, addr bytes_written, 0

    mov eax,0
    mov eax,bytes_written
    push    0

    call    ExitProcess@4
end     main

1 个答案:

答案 0 :(得分:2)

是的,您的返回值受最大值限制是合理的。这个最大值是255的BYTE边界或65536的WORD边界。让我逐一解释原因:

mov inputHandle, eax
invoke ReadConsoleA, inputHandle, addr buffer, bufSize, addr bytes_read,0
sub bytes_read, 2   ; -2 to remove cr,lf
mov ebx,0

mov al, byte ptr buffer+[ebx] 
sub al,30h
add [actualNumber],ax

在这部分中,您调用Win32 API函数,该函数始终返回寄存器return中的EAX值。返回后,将32位返回值的低8位分配给byte ptr buffer+[ebx],从中减去30h。然后,MOV刚刚在AL中修改的8位,以及AH中保留的返回值中的8位作为块AXWORD变量add [actualNumber],ax。因此AH源于EAX返回值并且非常undefined。如果它是0,你可能会很幸运,但不应该这样做。

下一个问题是以下子程序:

getNext:
  inc bx
  cmp ebx,bytes_read
  jz cont
  mov ax,10
  mul [actualNumber]
  mov actualNumber,ax
  mov al, byte ptr buffer+[ebx] 
  sub al,30h
  add actualNumber,ax
  jmp getNext

您正在将小数基数10移至WORD寄存器AX,并将其乘以WORD变量[actualNumber]。到现在为止还挺好。但是16位* 16位MUL的结果在寄存器对AX:DX中返回(低位:更高)。因此,mov actualNumber,axMOV变量DX的低16位被忽略,将结果限制为result % 65536。因此,您的最大可能结果是MAX_WORD = 65535.其他所有内容都只会在AX中为您提供模数。

mov al, byte ptr buffer+[ebx]覆盖此结果的低8位后,BYTE指向buffer[ebx],然后从中减去30h。请记住:结果的高8位仍然保留在AH中,即AX的高8位。

然后您(重新)使用actualNumber将此值添加到变量add actualNumber,ax。让我浓缩这最后两段:

Operation                        |        AX        |
                                 |  AL          AH  |
mov actualNumber,ax              | ................ |
mov al, byte ptr buffer+[ebx]    | ........     AH  |
sub al,30h                       | ....-30h     AH  |
add actualNumber,ax              | ................ |

因此,您正在修改AXAL的低8位,然后将actualNumber / AH的高8位添加到自身 - 实际上加倍AH然后将其添加到actualNumber,如下所示:

actualNumber = 256 * (2 * AH) + (byte ptr buffer[ebx]-30h)      ; I doubt you want that ;-)

这些问题可能会导致与预期结果的偏差。