私は現在、入力として.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(商)を生成する必要があります。しかし、浮動小数点例外が発生し、問題を見つけることができないようです。
どんな助けでも大歓迎です!
Mysticialsの答えの最初の部分は正しいです。idiv
は128/64ビット除算を行うため、被除数の上位64ビットを保持するrdx
の値にランダムな値を含めることはできません。しかし、ゼロ拡張は間違った方法です。
signed変数があるので、signrax
をrdx:rax
に拡張する必要があります。これには特定の命令があります。AT&Tではcqto
(quadをoctに変換)、Intel構文ではcqo
です。 AFAIKの新しいバージョンのガスは両方の名前を受け入れます。
movq %rdx, %rbx
cqto # sign extend rax to rdx:rax
idivq %rbx
idivq
命令は、128ビット整数(rdx:rax
)をオペランドで除算します。
rax
は、被除数の下位64ビットを保持します。rdx
は、被除数の上位64ビットを保持します。商が64ビットに収まらない場合、その浮動小数点例外がスローされます。
したがって、あなたがする必要があるのは、rdx
をゼロにすることです。
movq %rdx, %rbx
xorq %rdx, %rdx # zero "rdx"
idivq %rbx
符号付き整数を扱う場合は、rax
をrdx:rax
に符号拡張する必要もあります。つまり、rax
符号ビットをrdx
のすべてのビットにコピーします。 cqoエイリアスcqtoで実現されます:
movq %rdx, %rbx
cqo
idivq %rbx