[インデックス 1882] ファイルの概要
このコミットは、Go言語のツールチェインの一部であるリンカ 8l
における変更を記録しています。具体的には、rt0
オブジェクトファイルの自動ロードの削除と、デバッグ用の print
文の削除が行われています。
コミット
commit 34a5537edbc154419822b96173101e9c774af5a1
Author: Russ Cox <rsc@golang.org>
Date: Tue Mar 24 18:02:24 2009 -0700
drop rt0 object from 8l (already dropped from 6l).
remove debugging print.
R=r
DELTA=8 (0 added, 8 deleted, 0 changed)
OCL=26695
CL=26710
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/34a5537edbc154419822b96173101e9c774af5a1
元コミット内容
8l
リンカから rt0
オブジェクトファイルを削除し(6l
からは既に削除済み)、デバッグ用の print
文を削除する。
変更の背景
このコミットは、Go言語がまだ初期開発段階にあった2009年に行われたものです。当時のGoツールチェインは、Plan 9オペレーティングシステムのツールチェイン(8c
, 8l
, 6c
, 6l
など)に強く影響を受けていました。
8l
は、x86 (32-bit) アーキテクチャ向けのGoリンカです。同様に6l
はamd64 (64-bit) アーキテクチャ向けのリンカでした。rt0
(runtime 0) は、プログラムのエントリポイントとなる非常に低レベルなランタイムコードを含むオブジェクトファイルです。これはC言語におけるcrt0
(C runtime 0) に相当し、プログラムが実行を開始する前に必要な初期化(スタックの設定、引数の処理、main
関数呼び出しなど)を行います。
この変更の背景には、Goランタイムの初期化プロセスにおける設計変更があったと考えられます。rt0
オブジェクトがリンカによって自動的にロードされるのではなく、より明示的な方法でリンクされるように変更された可能性があります。これは、リンカの責務をより明確にし、ビルドプロセスの柔軟性を高めるための一環であったかもしれません。また、デバッグ用の print
文の削除は、開発が進むにつれて不要になった一時的なコードのクリーンアップです。
前提知識の解説
GoツールチェインとPlan 9
Go言語の初期のツールチェインは、Rob PikeやKen ThompsonといったPlan 9の設計者が関わっていたため、Plan 9のツールチェインの命名規則や設計思想を色濃く受け継いでいました。
- コンパイラ:
8c
(x86),6c
(amd64),5c
(ARM) など。 - リンカ:
8l
(x86),6l
(amd64),5l
(ARM) など。 - アセンブラ:
8a
(x86),6a
(amd64),5a
(ARM) など。
これらのツールは、特定のCPUアーキテクチャ(数字がアーキテクチャを示す)とツールタイプ(c
for compiler, l
for linker, a
for assembler)を組み合わせて命名されていました。
rt0
(runtime 0)
rt0
は、Goプログラムが実行される際に最初に実行されるコードです。その主な役割は以下の通りです。
- 環境のセットアップ: プログラムが実行されるための基本的な環境(スタックポインタの初期化、レジスタのクリアなど)をセットアップします。
- コマンドライン引数の処理:
main
関数に渡されるコマンドライン引数を準備します。 - ランタイムの初期化: Goランタイム(スケジューラ、ガベージコレクタなど)の初期化ルーチンを呼び出します。
main
関数の呼び出し: 最終的にユーザーが記述したmain
関数を呼び出して、プログラムの本格的な実行を開始します。
rt0
は通常、アセンブリ言語で書かれており、OSやアーキテクチャに依存する低レベルな処理を行います。
リンカの役割
リンカ(ld
または l
)は、コンパイラやアセンブラによって生成された複数のオブジェクトファイル(.o
ファイル)とライブラリを結合し、実行可能なバイナリファイルを生成するツールです。リンカの主な機能は以下の通りです。
- シンボル解決: 異なるオブジェクトファイル間で参照される関数や変数のアドレスを解決します。
- 再配置: コード内のアドレス参照を、最終的な実行可能ファイル内の正しいメモリ位置に調整します。
- ライブラリの結合: 静的ライブラリや動的ライブラリをプログラムに結合します。
obj.c
Goツールチェインにおける obj.c
のようなファイルは、リンカのオブジェクトファイル処理ロジックを実装していることが多いです。これには、オブジェクトファイルのフォーマット解析、シンボルテーブルの読み込み、セクションの処理などが含まれます。
技術的詳細
このコミットは、Goリンカ 8l
の src/cmd/8l/obj.c
ファイルに対する変更です。
rt0
オブジェクトの自動ロードの削除
変更前のコードでは、debug['l']
フラグが設定されていない場合(つまり、通常ビルド時)、リンカは goroot/lib/rt0_<arch>_<os>.<char>
というパスから rt0
オブジェクトファイルを自動的にロードしようとしていました。
-if(!debug['l']) {
- a = mal(strlen(goroot)+strlen(goarch)+strlen(goos)+20);
- sprint(a, "%s/lib/rt0_%s_%s.%c", goroot, goarch, goos, thechar);
- objfile(a);
-}
このコードブロックが削除されたことにより、8l
はもはや rt0
オブジェクトを自動的に検索してロードしなくなりました。コミットメッセージにある「already dropped from 6l」という記述から、この変更は 6l
リンカ(amd64向け)で先行して行われており、8l
もそれに追従したことがわかります。
この変更の技術的な意味合いはいくつか考えられます。
- ビルドプロセスの明示化:
rt0
が自動的にロードされるのではなく、ビルドシステム(例:go tool link
コマンドの内部処理)が明示的にrt0
オブジェクトをリンカに渡すようになった可能性があります。これにより、リンカの内部ロジックが簡素化され、rt0
の選択やカスタマイズがより柔軟になった可能性があります。 - ランタイム初期化の統合: Goランタイムの初期化ロジックが進化し、
rt0
の役割が変更されたか、あるいはrt0
の内容が他のランタイムオブジェクトに統合された可能性があります。これにより、リンカが特定のrt0
ファイルを「知っている」必要がなくなったのかもしれません。 - クロスコンパイルの簡素化: 異なるアーキテクチャやOS向けのクロスコンパイルにおいて、
rt0
ファイルのパス解決がリンカ内部で行われるよりも、ビルドスクリプトや上位のツールで管理する方が容易になった可能性があります。
デバッグ用 print
文の削除
もう一つの変更は、ldobj
関数内のデバッグ用 print
文の削除です。
-print("import %ld-%ld\\n", import0, import1);
この print
文は、オブジェクトファイルのインポートセクションの範囲 (import0
から import1
) を出力するためのものでした。これは開発中のデバッグ目的で一時的に追加されたものであり、機能が安定したため削除されました。このようなデバッグ出力は、通常、最終的なプロダクションコードには含まれません。
コアとなるコードの変更箇所
src/cmd/8l/obj.c
ファイルにおいて、以下の2つのコードブロックが削除されました。
main
関数内のrt0
オブジェクトロードに関するif
ブロック。ldobj
関数内のprint
文。
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -324,12 +324,6 @@ main(int argc, char *argv[])
}
lookup(INITENTRY, 0)->type = SXREF;
- if(!debug['l']) {
- a = mal(strlen(goroot)+strlen(goarch)+strlen(goos)+20);
- sprint(a, "%s/lib/rt0_%s_%s.%c", goroot, goarch, goos, theos, thechar);
- objfile(a);
- }
-
while(*argv)
objfile(*argv++);
@@ -857,8 +851,6 @@ ldobj(Biobuf *f, int32 len, char *pn)
// ldpkg(f, import1 - import0 - 2, pn);\t// -2 for !\\n
Bseek(f, import1, 0);
-print("import %ld-%ld\\n", import0, import1);
-
newloop:
memset(h, 0, sizeof(h));
version++;
コアとなるコードの解説
main
関数内の変更
削除されたコードは、Goの環境変数 (goroot
, goarch
, goos
) を利用して rt0
オブジェクトファイルのパスを構築し、objfile
関数を呼び出してそのファイルをリンカにロードしていました。
goroot
: Goのインストールディレクトリ。goarch
: ターゲットアーキテクチャ(例:8
for x86)。goos
: ターゲットOS(例:linux
)。thechar
: リンカが処理するオブジェクトファイルのタイプを示す文字(例:8
for x86)。
この自動ロードの削除は、リンカが rt0
の存在を前提とするのではなく、ビルドシステムが明示的に rt0
をリンカに渡すように変更されたことを示唆しています。これは、Goのビルドシステムがより洗練され、リンカの内部ロジックから特定のファイルパスの解決ロジックを分離した結果と考えられます。
ldobj
関数内の変更
ldobj
関数は、オブジェクトファイルを読み込み、その内容を処理するリンカの主要な部分です。削除された print
文は、オブジェクトファイル内のインポートセクションの開始と終了オフセットを表示していました。これは、リンカがオブジェクトファイルをどのように解析しているかをデバッグするために使用された一時的なコードでした。この削除は、そのデバッグ情報がもはや不要になったことを意味します。
関連リンク
- Go言語の初期のツールチェインに関する議論やドキュメントは、Goプロジェクトのメーリングリストアーカイブや初期のコミット履歴に多く見られます。
- Goのランタイム初期化に関する現在の情報は、Goのソースコード(特に
src/runtime
ディレクトリ)や公式ドキュメントで確認できます。
参考にした情報源リンク
- Go言語の公式GitHubリポジトリ: https://github.com/golang/go
- Go言語の初期のコミット履歴と関連する議論。
- Plan 9オペレーティングシステムのツールチェインに関する一般的な情報。
- リンカの基本的な概念と
crt0
の役割に関する一般的なコンピュータサイエンスの知識。 - Goの
rt0
に関する情報は、Goのソースコード内のsrc/runtime
ディレクトリや、Goのビルドプロセスに関するドキュメントから得られます。 - Goのツールチェインの歴史に関する記事やプレゼンテーション。