switch_to_parent
への呼び出しの鎖の中の全ての
手続きについて必要である.
我々の実装はSparc version 8
[41]
の呼びだし慣例
の下での無修正のGNU C コンパイラバージョン2.7.2を
使用して完成されている. レジスタ使用慣例として,
我々は, レジスタウィンドウを使用しない -mflat
オプションを
使用した. この慣例はレジスタウィンドウを使用する伝統的なCバイナリ
との互換性を維持する.
図3.6: GNU C コンパイラにおける, -mflat オプション(レジスタウィンドウを使用しない) をつけたときのスタックフレームの配置. alloca 領域の ちょうど二つ上のワードはcallerのFPとリターンアドレスである.
我々の環境ではパラメタのサイズは, 現在の手続きの
パラメタの個数をワードで返す
組み込みの関数, __builtin_args_info(0)
によって得られる.
Epilogue コードアドレスは, 図3.5に示すように, 手続きの終わりにラベルを置き,
そのアドレスを &&
オペレータで獲得することによって得られる
.
リターンアドレスと caller の FP の場所はより直接的ではない.
GNU C コンパイラのスタックの配置を図3.6に示す.
それらは局所変数のセーブエリアの最も低い2ワードに,
callerのFPを最も下に, リターンアドレスをその次に配置する.
オフセットは全ての手続きを通じて, FPからも, SPからも, 定数ではない.
しかし, 幸運にも, 局所変数領域のすぐ下は alloca
による
スタック確保のためのものであり, すべての他の alloca
の要求の前に,
一番下のワードのアドレスを,
alloca
(例えば alloca(0)
)によって
ゼロバイト(!)の要求を行なうことによって得られる
.
まとめると, スレッドが最終的に switch_to_parent
で
終わるかもしれない手続きを呼び出すときには,
(1) alloca(0)
の結果, (2) その手続きの epilogue コード
のアドレス (3) その手続きに対する __builtin_args_info(0)
の結果を保持する, スタックに確保されたデスクリプタを渡してやる.
そのような手続きが最終的に switch_to_parent
を
呼び出す他の手続きを呼び出すときには,
次の手続きに対し, (1),(2), そして, 前のデスクリプタへの
リンクを渡す. 我々は上の情報をスタック上に準備するマクロを
提供している. 下の例では, 前者を「SET_THREAD_DESC」と,
後者を「SET_LINK_DESC」と呼ぶ.