[インデックス 17922] ファイルの概要
このコミットは、Goコンパイラのcmd/5c
(ARM), cmd/6c
(x86-64), cmd/8c
(x86) の各バックエンドが、共通のリンカライブラリであるliblink
を使用するように変更するものです。これは、Go 1.3のリンカの大規模な再構築(golang.org/s/go13linker
で計画された作業)に向けた準備の一環として行われました。この変更により、各アーキテクチャ固有のコンパイラから重複するリンカ関連のコードが削除され、共通のliblink
インターフェースを通じてリンカ機能が提供されるようになります。
コミット
76a8c873cf06cfc42e3c306ac3f18e62795253d3
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/76a8c873cf06cfc42e3c306ac3f18e62795253d3
元コミット内容
cmd/5c, cmd/6c, cmd/8c: use liblink
Preparation for golang.org/s/go13linker work.
This CL does not build by itself. It depends on 35740044
and 35790044 and will be submitted at the same time.
R=iant
CC=golang-dev
https://golang.org/cl/34580044
変更の背景
このコミットは、Go 1.3のリンカの大規模な再構築プロジェクト(golang.org/s/go13linker
)の一環として実施されました。当時のGoのツールチェインでは、各アーキテクチャ(ARM, x86-64, x86など)のコンパイラ(cmd/5c
, cmd/6c
, cmd/8c
)がそれぞれリンカの一部機能を独自に実装していました。これにより、コードの重複やメンテナンスの複雑さが増していました。
go13linker
プロジェクトの目的は、リンカのパフォーマンスを向上させ、その機能をよりモジュール化することでした。そのために、リンカの機能をliblink
という共通ライブラリに集約し、コンパイラからこのliblink
を呼び出す形に移行する計画が立てられました。
このコミットは、その移行の第一歩として、各コンパイラがliblink
を使用するようにコードベースを調整するものです。コミットメッセージにもあるように、この変更単体ではビルドが通らず、他の関連する変更(35740044
と35790044
)と同時に適用されることを前提としていました。これにより、リンカの命令選択フェーズがコンパイラ側に移動し、リンカの機能が再編成されることになります。
前提知識の解説
- Goコンパイラ (
cmd/5c
,cmd/6c
,cmd/8c
): Go言語のソースコードを機械語に変換するプログラムです。5c
はARMアーキテクチャ向け、6c
はx86-64アーキテクチャ向け、8c
はx86アーキテクチャ向けのコンパイラを指します。これらはGo 1.5以前のコンパイラであり、現在はcmd/compile
に統合されています。 - Goリンカ: コンパイラによって生成されたオブジェクトファイルやライブラリを結合し、実行可能なバイナリを生成するプログラムです。
liblink
: Go 1.3のリンカ再構築プロジェクトで導入された共通リンカライブラリです。リンカの共通機能をカプセル化し、コンパイラや他のツールから利用できるように設計されました。これにより、リンカのコードベースが整理され、重複が排除されました。golang.org/s/go13linker
: Russ Coxによって2013年11月に公開された「Go 1.3 Linker Overhaul」というドキュメントを指します。このドキュメントでは、Goリンカのパフォーマンス改善とモジュール化のための詳細な計画が述べられており、liblink
の導入もその一環でした。Adr
(Address) 構造体: 以前のGoコンパイラで使用されていた、メモリアドレスやレジスタ、定数などのオペランドを表すための構造体です。Prog
(Program) 構造体: 以前のGoコンパイラで使用されていた、単一の機械語命令を表すための構造体です。Sym
(Symbol) /LSym
(Linker Symbol): プログラム内の変数、関数、ラベルなどのシンボル情報を表す構造体です。LSym
はliblink
導入後にリンカが管理するシンボルを表すために導入されました。
技術的詳細
このコミットの主要な技術的変更点は、各アーキテクチャ固有のコンパイラ(cmd/5c
, cmd/6c
, cmd/8c
)から、リンカ関連のコードを削除し、共通のliblink
ライブラリが提供する機能に置き換えることです。
具体的には、以下の変更が行われています。
Adr
およびProg
構造体の削除とAddr
への移行:src/cmd/5c/gc.h
,src/cmd/6c/gc.h
,src/cmd/8c/gc.h
などのヘッダファイルから、Adr
およびProg
構造体の定義が削除されています。- これらの構造体を使用していた箇所は、
liblink
で定義されているAddr
構造体(またはその概念)に置き換えられています。これにより、コンパイラとリンカ間のデータ構造が共通化され、インターフェースが簡素化されます。 - 例えば、
typedef struct Adr Adr;
やtypedef struct Prog Prog;
の行が削除され、#define A ((Addr*)0)
のようにAddr
が使われるようになっています。
- リンカ関連のユーティリティ関数の削除:
src/cmd/5c/swt.c
,src/cmd/6c/swt.c
,src/cmd/8c/swt.c
などから、オブジェクトファイルの書き出しやシンボル名の管理など、リンカが担当していた多くのユーティリティ関数(例:zwrite
,outhist
,zname
,zaddr
)が削除されています。- これらの機能は
liblink
内部で処理されるようになり、コンパイラはlinkouthist
やlinkwritefuncs
といったliblink
のAPIを呼び出す形に変更されています。
- シンボル管理の変更 (
Sym
からLSym
へ):src/cmd/5c/gc.h
,src/cmd/6c/gc.h
,src/cmd/8c/gc.h
において、Var
構造体内のシンボルポインタがSym*
からLSym*
に変更されています。これは、リンカが管理するシンボルがLSym
型で表現されるようになったためです。naddr
関数など、シンボルを扱う関数内でlinksym(n->sym)
のようにliblink
のシンボル変換関数が使用されるようになっています。
- 浮動小数点定数と文字列定数の扱い:
src/cmd/5c/list.c
,src/cmd/6c/list.c
,src/cmd/8c/list.c
などにおいて、浮動小数点定数(D_FCONST
)や文字列定数(D_SCONST
)の内部表現がa->dval
やa->sval
からa->u.dval
やa->u.sval
に変更されています。これは、Addr
構造体内で共用体(union)が使用されるようになったためと考えられます。
firstp
の削除とPlist
の導入:src/cmd/5c/txt.c
,src/cmd/6c/txt.c
,src/cmd/8c/txt.c
において、命令リストの先頭を指すfirstp
グローバル変数が削除されています。- 代わりに、
linknewplist(ctxt)
を呼び出してPlist
構造体を取得し、そのfirstpc
フィールドに命令リストの先頭を設定する形に変更されています。これは、liblink
が命令リストの管理を行うようになったことを示しています。
- アーキテクチャ固有のリンカアーキテクチャ設定:
src/cmd/5c/txt.c
,src/cmd/6c/txt.c
,src/cmd/8c/txt.c
において、LinkArch *thelinkarch = &linkarm;
のように、各アーキテクチャに対応するLinkArch
構造体へのポインタが設定されています。これにより、liblink
が現在のコンパイル対象アーキテクチャを認識できるようになります。
これらの変更は、コンパイラとリンカの間の責任分担を明確にし、リンカのコードベースをよりクリーンでメンテナンスしやすいものにするための重要なステップでした。
コアとなるコードの変更箇所
このコミットでは、主に以下のファイル群が変更されています。
src/cmd/5c/gc.h
,src/cmd/6c/gc.h
,src/cmd/8c/gc.h
: 各アーキテクチャのコンパイラのヘッダファイル。Adr
とProg
構造体の削除、Var
構造体のSym*
からLSym*
への変更、および関連する関数のプロトタイプ変更。src/cmd/5c/list.c
,src/cmd/6c/list.c
,src/cmd/8c/list.c
: 命令リストの出力に関するファイル。Adr
からAddr
への型変更、シンボルがnil
かどうかのチェック、浮動小数点定数や文字列定数のアクセス方法の変更。src/cmd/5c/peep.c
,src/cmd/6c/peep.c
,src/cmd/8c/peep.c
: 命令の最適化(peephole optimization)に関するファイル。Adr
からAddr
への型変更。src/cmd/5c/reg.c
,src/cmd/6c/reg.c
,src/cmd/8c/reg.c
: レジスタ割り当てに関するファイル。Adr
からAddr
への型変更、Sym*
からLSym*
への変更。src/cmd/5c/swt.c
,src/cmd/6c/swt.c
,src/cmd/8c/swt.c
: スイッチ文の処理やオブジェクトファイルの書き出しに関するファイル。リンカ関連のユーティリティ関数(zwrite
,outhist
,zname
,zaddr
)の削除と、liblink
のAPI呼び出しへの置き換え。文字列定数のアクセス方法の変更。src/cmd/5c/txt.c
,src/cmd/6c/txt.c
,src/cmd/8c/txt.c
: テキストセクションの生成に関するファイル。firstp
の削除とPlist
の導入、naddr
関数でのlinksym
の使用、thelinkarch
の設定。src/cmd/cc/cc.h
,src/cmd/cc/lex.c
,src/cmd/cc/macbody
,src/cmd/cc/pswt.c
,src/cmd/cc/sub.c
: Cコンパイラ関連のファイル。一部のリンカ関連の定義やコードが削除されています。
これらの変更は、各コンパイラからリンカの低レベルな実装詳細を抽象化し、liblink
という共通インターフェースを通じてリンカ機能を利用するようにするためのものです。
コアとなるコードの解説
このコミットの核心は、Goコンパイラのバックエンド(cmd/5c
, cmd/6c
, cmd/8c
)が、リンカとの連携方法を根本的に変更した点にあります。
- データ構造の共通化: 以前は各コンパイラが独自に
Adr
やProg
といった命令やアドレスを表す構造体を持っていましたが、このコミットでこれらが削除され、liblink
が提供する共通のAddr
構造体を使用するようになりました。これにより、コンパイラとリンカの間で命令やオペランドの表現が統一され、データの受け渡しがより効率的かつ安全になります。例えば、naddr
関数(ノードからアドレス構造体を生成する関数)の引数がAdr*
からAddr*
に変更されています。 - リンカ機能の委譲: オブジェクトファイルの書き出し(
outcode
関数内)やシンボル情報の管理(zname
,zaddr
など)といった、以前はコンパイラが直接行っていた多くのリンカ関連の処理が削除され、liblink
のAPI(linkouthist
,linkwritefuncs
など)に委譲されるようになりました。これにより、コンパイラは命令生成に専念し、リンカはオブジェクトファイルの最終的な生成と結合に専念するという、役割分担が明確化されました。 - シンボル解決の一元化:
Sym
からLSym
への移行は、リンカがプログラム全体のシンボル情報を一元的に管理するための基盤を強化します。コンパイラはlinksym
のような関数を通じて、ローカルなシンボルをリンカが認識できるグローバルなシンボルに変換するようになりました。 - モジュール性の向上: これらの変更により、Goのツールチェイン全体のモジュール性が大幅に向上しました。リンカの機能が
liblink
にカプセル化されたことで、将来的にリンカの実装を変更したり、新しいアーキテクチャをサポートしたりする際に、コンパイラ側の変更を最小限に抑えることができるようになりました。これは、Go 1.3のリンカ再構築の主要な目標の一つでした。
このコミットは、Goのビルドシステムがより堅牢でスケーラブルになるための重要な基盤を築いたと言えます。
関連リンク
- Go CL 34580044: https://golang.org/cl/34580044
参考にした情報源リンク
- Go 1.3 Linker Overhaul by Russ Cox: https://golang.org/s/go13linker
- The Go 1.3 Linker Overhaul: https://hexang.org/post/go-1.3-linker-overhaul/