GCCは奇妙な一時変数を追加する

私はこのコードを作成しました:

#include 

typedef unsigned int uint;
uint in[2]={1,2},out[2]={3,4};

int main() {

    in[0]=out[0]/10;
}

Linux上でGCC(v4.4.5、最適化なし)でコンパイルすると、結果のアセンブリは次のようになります。

0000000000400474 
: 400474: 55 push rbp 400475: 48 89 e5 mov rbp,rsp 400478: 8b 05 ae 03 20 00 mov eax,DWORD PTR [rip+0x2003ae] # 0082c 40047e: 89 45 fc mov DWORD PTR [rbp-0x4],eax 400481: ba cd cc cc cc mov edx,0xcccccccd 400486: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] 400489: f7 e2 mul edx 40048b: 89 d0 mov eax,edx 40048d: c1 e8 03 shr eax,0x3 400490: 89 05 8e 03 20 00 mov DWORD PTR [rip+0x20038e],eax # 600824 400496: c9 leave 400497: c3 ret 400498: 90 nop 400499: 90 nop 40049a: 90 nop 40049b: 90 nop 40049c: 90 nop 40049d: 90 nop 40049e: 90 nop 40049f: 90 nop

今、問題は、このコードは5行目で何をしているのですか?

40047e:       89 45 fc                mov    DWORD PTR [rbp-0x4],eax

メモリ内のある場所に再び[0]から取得した値を保存していませんか?なぜそうなのか?私はある場所にすぐに読み書きするように言っていませんでした。

今、この一時変数は、行番号7の400486番地に再び現れます。

400486:       8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]

この例のように、GCCは非常に非効率的なコードを生成しており、これらの一時的な格納のためにキャッシュラインを退去させます。確認してください、多分私が得ていない何かがあります。

0
rbp-0x4 はスタックではありませんか?以前は mov rbp、rsp です。
追加された 著者 K-ballo,
まあ、あなたは最適化がないと言った。
追加された 著者 Fred Larson,
もちろん、非効率的なコードを生成しています。あなたはそれを最適化しないように言いました。
追加された 著者 Dave,
スタックから%eax の値を保存して復元するだけです。配列は%ebx + 0x20038e にあります。
追加された 著者 Alexandre C.,

1 答え

GCCは -O0 でコンパイルすると非常に効率の悪いコードを作ります。見ているのは基本的にプログラムの内部表現の生の翻訳です。この内部表現にはいくつかの一時変数があり、ここでのロード/ストアのペアはそのような一時的なものを通る値です。より高い最適化レベルでは、これらの無駄なロード/ストアはほとんどなくなります。ただし、最も単純な解析でも -O0 で無効になります。

5
追加された
ありがとう、私はそれを得た。私は、GCCによって生成された元のコードが、-O0であっても、レジスタ値を保存したり復元したりせずにやったことをやると思っていました。
追加された 著者 Nulik,
@Neil:GCCにはいくつかの異なる中間表現があります:GIMPLE、SSA、RTL、...もちろんSSA形式は一時変数のロードを作成します。
追加された 著者 ninjalj,
私はそのILはスタックベースのマシンでなければならないと思います。私は return argc; を追加し、それを返す前にスタックにargcをコピーしました。 (私も単純な変数に入れ替えようとしましたが、スタックに(1 << 32)* 0.8 をコピーしました)。/Od コンパイラは一般的に mov eax、_out xor edx、edx mov ecx、10 div ecx 、eax (これは/O2 でmulを使用します)。
追加された 著者 Neil,