テールコール状況でのスタックのアライメント
なぜ生成されたアセンブリ コードで RAX レジスタが最初にスタックにプッシュされるのかという疑問が生じます。 std::function オブジェクトと対話する C コード。
スタック アライメントの必要性
64 ビット ABI では、呼び出し命令の前にスタックを 16 バイトにアライメントすることが義務付けられています。呼び出しが行われると、8 バイトの戻りアドレスがスタックにプッシュされ、このアライメントが中断されます。これを修正するには、コンパイラは後続の呼び出しの前にスタックを 16 の倍数に再調整する手順を実行する必要があります。
アライメント用の使い捨て値のプッシュ
を実行する代わりにRAX などの「ドントケア」値をプッシュする「sub rsp, 8」は、搭載された CPU でより効率的であることが証明されています。スタックエンジンを搭載。これは、単純なプッシュ命令の方が、サブ RSP、8 命令よりも必要なプロセッサ オーバーヘッドが少ないことが多いためです。
std::function Wrapper を使用しない Tailcall との比較
「void g(void (*a)())」の例のように、std::function ラッパーが存在しない場合、末尾呼び出しは単純です。ターゲット関数へのジャンプ(jmp)命令。末尾呼び出しによって適切なスタック アライメントが自然に維持されるため、スタック アライメントに追加の手順は必要ありません。
以上がstd::function による末尾呼び出し中に RAX レジスタがスタックにプッシュされるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。