2011-02-04 17 views
8

私はこのCプログラムをコンパイルし、生成されたアセンブリコードを比較しています:LLVMが同じプログラムに対して2つの追加命令を追加するのはなぜですか?

_main: 
LFB2: 
    pushq %rbp 
LCFI0: 
    movq %rsp, %rbp 
LCFI1: 
    movl $0, %eax 
    leave 
    ret 

LLVMこの主な機能を与える(clang hello.c -S):

int main(){ return 0; } 

GCCと、このメイン関数(cc hello.c -S)を与えます

_main: 
Leh_func_begin0: 
    pushq %rbp 
Ltmp0: 
    movq %rsp, %rbp 
Ltmp1: 
    movl $0, %eax 
    movl $0, -4(%rbp) 
    popq %rbp 
    ret 
Leh_func_end0: 

movl $0, -4(%rbp)popq %rbpは何のために必要ですか?スタック上の何かを移動し、後で直接ポップすることは私には役に立たないようです。

+10

オプティマイザを使用せずにコンパイラのアセンブリ出力を比較するのはちょっと不公平です。 –

答えて

9

をクリーンアップする必要がないという事実を利用しているのに対し、LLVMは、伝統的な機能のプロローグ/エピローグを使用しているように見えます。これは最適化されていないコードであるため、

基本的に
16-bit: C9 LEAVE A Valid Valid Set SP to BP, then pop BP. 
32-bit: C9 LEAVE A N.E. Valid Set ESP to EBP, then pop EBP. 
64-bit: C9 LEAVE A Valid N.E. Set RSP to RBP, then pop RBP. 

、休暇が同等である

movq %rbp, %rsp 
popq %rbp 
+1

私が理解しているように、 'leave'は同じ' mov'/'pop'より多かれ少なかれ安いですが、' enter'はスタックポインタに単に追加するよりもずっと高額です。 –

+0

これは、なぜ私がコンパイラが 'enter'命令を生成することをほとんど見たことがないのかを説明します。 –

2

GCCは、エントリポイントが実際に、彼らは比較可能だ

+0

ああ、GCCはいつも私の主な機能を出発点としていますが、LLVMはそうではありませんか? –

+0

いいえ、gccは関数本体が空であるという事実を利用しています。 –

+3

私はどちらの意見にも同意しません。 'eax'が設定されても、エピローグは' leave 'を経てまだ起こります。最も効率的な実装は、 'movl $ 0、$ eax'と' ret'です。スタックをまったく気にしません。 gccが実際に空の関数を利用している '-O3'に対してこれが行われています。私は高価な休暇がmov/popと比較されているか分かりませんが、2つは同等です。 –

9

movl $0, -4(%rbp)命令が死んでいるの:インテルのマニュアルから

:休暇は、高レベルの命令です。両方のコンパイラに-Oを渡して、変更内容を確認してください。

+2

Chrisはコードのビットを書くときに"コード "引用を探します。 –

関連する問題