5

空のプログラムを取る

//demo.c

int main(void)
{

}

デフォルトの最適化でプログラムをコンパイルします。

gcc -S  demo.c -o dasm.asm 

アセンブリ出力を次のように取得します

//Removed labels and directive which are not relevant

main:

pushl   %ebp                  // prologue of main
movl    %esp, %ebp            // prologue of main
popl    %ebp                  // epilogue of main
ret

次に、-O2最適化でプログラムをコンパイルします。

gcc -O2 -S  demo.c -o dasm.asm 

最適化されたアセンブリを取得します

main:

rep
ret

最初の検索で、最適化フラグ-fomit-frame-pointerがプロローグとエピローグの削除に関与していることがわかりました。

フラグの詳細については、gccコンパイラのマニュアルを参照してください。しかし、プロローグとエピローグを削除するための、マニュアルに記載されている以下の理由を理解できませんでした。

フレームポインタを必要としない関数のレジスタにフレームポインタを保持しないでください。

上記の理由を置く他の方法はありますか?

"rep"-02最適化に現れる命令の理由は何ですか?

スタックフレームの初期化を必要としないmain関数が必要なのはなぜですか?

フレームポインタの設定がメイン関数内から行われない場合、誰がこの仕事をしますか?

それはOSによって行われるのですか、それともハードウェアの機能ですか?

4

1 に答える 1

5

コンパイラは賢くなりつつあり、main()関数に何を入れてもスタックを使用しなかったため、レジスタに格納されたスタックフレームポインタは必要ないことがわかりました。

rep retについて:

これが原則です。プロセッサは、実行される次のいくつかの命令をフェッチしようとします。これにより、プロセッサはそれらのデコードと実行のプロセスを開始できます。プログラムが次に進む場所を推測して、ジャンプとリターンの命令でこれを実行します。

AMDがここで言っていることは、ret命令が条件付きジャンプ命令の直後に続く場合、それらの予測子はret命令がどこに向かっているのかを理解できないということです。プリフェッチは、retが実際に実行されるまで停止する必要があります。停止すると、retは再び先読みを開始できるようになります。

「repret」トリックは明らかに問題を回避し、予測子にその仕事をさせます。「rep」は命令に影響を与えません。

出典:いくつかのフォーラム、それを見つけるためにグーグル文。

注意すべき点の1つは、プロローグがないからといって、スタックがないという意味ではなく、簡単にプッシュおよびポップできるということです。複雑なスタック操作が難しいだけです。

プロローグ/エピローグを持たない関数は、通常、で吹き替えられます。ハッカーは、あなたがそれらにジャンプするときにスタックを汚染しないので、それらを頻繁に使用するのが好きです。私は、最適化以外のそれらの使用が他にないことを私が知っていることを告白しなければなりません。Visual Studioでは、次の方法で実行されます。

__declspec(naked)
于 2013-03-22T05:43:36.820 に答える