Reputation: 23
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
Reputation: 66
The result is consistent with your use of the stack.
The first three "push" of your code, leave the stack as
When your code reaches the printOut, you overwrite the topmost value with the address of the string to printf. So your stack is :
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 :
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
Reputation: 7061
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
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
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
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