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

[インデックス 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プログラムが実行される際に最初に実行されるコードです。その主な役割は以下の通りです。

  1. 環境のセットアップ: プログラムが実行されるための基本的な環境(スタックポインタの初期化、レジスタのクリアなど)をセットアップします。
  2. コマンドライン引数の処理: main 関数に渡されるコマンドライン引数を準備します。
  3. ランタイムの初期化: Goランタイム(スケジューラ、ガベージコレクタなど)の初期化ルーチンを呼び出します。
  4. main 関数の呼び出し: 最終的にユーザーが記述した main 関数を呼び出して、プログラムの本格的な実行を開始します。

rt0 は通常、アセンブリ言語で書かれており、OSやアーキテクチャに依存する低レベルな処理を行います。

リンカの役割

リンカ(ld または l)は、コンパイラやアセンブラによって生成された複数のオブジェクトファイル(.o ファイル)とライブラリを結合し、実行可能なバイナリファイルを生成するツールです。リンカの主な機能は以下の通りです。

  • シンボル解決: 異なるオブジェクトファイル間で参照される関数や変数のアドレスを解決します。
  • 再配置: コード内のアドレス参照を、最終的な実行可能ファイル内の正しいメモリ位置に調整します。
  • ライブラリの結合: 静的ライブラリや動的ライブラリをプログラムに結合します。

obj.c

Goツールチェインにおける obj.c のようなファイルは、リンカのオブジェクトファイル処理ロジックを実装していることが多いです。これには、オブジェクトファイルのフォーマット解析、シンボルテーブルの読み込み、セクションの処理などが含まれます。

技術的詳細

このコミットは、Goリンカ 8lsrc/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 もそれに追従したことがわかります。

この変更の技術的な意味合いはいくつか考えられます。

  1. ビルドプロセスの明示化: rt0 が自動的にロードされるのではなく、ビルドシステム(例: go tool link コマンドの内部処理)が明示的に rt0 オブジェクトをリンカに渡すようになった可能性があります。これにより、リンカの内部ロジックが簡素化され、rt0 の選択やカスタマイズがより柔軟になった可能性があります。
  2. ランタイム初期化の統合: Goランタイムの初期化ロジックが進化し、rt0 の役割が変更されたか、あるいは rt0 の内容が他のランタイムオブジェクトに統合された可能性があります。これにより、リンカが特定の rt0 ファイルを「知っている」必要がなくなったのかもしれません。
  3. クロスコンパイルの簡素化: 異なるアーキテクチャやOS向けのクロスコンパイルにおいて、rt0 ファイルのパス解決がリンカ内部で行われるよりも、ビルドスクリプトや上位のツールで管理する方が容易になった可能性があります。

デバッグ用 print 文の削除

もう一つの変更は、ldobj 関数内のデバッグ用 print 文の削除です。

-print("import %ld-%ld\\n", import0, import1);

この print 文は、オブジェクトファイルのインポートセクションの範囲 (import0 から import1) を出力するためのものでした。これは開発中のデバッグ目的で一時的に追加されたものであり、機能が安定したため削除されました。このようなデバッグ出力は、通常、最終的なプロダクションコードには含まれません。

コアとなるコードの変更箇所

src/cmd/8l/obj.c ファイルにおいて、以下の2つのコードブロックが削除されました。

  1. main 関数内の rt0 オブジェクトロードに関する if ブロック。
  2. 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のツールチェインの歴史に関する記事やプレゼンテーション。