Go ABIにおけるスタックのレイアウト
複数あるABIの違いはGoにおけるABI仕様も参照。
[! Todo] Mermaidにはpacket diagramがあるけどObsidian同梱のバージョンには入ってない。更新されたら図を書き直したい。
関数呼び出しを行ったとき、上位から下位に向かって以下のようなフレームレイアウトになる。混乱するが BP と FP は同じものらしいので、Go ABIにおけるレジスタの意味も参照するといい。
| 内容(上位→下位) | サイズ | 補足 |
|---|---|---|
| BPレジスタの値 | 8 | 関数呼び出し前のBPレジスタを退避している |
| 戻り値 | 可変 | |
| 関数引数 | 可変 | FPレジスタはこの場所を指す |
| リターンアドレス | 8 | SPレジスタはこの場所を指す |
| ローカル変数 | 可変 |
ドキュメントは見つからなかったが、過去にGoアセンブリの書き方で調べたことがある。
ABIInternal
Section titled “ABIInternal”スタックフレームのレイアウトはアーキテクチャごとに異なる。
おそらく 386 と amd64 どちらも同じ。このレイアウトはAMD64の呼び出し規約と同じらしい。Goのエラーハンドリングを集約するライブラリを作った + Goが管理するスタック周りの挙動についての記事でスタック図を描いた。
| 内容(上位→下位) | サイズ | 補足 |
|---|---|---|
| リターンアドレス | 8 | |
| BPレジスタの値 | 8 | 関数呼び出し前のBPレジスタを退避している |
| 関数引数 | 可変 | レジスタに入らなかった残り |
| 戻り値 | 可変 | |
| ローカル変数 | 可変 | SPレジスタはこの場所を指す |
FP レジスタの定義としては
The FP pseudo-register is a virtual frame pointer used to refer to function arguments.
なので、たぶん関数引数の下位アドレスを指すが、ABIInternal を自分で書くことはないので詳細は調べていない。
Arm64呼び出し規約に少し書いたが、BP レジスタや SP レジスタの意味は amd64 と同じだった。
スタックの使い方を調べる。
go build -gcflags='-S -N -l' .
go tool compile -S -N [file]-S でアセンブリを出力、-N で最適化を抑制、-I でインライン化を抑制している。-gcflags という名前から分かるように、オプションの詳細は go tool compile -h で調べられる。