user2922055
user2922055

Reputation: 23

intel-Based Assembly Language idiv

I'm trying to get idiv working properly and I've read you put what you want to divide such as 25 and then in ebx you put what you want to divide by such as 5 then you do

idiv ebx

which then puts EAX = 5 and then EDX = 0.

However it doesn't do that in my program the input I do is 100000000

output:

Kilobytes: 100000000

Megabytes: 1869375819

Was wondering what am I doing wrong here?

%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

UPDATE

Well I put in xor edx, edx but I am still getting the same output as before. I've looked into my ebook and other sites and it says same thing so I am really unsure of what I am doing wrong. As well tried the idiv route with no luck.

Upvotes: 2

Views: 13624

Answers (3)

João Monteiro
João Monteiro

Reputation: 66

The result is consistent with your use of the stack.

The first three "push" of your code, leave the stack as

  • 100000000
  • 100000000
  • 1869375819 (corresponding to string "Kilobytes: %d..." of your data.

When your code reaches the printOut, you overwrite the topmost value with the address of the string to printf. So your stack is :

  • (address of printf string)
  • 100000000
  • 1869375819 (corresponding to string "Kilobytes: %d..." of your data.)

And printf prints these two values.

In fact, appears that you don't need all that push/pop. The only place where the stack is needed is in the call to printf. It must be :

  • (address of printf string)
  • (result of kilobyte: code)
  • (result of megabyte: code)

As you saved the value into input (to use in kilobyte:) and input2 (to use in megabyte:), you don't need to pop anything.

you can use :

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

So, input now contains the result of idiv. Similarly, in megabyte :

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

As in the previous code, now, input2 contains the result you want. Finally, in printOut :

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

Good luck coding.

Upvotes: 1

johnfound
johnfound

Reputation: 7061

About the division

At first, for the goal you need (computing MBytes and KBytes) you need unsigned devision actually. So, use div instruction instead of idiv.

Second, div and idiv actually divide 64bit number in edx:eax by a 32bit number specified as an operand. But your edx register contains random number.

So, you have to expand the number in eax to 64bit before the division.

For idiv use:

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

For div use:

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

About the printint

Your printing code looks wrong:

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

At first, why to jump to the next address??? The CPU will get there by itself. This is not exactly error, but makes the code less readable and is simply redundant.

    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

Here you can see, that the result is stored in [input2], but [input] is pushed in the stack. Why? The next instruction mov dword [esp], output overwrites the last pushed value in the stack.

Notice that push instruction first decrements esp and then stores the pushed value at [esp]. Here you need push output instead.

Upvotes: 6

Leeor
Leeor

Reputation: 19746

You need to initialize EDX - either zero it (xor edx, edx) and use unsigned operations, or sign extend EAX into it (cdq)


IDIV does as follows (link):

Divides (signed) the value in the AX, DX:AX, or EDX:EAX registers (dividend) by the source operand (divisor) and stores the result in the AX (AH:AL), DX:AX, or EDX:EAX registers. The source operand can be a general-purpose register or a memory location.

The action of this instruction depends on the operand size (dividend/divisor), as shown in the following table: IDIV Results [header]Operand

enter image description here

Since you're dividing by EBX, it would take the dividend from EDX:EAX. You didn't initialize EDX to zero and therefor got junk result.

Upvotes: 5

Related Questions