基于英特尔的汇编语言idiv

时间:2013-11-08 06:37:50

标签: assembly x86

我正在努力让idiv正常工作,而且我已经读过你想要划分的内容 例如25,然后在ebx中你把你想要除的东西比如5,然后你做

idiv ebx

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

然而,在我的程序中,我的输入不是 100000000

输出:

Kilobytes: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路线没有运气。

3 个答案:

答案 0 :(得分:5)

关于分部

首先,对于你需要的目标(计算MBytes和KBytes),你实际上需要无符号的划分。因此,请使用div指令代替idiv

其次,dividiv实际上将edx:eax中的64位数除以指定为操作数的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

关于printint

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

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

答案 1 :(得分:4)

您需要初始化EDX - 将其归零(xor edx, edx)并使用无符号运算,或将EAX扩展到其中(cdq


IDIV如下(link):

  

除以(签名)AX,DX:AX或EDX:EAX寄存器中的值   (被除数)由源操作数(除数)并存储结果   AX(AH:AL),DX:AX或EDX:EAX寄存器。源操作数可以是   通用寄存器或存储器位置。

     

这个动作   指令取决于操作数大小(被除数/除数),如图所示   在下表中:IDIV结果[header]操作数

     

enter image description here

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

答案 2 :(得分:1)

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

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

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

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

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

然后printf打印这两个值。

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

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

将值保存到输入(以千字节为单位使用)和输入2(以兆字节为单位使用)时, 您不需要弹出任何东西。

您可以使用:

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

祝你好运。