25

現在、.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 (商) を生成する必要があります。しかし、浮動小数点例外が発生しており、問題が見つからないようです。

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

4

2 に答える 2

26

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

変数に署名したので、に拡張に署名する必要があります。AT&TおよびIntel構文には、これに関する特定の命令があります(quadをoctに変換します)。AFAIKの新しいバージョンのガスは両方の名前を受け入れます。raxrdx:raxcqtocqo

movq    %rdx, %rbx
cqto                  # sign extend rax to rdx:rax
idivq   %rbx
于 2012-04-27T10:23:57.923 に答える
13

このidivq命令は、128 ビット整数 ( rdx:rax) を指定されたソース オペランドで除算します。

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

商が 64 ビットに収まらない場合、idiv障害が発生します (#DE 例外。OS は、算術例外の POSIX で必要とされるSIGFPE シグナルを配信することによって処理します)。

signed を使用するコードをコンパイルしているため、 sign extends tointも必要です。つまり、符号ビットを and のすべてのビットにコピーすることは、cqo エイリアス cqto で実現されます。raxrdx:raxraxrdx

movq    %rdx, %rbx        # or load into RBX or RCX in the first place
cqo
idivq   %rbx              # signed division of RDX:RAX / RBX

除算を行っていた場合はunsigned、RDX をゼロにして、RAX を RDX:RAX にゼロ拡張します。

movq    %rdx, %rbx
xor     %edx, %edx      # zero "rdx"
divq    %rbx            # unsigned division of RDX:RAX / RBX

また、x86-64 System V ABI では、int64 ビットではなく 32 ビットの符号付きタイプであることに注意してください。この場合、64 ビットに拡張することは有効ですが (結果が同じであるため)、特に除算の場合にコードが遅くなります。

于 2012-04-27T00:27:45.197 に答える