web-dev-qa-db-ja.com

X86アセンブリ-IDIV命令の処理

私は現在、入力として.cファイルを受け取り、アセンブリコード(X86、AT&T構文)を生成する単純なCコンパイラを作成しています。すべてが良好ですが、IDIVQ命令を実行しようとすると、浮動小数点例外が発生します。これが私の入力です:

int mymain(int x){
  int d;
  int e;
  d = 3;
  e = 6 / d;
  return e;
}

そして、これが私の生成されたコードです:

mymain:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movq    %rdi, -40(%rbp)
    movq    $3, -8(%rbp)
    movq    $6, %rax
    movq    -8(%rbp), %rdx
    movq    %rdx, %rbx
    idivq   %rbx
    movq    %rax, -16(%rbp)
    movq    -16(%rbp), %rax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size mymain, .-mymain

http://www.cs.virginia.edu/~evans/cs216/guides/x86.html によると、idivq%rbx%raxで6/d(商)を生成する必要があります。しかし、浮動小数点例外が発生し、問題を見つけることができないようです。

どんな助けでも大歓迎です!

23
elyas-bhy

Mysticialsの答えの最初の部分は正しいです。idivは128/64ビット除算を行うため、被除数の上位64ビットを保持するrdxの値にランダムな値を含めることはできません。しかし、ゼロ拡張は間違った方法です。

signed変数があるので、signraxrdx:raxに拡張する必要があります。これには特定の命令があります。AT&Tではcqtoquadをoctに変換)、Intel構文ではcqoです。 AFAIKの新しいバージョンのガスは両方の名前を受け入れます。

movq    %rdx, %rbx
cqto                  # sign extend rax to rdx:rax
idivq   %rbx
24
Gunther Piez

idivq命令は、128ビット整数(rdx:rax)をオペランドで除算します。

  • raxは、被除数の下位64ビットを保持します。
  • rdxは、被除数の上位64ビットを保持します。

商が64ビットに収まらない場合、その浮動小数点例外がスローされます。

したがって、あなたがする必要があるのは、rdxをゼロにすることです。

movq    %rdx, %rbx
xorq    %rdx, %rdx    # zero "rdx"
idivq   %rbx

符号付き整数を扱う場合は、raxrdx:raxに符号拡張する必要もあります。つまり、rax符号ビットをrdxのすべてのビットにコピーします。 cqoエイリアスcqtoで実現されます:

movq    %rdx, %rbx
cqo
idivq   %rbx
11
Mysticial