x86プラットフォーム用のgccでコンパイルされたCプログラムの関数呼び出しに最初から最後までいくつの命令が必要か知りたいです。
4 に答える
- いくつかのコードを書いてください。
- コンパイルします。
- 分解を見てください。
- 指示を数えます。
パラメータの数とタイプ、呼び出し規約などを変えると、答えは変わります。
それは答えるのが難しい本当にトリッキーな質問であり、それは変わるかもしれません。
まず最初に、呼び出し元でパラメーターを渡す必要があります。これはタイプによって異なります。ほとんどの場合、パラメーターごとにプッシュ命令があります。
次に、呼び出されたプロシージャの最初の命令は、ローカル変数の割り当てを行うことです。これは通常、次の3つの操作で実行されます。
PUSH EBP
MOV EBP, ESP
SUB ESP, xxx
その後、関数のアセンブリコードが作成されます。
コードに続いて、戻る前に、ebpとespが復元されます。
MOV ESP, EBP
POP EBP
最後に、呼び出し規約に応じてスタックのパラメーターの割り当てを解除するか、呼び出し元に任せるret命令があります。これは、RETがパラメータとして数値を使用している場合、またはパラメータが0である場合にそれぞれ判断できます。パラメータが0の場合、 CALL命令の後に呼び出し元にPOP命令があります。
私は少なくとも1つを期待します
CALL Function
もちろん、インライン化されていない限り。
-mno-accumulate-outgoing-args
and -Os
(または-mpreferred-stack-boundary=2
、または64ビットの場合は3)を使用する場合、オーバーヘッドはpush
引数ごとに1ワードサイズの引数、1 call
、およびadd
リターン後にスタックポインタを調整するために1つです。
デフォルトの16バイトのスタックアラインメントがない-mno-accumulate-outgoing-args
場合とある場合、gccは、正当な理由もなく、ほぼ同じ速度ですが、関数呼び出しの場合は約5倍のコードを生成します。