[インデックス 13814] ファイルの概要
このコミットは、Go言語のツールチェーンにおいて、アーカイブファイル内のシンボル定義セクションの識別子を __.SYMDEF
から __.GOSYMDEF
へと変更するものです。この変更の主な目的は、標準的なELF(Executable and Linkable Format)ツールがGoの非標準的なシンボルテーブルフォーマットを誤って解釈する問題を解決することにあります。これにより、Goのツールチェーンが生成するバイナリと、一般的なシステムツールとの間の互換性の問題が解消されます。
コミット
commit 6ee91ced92fc27f8c93b0589484923593cad240f
Author: Russ Cox <rsc@golang.org>
Date: Thu Sep 13 10:26:21 2012 -0400
cmd/pack: rename __.SYMDEF to __.GOSYMDEF
This fixes a problem with ELF tools thinking they know the
format of the symbol table, as we do not use any of the
standard formats for that table.
This change will probably annoy the Plan 9 users, but I
believe there are other incompatibilities already that mean
they have to use a Go-specific nm.
Fixes #3473.
R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/6500117
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6ee91ced92fc27f8c93b0589484923593cad240f
元コミット内容
commit 6ee91ced92fc27f8c93b0589484923593cad240f
Author: Russ Cox <rsc@golang.org>
Date: Thu Sep 13 10:26:21 2012 -0400
cmd/pack: rename __.SYMDEF to __.GOSYMDEF
This fixes a problem with ELF tools thinking they know the
format of the symbol table, as we do not use any of the
standard formats for that table.
This change will probably annoy the Plan 9 users, but I
believe there are other incompatibilities already that mean
they have to use a Go-specific nm.
Fixes #3473.
R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/6500117
変更の背景
この変更は、Go言語のコンパイラやリンカが生成するアーカイブファイル(主にライブラリファイル)内のシンボルテーブルの扱いに関する問題を解決するために行われました。
Goのツールチェーンは、その内部で独自のシンボルテーブルフォーマットを使用しています。しかし、このシンボルテーブルがアーカイブファイル内で __.SYMDEF
という名前で識別されていたため、LinuxなどのUnix系システムで広く使われているELF(Executable and Linkable Format)形式を扱う標準的なツール(例えば nm
コマンドなど)が、この __.SYMDEF
を標準的なシンボル定義セクションとして誤って認識してしまう問題が発生していました。
標準ツールがGoの非標準フォーマットを標準として扱おうとすると、解析エラーや予期せぬ動作を引き起こす可能性がありました。この問題を回避するため、Go独自のシンボル定義セクションの識別子を __.SYMDEF
から __.GOSYMDEF
へと変更することで、名前の衝突を避け、標準ツールがGoのシンボルテーブルを誤解釈するのを防ぐことが目的です。
コミットメッセージには「Fixes #3473」とあり、これはGoのIssueトラッカーにおけるIssue 3473を修正するものであることを示しています。このIssueは、まさに __.SYMDEF
が原因で nm
などのツールがGoのアーカイブファイルを正しく扱えないという問題が報告されていました。
また、コミットメッセージではPlan 9ユーザーへの影響についても言及されています。Go言語はPlan 9オペレーティングシステムの影響を強く受けており、一部のGoツールはPlan 9の慣習に従っています。__.SYMDEF
はPlan 9のアーカイブフォーマットにおけるシンボル定義の慣習的な名前でした。しかし、GoのシンボルテーブルはPlan 9のそれとは異なるため、Go固有の nm
ツールを使用する必要があるという現状を鑑み、互換性よりも問題解決を優先した形です。
前提知識の解説
このコミットを理解するためには、以下の技術的な概念を理解しておく必要があります。
-
ELF (Executable and Linkable Format):
- LinuxやUnix系OSで実行ファイル、オブジェクトファイル、共有ライブラリなどのバイナリファイルを格納するための標準的なファイルフォーマットです。
- ELFファイルは、プログラムコード、データ、シンボルテーブル、デバッグ情報など、様々なセクションで構成されます。
nm
などのツールは、ELFファイルの構造を解析して情報を抽出します。
-
シンボルテーブル (Symbol Table):
- コンパイルされたプログラムやライブラリ内に含まれるデータ構造の一つです。
- 関数名、グローバル変数名、静的変数名などの「シンボル」と、それらがメモリ上のどこに配置されているか(アドレス)のマッピング情報を含みます。
- リンカはシンボルテーブルを使用して、異なるオブジェクトファイルやライブラリ間の参照を解決します。デバッガやプロファイラもシンボルテーブルを利用して、人間が読める形式で情報を提供します。
-
nm
コマンド:- Unix系OSで利用されるコマンドラインツールで、オブジェクトファイル、アーカイブファイル、共有ライブラリなどのバイナリファイルからシンボル(関数名や変数名など)のリストを表示するために使用されます。
- シンボルの種類(関数、変数、未定義など)やアドレスなどの情報を提供します。
-
アーカイブファイル (Archive File):
- 複数のオブジェクトファイルやライブラリを一つにまとめたファイル形式です。Unix系では
.a
拡張子を持つ静的ライブラリがこれに該当します。 - リンカはアーカイブファイルから必要なオブジェクトファイルを選択的にリンクします。
- アーカイブファイルには、通常、内部のオブジェクトファイルに含まれるシンボルを効率的に検索するためのインデックス(シンボルテーブル)が含まれています。
- 複数のオブジェクトファイルやライブラリを一つにまとめたファイル形式です。Unix系では
-
Go言語のツールチェーン:
- Go言語のプログラムをビルドするために使用される一連のツール群です。主要なものには以下があります。
go tool compile
(gc): Goソースコードをオブジェクトファイルにコンパイルします。go tool link
(ld, 5l, 6l, 8l): オブジェクトファイルをリンクして実行可能ファイルやライブラリを生成します。5l
,6l
,8l
はそれぞれARM、x86-64、x86アーキテクチャ向けのリンカです。go tool pack
(ar): Goのアーカイブファイルを操作するツールです。Unixのar
コマンドに似ています。go tool nm
: Goのバイナリファイルからシンボルをリスト表示するGo固有のnm
ツールです。
- Go言語のプログラムをビルドするために使用される一連のツール群です。主要なものには以下があります。
-
Plan 9:
- ベル研究所で開発された分散オペレーティングシステムです。Go言語の設計思想や一部のツールはPlan 9の影響を強く受けています。
- Plan 9のアーカイブフォーマットでは、シンボル定義セクションが
__.SYMDEF
という名前で識別されるのが一般的でした。
技術的詳細
このコミットの技術的な核心は、Goのツールチェーンが生成するアーカイブファイル内のシンボルテーブルの識別子を、既存の __.SYMDEF
から __.GOSYMDEF
へと変更することにあります。
Goのコンパイラやリンカは、標準的なELFフォーマットとは異なる独自の内部フォーマットでシンボル情報を管理しています。これはGoのクロスコンパイル能力や、特定のランタイム要件(例: ガベージコレクション)に対応するために設計されたものです。
問題は、Goが生成するアーカイブファイルが、その内部に __.SYMDEF
という名前の特別なエントリを含んでいたことです。この __.SYMDEF
は、Plan 9のアーカイブフォーマットにおけるシンボルテーブルの慣習的な名前と一致していました。しかし、Goの __.SYMDEF
の内容はPlan 9や一般的なELFツールの期待するフォーマットとは全く異なっていました。
結果として、Linuxなどのシステムで nm
のような標準的なELFツールがGoのアーカイブファイルを解析しようとすると、__.SYMDEF
という名前を見つけて「これはシンボルテーブルだ」と判断し、その内容を標準的なシンボルテーブルフォーマットとして解釈しようとしました。しかし、フォーマットが異なるため、ツールは解析に失敗したり、誤った情報を表示したり、クラッシュしたりする可能性がありました。
この問題を解決するために、Goのツールチェーンはシンボルテーブルの識別子を __.GOSYMDEF
に変更しました。この新しい名前は、Go固有のシンボル定義であることを明確に示し、標準的なELFツールがこれを一般的なシンボルテーブルとして誤解釈するのを防ぎます。これにより、Goのアーカイブファイルがシステム上の他のツールと共存しやすくなります。
src/pkg/exp/types/exportdata.go
の変更は特に重要です。このファイルはGoのパッケージのエクスポートデータを処理する部分であり、古いアーカイブファイルとの互換性を考慮しています。具体的には、FindGcExportData
関数内で、アーカイブの最初のエントリが __.SYMDEF
または __.GOSYMDEF
のいずれかであることを許容するように変更されています。これにより、この変更が適用される前にビルドされたGoのアーカイブファイルも引き続き正しく処理できるようになっています。
この変更は、Goのツールチェーンが生成するバイナリの「自己完結性」を保ちつつ、外部ツールとの不必要な衝突を避けるための、実用的な解決策と言えます。
コアとなるコードの変更箇所
このコミットでは、主にGoのリンカ、コンパイラ、アーカイブツール、および関連するユーティリティが使用するシンボル定義の文字列定数が変更されています。
-
リンカのヘッダーファイル (
src/cmd/5l/5.out.h
,src/cmd/6l/6.out.h
,src/cmd/8l/8.out.h
): これらのファイルは、それぞれ異なるアーキテクチャ(ARM, x86-64, x86)向けのGoリンカが使用する定数を定義しています。SYMDEF
マクロの定義が変更されています。--- a/src/cmd/5l/5.out.h +++ b/src/cmd/5l/5.out.h @@ -276,7 +276,7 @@ enum /* * this is the ranlib header */ -#define SYMDEF "__.SYMDEF" +#define SYMDEF "__.GOSYMDEF" /* * this is the simulated IEEE floating point
同様の変更が
6l/6.out.h
と8l/8.out.h
にも適用されています。 -
コンパイラの字句解析部分 (
src/cmd/gc/lex.c
): Goコンパイラの一部で、アーカイブファイルを読み込む際にシンボルテーブルをスキップするロジックが変更されています。--- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -480,7 +480,7 @@ skiptopkgdef(Biobuf *b) if(memcmp(p, "!<arch>\\n", 8) != 0) return 0; /* symbol table is first; skip it */ - sz = arsize(b, "__.SYMDEF"); + sz = arsize(b, "__.GOSYMDEF"); if(sz < 0) return 0; Bseek(b, sz, 1);
-
リンカのライブラリ処理部分 (
src/cmd/ld/lib.c
): Goリンカがライブラリ(アーカイブファイル)を処理する際に、__.SYMDEF
セクションをスキップする箇所が変更されています。--- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -366,7 +366,7 @@ objfile(char *file, char *pkg) return; } - /* skip over __.SYMDEF */ + /* skip over __.GOSYMDEF */ off = Boffset(f); if((l = nextar(f, off, &arhdr)) <= 0) { diag("%s: short read on archive file symbol header", file); @@ -402,7 +402,7 @@ objfile(char *file, char *pkg) * the individual symbols that are unused. * * loading every object will also make it possible to - * load foreign objects not referenced by __.SYMDEF. + * load foreign objects not referenced by __.GOSYMDEF. */ for(;;) { l = nextar(f, off, &arhdr);
-
nm
コマンドのソース (src/cmd/nm/nm.c
): Goのnm
ツールが使用するシンボルテーブルファイル名の定数が変更されています。--- a/src/cmd/nm/nm.c +++ b/src/cmd/nm/nm.c @@ -43,7 +43,7 @@ enum{ char *errs; /* exit status */ char *filename; /* current file */ -char symname[]="__.SYMDEF"; /* table of contents file name */ +char symname[]="__.GOSYMDEF"; /* table of contents file name */ int multifile; /* processing multiple files */ int aflag; int gflag;
-
pack
コマンドのアーカイブ処理部分 (src/cmd/pack/ar.c
): Goのアーカイブツールpack
が使用するシンボル定義ファイル名の定数が変更されています。--- a/src/cmd/pack/ar.c +++ b/src/cmd/pack/ar.c @@ -111,7 +111,7 @@ char *opt = "uvnbailogS"; char artemp[] = "/tmp/vXXXXX"; char movtemp[] = "/tmp/v1XXXXX"; char tailtemp[] = "/tmp/v2XXXXX"; -char symdef[] = "__.SYMDEF"; +char symdef[] = "__.GOSYMDEF"; char pkgdef[] = "__.PKGDEF"; int aflag; /* command line flags */
-
Goパッケージのエクスポートデータ処理 (
src/pkg/exp/types/exportdata.go
): Goのパッケージエクスポートデータを読み込む際に、古い__.SYMDEF
と新しい__.GOSYMDEF
の両方を許容するように変更されています。--- a/src/pkg/exp/types/exportdata.go +++ b/src/pkg/exp/types/exportdata.go @@ -52,13 +52,14 @@ func FindGcExportData(r *bufio.Reader) (err error) { var name string var size int - // First entry should be __.SYMDEF. + // First entry should be __.GOSYMDEF. + // Older archives used __.SYMDEF, so allow that too. // Read and discard. if name, size, err = readGopackHeader(r); err != nil { return } - if name != "__.SYMDEF" { - err = errors.New("go archive does not begin with __.SYMDEF") + if name != "__.SYMDEF" && name != "__.GOSYMDEF" { + err = errors.New("go archive does not begin with __.SYMDEF or __.GOSYMDEF") return } const block = 4096
コアとなるコードの解説
上記の変更は、Goのビルドシステム全体で __.SYMDEF
という文字列定数を __.GOSYMDEF
に置き換えることを目的としています。
-
リンカのヘッダーファイル (
.out.h
): これらのファイルは、Goのリンカがオブジェクトファイルやアーカイブファイルを処理する際に使用する内部的な定数を定義しています。SYMDEF
マクロは、アーカイブファイル内のシンボルテーブルセクションを識別するために使われる文字列を定義していました。この変更により、リンカが新しい識別子__.GOSYMDEF
を使用してシンボルテーブルを生成・認識するようになります。 -
コンパイラの字句解析部分 (
src/cmd/gc/lex.c
):skiptopkgdef
関数は、パッケージ定義をスキップする際に、アーカイブの先頭にあるシンボルテーブルを読み飛ばす処理を行っています。ここで__.SYMDEF
を検索してそのサイズを取得していましたが、この検索対象が__.GOSYMDEF
に変更されました。これにより、コンパイラが新しい識別子を持つアーカイブを正しく処理できるようになります。 -
リンカのライブラリ処理部分 (
src/cmd/ld/lib.c
):objfile
関数は、オブジェクトファイルやライブラリファイルを処理するGoリンカの主要な部分です。この関数内で、アーカイブファイルから__.SYMDEF
セクションをスキップするロジックが存在しました。この変更により、リンカは__.GOSYMDEF
をスキップするようになります。また、コメントも更新され、__.GOSYMDEF
によって参照されない外部オブジェクトのロード可能性についても言及されています。 -
nm
コマンドのソース (src/cmd/nm/nm.c
): Goのnm
ツールは、Goのバイナリファイルからシンボル情報を抽出するために使用されます。symname
変数は、シンボルテーブルのファイル名を定義していました。この変更により、nm
ツールは__.GOSYMDEF
という名前のセクションをシンボルテーブルとして認識し、解析するようになります。 -
pack
コマンドのアーカイブ処理部分 (src/cmd/pack/ar.c
):pack
コマンドは、Goのオブジェクトファイルをアーカイブファイルにまとめるツールです。symdef
変数は、pack
がアーカイブ内にシンボルテーブルを作成する際に使用する名前を定義していました。この変更により、pack
は新しい識別子__.GOSYMDEF
を使用してシンボルテーブルを作成するようになります。 -
Goパッケージのエクスポートデータ処理 (
src/pkg/exp/types/exportdata.go
):FindGcExportData
関数は、Goのパッケージのエクスポートデータを読み込む際に、アーカイブの先頭にあるシンボル定義セクションをチェックします。この変更は、後方互換性を考慮した重要な部分です。新しいコードでは、アーカイブの先頭が__.SYMDEF
または__.GOSYMDEF
のいずれかであれば許容するようにロジックが変更されました。これにより、このコミットが適用される前にビルドされた古いGoアーカイブファイルも、新しいツールチェーンで引き続き正しく処理できるようになります。これは、既存のGoエコシステムとの互換性を維持するための配慮です。
これらの変更は、Goのビルドシステム全体でシンボルテーブルの識別子を統一し、外部ツールとの衝突を避けるための協調的な作業を示しています。
関連リンク
- Go Issue 3473: cmd/pack: __.SYMDEF causes problems with ELF tools
- Go Code Review 6500117: cmd/pack: rename __.SYMDEF to __.GOSYMDEF
参考にした情報源リンク
- ELF (Executable and Linkable Format) - Wikipedia: https://ja.wikipedia.org/wiki/Executable_and_Linkable_Format
- シンボルテーブル - Wikipedia: https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%B3%E3%83%9C%E3%83%AB%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB
- nm (Unix) - Wikipedia: https://en.wikipedia.org/wiki/Nm_(Unix)
- ar (Unix) - Wikipedia: https://en.wikipedia.org/wiki/Ar_(Unix)
- Plan 9 from Bell Labs - Wikipedia: https://ja.wikipedia.org/wiki/Plan_9_from_Bell_Labs
- Go言語のツールチェーンに関する一般的な知識 (Go公式ドキュメントなど)I have read the commit data and prepared the detailed explanation in Markdown format, following all the specified instructions and chapter structure. I will now output it to standard output.