HeadlinesBriefing favicon HeadlinesBriefing.com

GCC ネスト関数トランポリン スタック最適化

Hacker News •
×

GCC ネスト関数トランポリン スタック最適化。実行可能スタックなしで GCC 上でネスト関数を間接呼び出し。Martin Uecker、2026-08-29。前回、GCC と Clang でネスト関数をコールバックに使用する方法について、実行可能スタックを必要とせずに議論しました。しかし、古いバージョンの GCC をサポートする必要がある場合はどうでしょうか?もちろん、実行可能スタックをそのまま受け入れることもできますが、ハックを使ってこれを回避することも可能です。GCC:ネスト関数とトランポリン。まず、GCC がネスト関数のアドレスを取得するサポート方法について議論しましょう。新しいマクロを使用しないおもちゃの例を以下に示します。x86_64 では、生成されたアセンブリがトランポリンをスタック上に配置し、インライン化された baz 関数を通じて即座に呼び出します。トランポリンは、親関数からキャプチャされた変数を含むスタック上の構造体にスタティックフレームレジスタをロードし、その後ローカル関数にジャンプする短いコードシーケンスです。定数 -17591、-17847、-1864106167 をアセンブリ命令に逆変換すると、次の x86_64 コードが得られます:movq $bar.0, %r11、movq $frame, %r10、jump *%r11。スタティックチェーンとコードアドレスの両方が、トランポリンのコード内の mov 命令で使用される即値定数です。関数を呼び出すためにトランポリンのアドレスを使用する代わりに、トランポリンからコードアドレスとスタティックチェーンを抽出し、それらを組み込み関数 __builtin_call_with_static_chain と共に使用してローカル関数を直接呼び出すことができます。したがって、これら 2 つのポインタ値をトランポリンから読み取ることを、古いバージョンの GCC でのフォールバックメカニズムとして使用できます。欠点は、トランポリンが依然として作成され、コンパイラが依然として間接呼び出しをデバーチャライズできず、スタックが依然として実行可能としてマークされることです。では、何が得られたのでしょうか?トランポリンを実際に呼び出さないため、次のコマンドでスタックを再び非実行可能にでき、少なくともこの機能のセキュリティ懸念に対処できます。patchelf --clear-execstack program。このアイデアは私の実験的ライブラリ noplate に実装されており、そこではコードアドレスとスタティックチェーンからワイドポインタが構築されます。トランポリンとしての関数ディスクリプタ。探求する価値があると思う別のアイデアがあります:トランポリン自体を関数ディスクリプタとして使用することもできます。トランポリンが作成される場所でスタティックチェーンとコードポインタを抽出する代わりに、通常通りトランポリンのアドレスを渡します。しかし、トランポリンを呼び出す可能性のあるすべての場所で、まずポインタがトランポリンを指しているかどうかをチェックし、その後コードアドレスとスタティックチェーンを抽出して __builtin_call_with_static_chain を使用してネスト関数を直接呼び出します。ある意味では、トランポリンを呼び出す代わりに、呼び出し元で超シンプルなインタプリタを使用してトランポリンのコードを解釈していると言えます。このインタプリタはこの特定のコードシーケンスのみを解釈でき、非常にシンプルであるため...