2025/10/27 06:36 Stack walking: space and time trade-offs

やっほー、ロボ子!今日のITニュース、なかなか興味深いものがあるのじゃ。

博士、こんにちは。どんなニュースですか?

今日はね、DWARFというものと、スタック巻き戻しについてなのじゃ。C++の例外処理に必要なものらしいぞ。

DWARFですか。初めて聞きました。具体的にはどういうものなのでしょう?

DWARFは、簡単に言うと、プログラムのデバッグ情報を記録するための規格なのじゃ。これがないと、C++の例外処理とかがうまく動かないらしい。

なるほど。それで、そのDWARFの代替手段があるということですか?

そう!フレームポインタを有効にするか、SFrameという新しい形式を使うという手もあるみたい。「開発者はフレームポインタを有効にするか、プロファイリング用に設計された新しい形式であるSFrameを採用できる」って書いてあるぞ。

フレームポインタは聞いたことがあります。でも、SFrameは初めてです。プロファイリング専用なんですね。

そうみたいじゃな。記事によると、x86-64では、フレームポインタ、DWARF、SFrame、LBR、AppleのCompact Unwinding Formatなど、色々なスタックウォーキングのメカニズムがあるみたいじゃ。

そんなにたくさん!それぞれに特徴があるんでしょうね。

その通り!フレームポインタは速いけどレジスタを消費する。DWARFは包括的だけど遅い。SFrameはプロファイリング専用。LBRはSkylake以降で使える。AppleのCompact Unwinding FormatはDWARFをほぼ置き換えられるけど、一部にはDWARFが必要…って感じじゃ。

なるほど。状況に応じて使い分ける必要があるんですね。

そういうことじゃ!フレームポインタを有効にするには、`-fno-omit-frame-pointer`というオプションを使うらしいぞ。これで、フレームポインタレジスタが予約されて、関数の最初と最後にpush/pop命令が追加される。

リーフ関数の場合はどうなるんですか?

リーフ関数は、他の関数を呼び出さない関数のことじゃな。この場合は、`-momit-leaf-frame-pointer`というオプションを使うと、push/pop操作が省略されて、コードサイズが小さくなるみたい。

最適化ですね。

そうじゃ!フレームポインタを省略すると、コンパイラはRSP相対アドレッシングを使うことになる。RSPは追加のSIBバイトを必要とするけど、RBPは必要としない、と。

SFrameは、OracleがLinuxディストリビューションでの採用を提唱しているんですね。

そうみたいじゃな。SFrameの実装は、コンパイラではなくアセンブラとリンカによって処理されるらしい。

へえ、興味深いですね。

記事によると、Clangでビルドされたバイナリでは、フレームポインタ構成の方がSFrame構成よりも実行可能ファイルサイズが小さいみたいじゃ。GCCだと、フレームポインタバージョンの方が小さいらしい。

コンパイラによって結果が違うんですね。

そうみたいじゃな。GCCのフレームポインタコード生成は、デフォルトのomit-frame-pointerパスほど最適化されていない可能性がある、と。

フレームポインタを有効にすると、スタックオブジェクトへのアクセスが頻繁な場合、バイナリサイズが小さくなることもあるんですね。

逆説的じゃけど、そういうこともあるみたいじゃな!

勉強になりました。今日のニュースも奥が深いですね。

じゃろ?ところでロボ子、SFrameって、なんだかおしゃれなカフェの名前みたいじゃない?

確かに。今度、SFrameという名前のカフェを探してみましょうか。

もし見つけたら、メニューはアセンブリ言語で書かれてそうじゃな。
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。