NASM mov 无法正常工作

NASM mov doesn't work correctly

我想得到两个数字并做除法。 但是一直抛Float Point异常,所以我用gdb调试,发现当我存值到rax时,它的高位是'corrupted'.

当[num]为20d时,rax存储0x2800000014

当[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

您正在扫描两个 int,它们存储为两个 32 位整数(相隔 4 个字节),从地址 num.

开始

因此,当您尝试从该位置读取 64 位时,您会得到两个 32 位值。 0x14 == 20,0x28 是您输入的另一个值。

您应该能够将 mov rax, [num] 替换为 mov eax, [num](对于 rdx 也是如此)。这将自动清除这些寄存器的最高 32 位。


注意IDIV r/m64除以RDX:EAX(由rdxrax组成的128位八字)除以除数。
所以使用 rdx 作为除数不是一个好主意,因为这意味着您将 0xkkkkkkkkkkkkkkkkmmmmmmmmmmmmmmmm 除以 0xkkkkkkkkkkkkkkkk,得到商 0x0000000000000001nnnnnnnnnnnnnnnn。由于商的有效范围是 −2^632^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/cqoeax/rax的符号位填充edx/rdx)