Search code examples
nasmmov

NASM mov doesn't work correctly


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

Solution

  • You're scanning for two ints, 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)