Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

intel-Based Assembly Language idiv

Tags:

x86

assembly

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.

like image 263
user2922055 Avatar asked Apr 27 '26 09:04

user2922055


2 Answers

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.

like image 107
johnfound Avatar answered Apr 28 '26 22:04

johnfound


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.

like image 25
Leeor Avatar answered Apr 28 '26 23:04

Leeor



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!