2016-08-23 3 views
0

2つの数字を取得し、除算したいと思います。 しかし、それは浮動小数点例外を投げつけるので、私はデバッグにgdbを使いました。私はraxに値を格納すると、その上位ビットが「破損」していることがわかりました。NASMのmovが正しく動作しません

[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 

答えて

1

次の2つのint秒間スキャンしている、と彼らはアドレスnumから始まる2つの32ビット整数(離れた4バイト)として格納されます。

したがって、その場所から64ビットを読み取ろうとすると、両方の32ビット値が取得されます。 0x14 == 20、0x28は入力した別の値です。

mov rax, [num]mov eax, [num](およびrdx)と置き換えることができます。これにより、これらのレジスタの最上位32ビットが自動的にクリアされます。


IDIV r/m64は除数によって(128ビットオクタワードrdxraxによって形成される)RDX:EAXを分割すること。
rdxを除数として使用することはお勧めできません。を0xkkkkkkkkkkkkkkkkで除算して得点を0x0000000000000001nnnnnnnnnnnnnnnnとすることを意味します。商の有効範囲は−2^632^63 − 1なので、範囲外の商のために除算エラーが発生します。


TL; DR:あなたはにcall scanf後のコードの3行を変更することで、この問題を解決することができるはずです:あなたの被除数と除数の両方が32ビットであるため、

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 

それとも、あなたはこれlikely be faster意志IDIV r/m32を使用することができます。

mov  eax, [num] 
cdq      ; sign-extend eax into edx 
mov  ebx, [num + 4] 
idiv ebx    

cdq/cqoedx/いっぱい記号ビットがeax/rax

関連する問題