我想获得两个数字并进行划分。 但它不断抛出浮点异常,所以我使用gdb进行调试,我发现当我将值存储到rax时,它的高位被损坏了。
当[num]为20d时,0x2800000014存储在rax。
当[num]为40d时,存储0x1400000028。
当我存储它们时,我猜它的一些高位被破坏(?)。问题是什么?
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
答案 0 :(得分:1)
您正在扫描两个int
,它们存储为两个32位整数(相隔4个字节),从地址num
开始。
因此,当您尝试从该位置读取64位时,您将获得两个32位值。 0x14 == 20,而0x28是您输入的另一个值。
您应该可以将mov rax, [num]
替换为mov eax, [num]
(同样适用于rdx
)。这将自动清除这些寄存器中最重要的32位。
请注意IDIV r/m64
除以RDX:EAX
(由rdx
和rax
组成的128位八角形)除数。
因此,使用rdx
作为除数不是一个好主意,因为这意味着您将0xkkkkkkkkkkkkkkkkmmmmmmmmmmmmmmmm
除以0xkkkkkkkkkkkkkkkk
,为您提供0x0000000000000001nnnnnnnnnnnnnnnn
的商。由于商的有效范围为−2^63
到2^63 − 1
,因为超出范围的商,您将获得分红错误。
tl; dr:您应该可以通过将call scanf
之后的3行代码更改为:
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
或者,既然你的被除数和除数都是32位,你可以使用IDIV r/m32
likely be faster:
mov eax, [num]
cdq ; sign-extend eax into edx
mov ebx, [num + 4]
idiv ebx
(cdq
/ cqo
使用edx
/ rdx
的符号位填充eax
/ rax