2012-04-27 39 views
21

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

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(商)を生成する必要があります。しかし、私は浮動小数点の例外を取得している、と私は問題を見つけるように見えることはできません。

ご協力いただければ幸いです。

+0

この質問には関係ありませんが、 'esp'レジスタを調整しないで' movq%rdi、-40(%rbp) 'を実行する必要がありますか?それとも、x64の「赤いゾーン」のためにOKですか? –

答えて

23

ミスティカルズの答えの最初の部分が正しく、idivは128/64ビット除算を行うので、被除数の上位64ビットを保持するrdxの値にはランダム値を入れてはいけません。しかし、ゼロ拡張は間違った方法です。

あなたは変数を締結してきたように、あなたは記号rdx:raxraxを拡張する必要があります。具体的な指示はcqtoクワッドからオクテットへの変換)で、Intelの構文ではAT & Tとcqoです。 AFAIKの新しいバージョンのガスは両方の名前を受け入れます。

movq %rdx, %rbx 
cqto     # sign extend rax to rdx:rax 
idivq %rbx 
+0

+1私が署名された部分を見落とした面白い方法。 – Mysticial

+0

実際、テストを実行していて、符号付きの値を処理するときにエラーが発生しました。私は以前この指示を見ていないが、今問題を解決しているようだ。ありがとうございました! –

+0

@Mysticialでも最高です:-) – hirschhornsalz

11

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

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

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

だから、あなたが何をする必要があるかゼロrdxにある:あなたが符号付き整数を扱っている場合は、あなたもrdx:raxraxを符号拡張する必要が

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

、それはrax符号ビットをコピーすることを意味rdxのすべてのビットに対応し、cqoエイリアスcqtoで達成されます:

movq %rdx, %rbx 
cqo 
idivq %rbx 
+5

rdxを0にすると正の数で動作しますが、負のraxの場合はおそらくrdx = -1が必要です...そうではありませんか? – marekb

+5

私はmarekbが正しいと思います。 'xorq'は' rax'を 'rdx:rax'に拡張するための' cqo'命令であってはなりませんか? –

+0

この場合、署名付きの入力:私はそう思います。 –

関連する問題