Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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/6lTEXT 命令をリスト表示する際に、関数のスタックフレームサイズが正しく出力されないというバグが存在していました。これは、デバッグ情報やプロファイリング、あるいはアセンブリコードの低レベルな解析を行う際に、誤った情報が提供されることを意味します。特に、スタックフレームサイズは、関数がローカル変数や引数を格納するためにどれだけのスタック領域を必要とするかを示す重要な情報であり、これが誤っていると、デバッグや最適化の妨げとなる可能性がありました。

この修正は、cmd/6l が生成するアセンブリリストの正確性を向上させ、開発者がGoプログラムの低レベルな動作をより正確に理解できるようにすることを目的としています。

前提知識の解説

  • Go言語のツールチェーン: Go言語は、go build コマンドを通じて、ソースコードのコンパイル、リンク、実行可能ファイルの生成を行います。このプロセスには、コンパイラ (cmd/compile)、アセンブラ (cmd/asm)、リンカ (cmd/link) など、複数のツールが関与しています。
  • cmd/6l: これは、Go言語のリンカの一つで、特に amd64 (64ビットIntel/AMDアーキテクチャ) 向けのリンカを指します。Goのツールチェーンでは、ターゲットアーキテクチャに応じてリンカの名前が変わります(例: 8l386 向け、5larm 向け)。リンカの主な役割は、コンパイルされたオブジェクトファイルとライブラリを結合し、実行可能なバイナリを生成することです。
  • TEXT 命令: Goのアセンブリ言語(Plan 9アセンブリに似た構文)における TEXT 命令は、関数の開始を宣言するために使用されます。この命令は通常、関数名、フラグ、そしてスタックフレームサイズなどの情報を含みます。例えば、TEXT ·main(SB), $0-0 のような形式で記述され、$0-0 の部分がスタックフレームサイズと引数サイズを示します。
  • スタックフレームサイズ: 関数が呼び出されたときに、その関数のローカル変数、引数、レジスタの保存などに使用されるスタック領域のサイズです。正確なスタックフレームサイズは、スタックオーバーフローの検出や、メモリ使用量の最適化において重要です。
  • list.c: cmd/6l のソースコードの一部で、アセンブリコードのリスト表示(逆アセンブルされたコードの出力)を担当するファイルです。このファイル内のロジックが、TEXT 命令の情報をどのようにフォーマットして出力するかを決定します。
  • Fmt *fpfmtprint: これらは、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/6llist.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->asATEXT の場合)に対して、専用の 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->asATEXT (つまり 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言語のソースコード (特に 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のリンクから辿れる)