【问题标题】:why if the number I enter gets to high it returns the wrong number [closed]为什么如果我输入的数字很高,它会返回错误的数字[关闭]
【发布时间】:2016-04-15 15:57:58
【问题描述】:

我有以下代码,但我不知道为什么如果我输入的数字太高,它会返回错误的数字。这可能是因为数据类型以及除法和乘法,但我无法弄清楚为什么。如果您知道为什么我会感谢您的帮助。

.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

【问题讨论】:

  • Microsoft 在其 Visual Studio 环境中有一个不错的调试器。 Ollydbg 也可以。
  • 当你说“太高”和“错误的数字”时,你并没有给我们太多帮助。作为一种猜测,我认为您正在尝试使用一个大于您设计代码要处理的大小的数字。

标签: winapi assembly x86 masm


【解决方案1】:

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

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 函数,该函数始终返回寄存器EAX 中的return 值。返回后,将 32 位返回值的低 8 位分配给 byte ptr buffer+[ebx],从中减去 30h。然后你 MOV 刚刚在 AL 中修改的 8 位,以及从 AH 中保留的返回值作为块 AXWORD 变量的 8 位 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(lower:higher) 中返回。因此,您的 mov actualNumber,ax 仅是 MOVs 变量的低 16 位(DX 被忽略,将您的结果限制为 result % 65536)。因此,您的最大可能结果是 MAX_WORD = 65535。其他所有内容只会给您以 AX 的模数。

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

然后你(重新)将此值添加到变量actualNumberadd actualNumber,ax。让我浓缩最后两段:

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

因此,您正在通过 AL 修改 AX 的低 8 位,然后将 actualNumber/AH 的高 8 位添加到自身 - 有效地将 AH 加倍,然后将其添加到actualNumber 像这样:

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

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

【讨论】:

  • 谢谢你的帮助,但我不明白actualNumber = 256 * (2 * AH) + (byte ptr buffer[ebx]-30h)
  • @dummieadam:很简单:AX 是 (256*AH)+AL。或者用另一种表示法:AX=AH*256+AL。换句话说:像 AX 这样的 16 位值确实由两个 8 位值(AHAL)组成,“更高”的 8 位“加权”为 2^8= 256.所以AX(16-bit) = AH(8-bit)*256 + AL(8-bit).
猜你喜欢
  • 2011-02-10
  • 2012-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-15
  • 1970-01-01
相关资源
最近更新 更多