2

我正在努力idiv正常工作,我读过你把你想要除以 25 的东西放进去,然后ebx把你想要除以 5 的东西放进去,然后你做

idiv ebx

然后将EAX= 5 然后EDX= 0。

但是在我的程序中并没有这样做,我所做的输入是100000000

输出:

千字节:100000000

兆字节:1869375819

想知道我在这里做错了什么?

%include "asm_io.inc"
;
; initialized data is put in the .data segment
;
segment .data
prompt db "Please enter the number of bytes:", 0
param db "1 = Calculate it in kilobytes", 0Ah, "2 = Calculate it in megabytes", 10, 0
output db "Kilobytes: %d", 0Ah, "MegaBytes: %d", 10, 0
;
;
segment .bss
;
input resd 1
input2 resd 1
choice resd 1
;
; code is put in the .text segment
;
segment .text
    global  asm_main
extern printf
asm_main:
    enter   0,0              
    pusha

    mov eax, prompt
    call print_string
    call read_int
    mov [input], eax
    mov [input2], eax

    sub esp, 10h
    push dword [output]
    push dword [input2]
    push dword [input]


    mov eax, param
    call print_string
    call read_int

    cmp eax, 1
    je kilobyte; Jump if eax is equal to 1

    cmp eax, 2
    je megabyte; Jump if eax equal to 2

kilobyte:
    pop eax             ; Pop input into eax
    cdq             
    mov ebx, 1024       ; Put 1024 into ebx
    idiv ebx             ; EAX = 100000000/1024 = 97656
    mov [input], eax    ; Move 97656 into var=input
    push dword [input]  ; Put into stack
    jmp megabyte

megabyte:
    pop eax             ; Pop input into eax
    cdq         
    mov ebx, 1048576    ; Put 1048576 into ebx
    idiv ebx             ; EAX = 100000000/1024 = 95
    mov [input2], eax   ; Move 95 into var=input    
    push dword [input]  ; Put into stack
    jmp printOut

printOut:
    mov dword [esp], output
    call printf

    add esp, 4 * 3


    add esp, 10h

    popa
    mov     eax, 0            
    leave                     
    ret

更新

好吧,我输入了,xor edx, edx但我仍然得到与以前相同的输出。我查看了我的电子书和其他网站,它说了同样的话,所以我真的不确定我做错了什么。也尝试了idiv没有运气的路线。

4

3 回答 3

6

关于分工

首先,对于您需要的目标(计算 MBytes 和 KBytes),您实际上需要 unsigned devision。因此,使用div指令而不是idiv.

其次,div实际上idiv将 64 位数字除以edx:eax指定为操作数的 32 位数字。但是您的edx寄存器包含随机数。

因此,您必须在eax除法之前将数字扩展为 64 位。

使用idiv

    cdq       ; convert signed 32bit number in eax into signed 64bit in edx:eax
    idiv  ebx

使用div

    xor   edx, edx  ; set edx to 0 in order to extend unsigned eax in edx:eax
    div   ebx

关于印刷品

您的打印代码看起来不对:

kilobyte:
    pop eax             ; Pop input into eax
    cdq             
    mov ebx, 1024       ; Put 1024 into ebx
    idiv ebx             ; EAX = 100000000/1024 = 97656
    mov [input], eax    ; Move 97656 into var=input
    push dword [input]  ; Put into stack
    jmp megabyte

megabyte:
    pop eax             ; Pop input into eax
    cdq         
    mov ebx, 1048576    ; Put 1048576 into ebx
    idiv ebx             ; EAX = 100000000/1024 = 95
    mov [input2], eax   ; Move 95 into var=input    
    push dword [input]  ; Put into stack
    jmp printOut

printOut:
    mov dword [esp], output
    call printf

    add esp, 4 * 3

一开始,为什么要跳转到下一个地址???CPU 将自行到达那里。这并不完全是错误,但会降低代码的可读性并且只是多余的。

    mov [input2], eax   ; Move 95 into var=input    
    push dword [input]  ; Put into stack

printOut:
    mov dword [esp], output
    call printf

    add esp, 4 * 3

在这里您可以看到,结果存储在 [input2] 中,但 [input] 被压入堆栈。为什么?下一条指令mov dword [esp], output覆盖堆栈中最后压入的值。

请注意,推送指令首先递减esp,然后将推送的值存储在 [esp]。在这里你需要push output

于 2013-11-08T07:18:36.127 回答
5

您需要初始化 EDX - 要么将其归零(xor edx, edx)并使用无符号操作,要么将 EAX 签名扩展至其中(cdq


IDIV 执行以下操作(链接):

将 AX、DX:AX 或 EDX:EAX 寄存器中的值(除数)除以源操作数(除数)并将结果存储在 AX (AH:AL)、DX:AX 或 EDX:EAX寄存器。源操作数可以是通用寄存器或内存位置。

该指令的动作取决于操作数大小(除数/除数),如下表所示: IDIV 结果 [header]Operand

在此处输入图像描述

由于您要除以 EBX,它将从 EDX:EAX 获得红利。您没有将 EDX 初始化为零,因此得到了垃圾结果。

于 2013-11-08T06:53:11.780 回答
1

结果与您对堆栈的使用一致。

代码的前三个“推送”,将堆栈保留为

  • 100000000
  • 100000000
  • 1869375819(对应于数据的字符串“千字节:%d ...”。

当您的代码到达 printOut 时,您使用 printf 字符串的地址覆盖最上面的值。所以你的堆栈是:

  • printf 字符串的地址
  • 100000000
  • 1869375819(对应于数据的字符串“Kilobytes: %d...”。)

printf 打印这两个值。

事实上,您似乎不需要所有的推送/弹出。唯一需要堆栈的地方是对 printf 的调用。肯定是 :

  • printf 字符串的地址
  • (千字节的结果:代码)
  • (兆字节的结果:代码)

当您将值保存到 input(以千字节为单位:)和 input2(以兆字节为单位使用:)时,您不需要弹出任何内容。

您可以使用 :

kilobyte:
   mov eax, [input]
   cdq
   mov ebx, 1024
   idiv ebx
   mov [input], eax

因此,输入现在包含 idiv 的结果。同样,以兆字节为单位:

megabyte:
   mov eax, [input2]
   cdq
   mov ebx, 1048576
   idiv ebx
   mov [input2], eax

与前面的代码一样,现在 input2 包含您想要的结果。最后,在 printOut 中:

printOut:
   push [input2]
   push [input]
   push $output
   call printf

祝你编码好运。

于 2020-09-23T00:38:46.690 回答