I want to get two numbers and do division. But it keeps throwing Float Point exception, so I used gdb to debug and I found that when I store value to rax, its high bits are 'corrupted'.
When [num] is 20d, 0x2800000014 is stored at rax.
When [num] is 40d, 0x1400000028 is stored.
I guess some of its high bit is currupted(?) when I store them. What's the problem?
section .data
in: db "%d %d", 0
len: equ $-in
section .bss
num: resd 2
section .text
main:
mov rdi, in
mov rsi, num
mov rdx, num + 4
xor rax, rax
call scanf
mov rax, [num] ; ------------- here
mov rdx, [num + 4]
idiv rdx
...
xor rax, rax
ret
You're scanning for two int
s, and they are stored as two 32-bit integers (4 bytes apart) starting at address num
.
Hence, when you try to read 64 bits from that location you get both 32-bit values. 0x14 == 20, and 0x28 is the other value you entered.
You should be able to replace mov rax, [num]
with mov eax, [num]
(and similarly for rdx
). This will automatically clear the most significant 32 bits of those registers.
Note that IDIV r/m64
divides RDX:EAX
(the 128-bit octaword formed by rdx
and rax
) by the divisor.
So it's not a good idea to use rdx
as the divisor, since that means you will be dividing 0xkkkkkkkkkkkkkkkkmmmmmmmmmmmmmmmm
by 0xkkkkkkkkkkkkkkkk
, giving you a quotient of 0x0000000000000001nnnnnnnnnnnnnnnn
. Since the valid range for the quotient is −2^63
to 2^63 − 1
you'll get a Divide Error because of an out-of-range quotient.
tl;dr: you should be able to fix this by changing the 3 lines of code after call scanf
to:
mov eax, [num]
cqo ; sign-extend rax into rdx
mov ebx, [num + 4] ; <-- note, ebx instead of edx
idiv rbx ; <-- note, rbx instead of rdx
Or, since both your dividend and divisor is 32-bit, you could use IDIV r/m32
which will likely be faster:
mov eax, [num]
cdq ; sign-extend eax into edx
mov ebx, [num + 4]
idiv ebx
(cdq
/cqo
fills edx
/rdx
with the sign-bit of eax
/rax
)