[インデックス 17174] ファイルの概要
このコミットは、Go言語のリンカ cmd/6l
における TEXT
命令のフレームサイズ表示に関するバグ修正です。具体的には、TEXT
命令の出力において、フレームサイズが正しく表示されない問題を解決します。
コミット
cmd/6l: fix printing of frame size in TEXT instruction
R=ken2
CC=golang-dev
https://golang.org/cl/12827043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/4984e6e9fdde23a75b0a8c52d56c7a4b5f5d5736
元コミット内容
cmd/6l: fix printing of frame size in TEXT instruction
R=ken2
CC=golang-dev
https://golang.org/cl/12827043
変更の背景
Go言語のコンパイラツールチェーンの一部であるリンカ cmd/6l
は、Goプログラムをアセンブリレベルで処理し、実行可能なバイナリを生成します。TEXT
命令は、Goのアセンブリ言語において関数の開始を宣言し、その関数のスタックフレームサイズなどの情報を含みます。
このコミット以前は、cmd/6l
が TEXT
命令をリスト表示する際に、関数のスタックフレームサイズが正しく出力されないというバグが存在していました。これは、デバッグ情報やプロファイリング、あるいはアセンブリコードの低レベルな解析を行う際に、誤った情報が提供されることを意味します。特に、スタックフレームサイズは、関数がローカル変数や引数を格納するためにどれだけのスタック領域を必要とするかを示す重要な情報であり、これが誤っていると、デバッグや最適化の妨げとなる可能性がありました。
この修正は、cmd/6l
が生成するアセンブリリストの正確性を向上させ、開発者がGoプログラムの低レベルな動作をより正確に理解できるようにすることを目的としています。
前提知識の解説
- Go言語のツールチェーン: Go言語は、
go build
コマンドを通じて、ソースコードのコンパイル、リンク、実行可能ファイルの生成を行います。このプロセスには、コンパイラ (cmd/compile
)、アセンブラ (cmd/asm
)、リンカ (cmd/link
) など、複数のツールが関与しています。 cmd/6l
: これは、Go言語のリンカの一つで、特にamd64
(64ビットIntel/AMDアーキテクチャ) 向けのリンカを指します。Goのツールチェーンでは、ターゲットアーキテクチャに応じてリンカの名前が変わります(例:8l
は386
向け、5l
はarm
向け)。リンカの主な役割は、コンパイルされたオブジェクトファイルとライブラリを結合し、実行可能なバイナリを生成することです。TEXT
命令: Goのアセンブリ言語(Plan 9アセンブリに似た構文)におけるTEXT
命令は、関数の開始を宣言するために使用されます。この命令は通常、関数名、フラグ、そしてスタックフレームサイズなどの情報を含みます。例えば、TEXT ·main(SB), $0-0
のような形式で記述され、$0-0
の部分がスタックフレームサイズと引数サイズを示します。- スタックフレームサイズ: 関数が呼び出されたときに、その関数のローカル変数、引数、レジスタの保存などに使用されるスタック領域のサイズです。正確なスタックフレームサイズは、スタックオーバーフローの検出や、メモリ使用量の最適化において重要です。
list.c
:cmd/6l
のソースコードの一部で、アセンブリコードのリスト表示(逆アセンブルされたコードの出力)を担当するファイルです。このファイル内のロジックが、TEXT
命令の情報をどのようにフォーマットして出力するかを決定します。Fmt *fp
とfmtprint
: これらは、Goの内部的なフォーマットライブラリの一部であり、C言語で書かれたGoのツールチェーン内で、整形された出力を生成するために使用されます。Fmt *fp
は出力ストリームを表し、fmtprint
は指定されたフォーマットでデータをそのストリームに書き込む関数です。p->line
,p->as
,&p->from
,&p->to
: これらは、アセンブリ命令の構造体Prog
のメンバーを表しています。p->line
: ソースコードの行番号。p->as
: アセンブリ命令のオペレーションコード(例:TEXT
,MOVQ
,ADDQ
など)。&p->from
,&p->to
: 命令のオペランド(ソースとデスティネーション)を表す構造体へのポインタ。これらには、レジスタ、メモリ、定数などの情報が含まれます。
技術的詳細
このコミットが修正している問題は、cmd/6l
の list.c
ファイル内の Pconv
関数にありました。Pconv
関数は、アセンブリ命令(Prog
構造体)を受け取り、それを人間が読める形式の文字列に変換して出力する役割を担っています。
特に問題となっていたのは、TEXT
命令の処理部分です。以前の実装では、TEXT
命令の出力フォーマットが、他の一般的な命令(例: MOVQ
など)と同じ fmtprint(fp, "(%d)\t%A\t%D,%D", p->line, p->as, &p->from, &p->to);
を使用していました。このフォーマット文字列の %D
は、オペランドの値を表示するためのもので、TEXT
命令のスタックフレームサイズを適切に表示するためには不十分でした。
TEXT
命令の場合、p->from
オペランドには、関数のスタックフレームサイズに関する情報が含まれています。この情報は、通常のデータオペランドとは異なる方法で解釈され、表示される必要があります。
修正では、TEXT
命令(p->as
が ATEXT
の場合)に対して、専用の fmtprint
フォーマットが追加されました。新しいフォーマット fmtprint(fp, "(%d)\t%A\t%D,%lD", p->line, p->as, &p->from, &p->to);
では、%lD
という新しいフォーマット指定子が導入されています。この %lD
は、TEXT
命令の p->to
オペランド(通常は引数サイズを示す)を、より詳細な形式で表示するために使用されます。これにより、TEXT
命令の出力にスタックフレームサイズが正しく含まれるようになります。
この変更により、cmd/6l
が生成するアセンブリリストにおいて、TEXT
命令のスタックフレームサイズが正確に反映されるようになり、デバッグや解析の精度が向上します。
コアとなるコードの変更箇所
--- a/src/cmd/6l/list.c
+++ b/src/cmd/6l/list.c
@@ -61,6 +61,9 @@ Pconv(Fmt *fp)
p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
+ fmtprint(fp, "(%d)\t%A\t%D,%lD",
+ p->line, p->as, &p->from, &p->to);
+ break;
default:
fmtprint(fp, "(%d)\t%A\t%D,%D",
p->line, p->as, &p->from, &p->to);
コアとなるコードの解説
変更は src/cmd/6l/list.c
ファイルの Pconv
関数内で行われています。
-
変更前:
Pconv
関数は、アセンブリ命令のタイプ(p->as
)に基づいて、異なる出力フォーマットを選択していました。ATEXT
(TEXT命令) の場合、以前はdefault
ケースのfmtprint(fp, "(%d)\t%A\t%D,%D", p->line, p->as, &p->from, &p->to);
が適用されていました。このフォーマットは、一般的な命令のオペランド表示には適していましたが、TEXT
命令のスタックフレームサイズを適切に表示する機能がありませんでした。 -
変更後:
case ATEXT:
ブロックが追加されました。これにより、p->as
がATEXT
(つまりTEXT
命令) である場合に、専用の処理が実行されるようになります。 新しく追加された行:fmtprint(fp, "(%d)\t%A\t%D,%lD", p->line, p->as, &p->from, &p->to); break;
この行は、
TEXT
命令のために特別に調整されたフォーマット文字列を使用しています。(%d)
: ソースコードの行番号 (p->line
) を表示します。\t%A
: タブに続いて、命令のオペレーションコード (p->as
、例:TEXT
) を表示します。\t%D
: タブに続いて、p->from
オペランドの値を表示します。TEXT
命令の場合、ここに関数名やフラグが含まれます。,%lD
: カンマに続いて、p->to
オペランドの値を表示します。ここで重要なのは%lD
です。このフォーマット指定子は、TEXT
命令のp->to
オペランドが持つスタックフレームサイズや引数サイズといった情報を、より詳細かつ正確な形式で出力するために導入されました。
この修正により、TEXT
命令の出力が他の命令と区別され、その重要なメタデータであるスタックフレームサイズが正しく表示されるようになりました。
関連リンク
- Go CL 12827043: https://golang.org/cl/12827043
参考にした情報源リンク
- Go言語のソースコード (特に
src/cmd/6l/list.c
): https://github.com/golang/go/blob/master/src/cmd/6l/list.c - Go Assembly Language (Plan 9 Assembly): https://go.dev/doc/asm
- Goのツールチェーンに関するドキュメント (必要に応じてGo公式ドキュメントやブログ記事を参照)
fmtprint
のような内部関数に関する情報は、Goのソースコードを直接読むか、関連するGoのIssueやCL (Change List) を参照することで得られます。- Goのリンカに関する一般的な情報: https://go.dev/blog/go1.2 (Go 1.2のリリースノートなど、過去のブログ記事も参考になる場合があります)
- GoのIssueトラッカー (バグ報告や機能要求の履歴): https://github.com/golang/go/issues
- Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/ (CLのリンクから辿れる)