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

[インデックス 1217] ファイルの概要

このコミットは、Go言語のリンカである6lにおけるデバッガが使用するmachテーブル内のシンボルテーブルの位置記録に関するバグ修正です。具体的には、シンボルテーブルが移動された際に、machテーブルが正しい場所を記録していなかった問題に対処しています。

コミット

commit 284a50c109495973def8b9e7d94fa329a207a99e
Author: Russ Cox <rsc@golang.org>
Date:   Fri Nov 21 16:13:11 2008 -0800

    fix 6l bug - moved symbol table without
            recording correct place in mach tables
            used by debuggers.
    
    R=r
    DELTA=4  (0 added, 2 deleted, 2 changed)
    OCL=19810
    CL=19849

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/284a50c109495973def8b9e7d94fa329a207a99e

元コミット内容

fix 6l bug - moved symbol table without
        recording correct place in mach tables
        used by debuggers.

変更の背景

このコミットは、Go言語の初期開発段階におけるリンカ6lのバグ修正です。6lは、Goプログラムをコンパイルした際に生成されるオブジェクトファイルをリンクし、実行可能ファイルを生成する役割を担っていました。デバッガが正しく機能するためには、実行可能ファイル内のシンボル情報(変数名、関数名、行番号など)が正確に参照できる必要があります。

コミットメッセージによると、このバグはシンボルテーブルがメモリ内で移動された際に発生しました。リンカがシンボルテーブルを再配置したにもかかわらず、デバッガがシンボル情報を解決するために使用する「machテーブル」(おそらくMach-O形式の実行可能ファイルにおけるシンボル関連のメタデータ)が、その新しい位置を正しく記録していなかったと考えられます。結果として、デバッガはシンボルを正しく解決できず、デバッグ体験に支障をきたしていたと推測されます。

前提知識の解説

  • リンカ (Linker): コンパイラによって生成された複数のオブジェクトファイル(機械語コードとシンボル情報を含む)を結合し、単一の実行可能ファイルやライブラリを生成するプログラムです。リンカは、異なるオブジェクトファイル間で参照されるシンボル(関数や変数)を解決し、それらのアドレスを決定します。
  • シンボルテーブル (Symbol Table): プログラム内の識別子(変数名、関数名など)とその属性(型、スコープ、メモリ上のアドレスなど)を格納するデータ構造です。コンパイラやリンカ、デバッガがプログラムの構造を理解し、シンボルを解決するために使用します。
  • デバッガ (Debugger): プログラムの実行を制御し、その内部状態(変数の値、実行パスなど)を検査することで、バグを発見・修正するためのツールです。デバッガはシンボルテーブルを利用して、ソースコードの変数名や関数名と、実行時のメモリ上のアドレスを対応付けます。
  • Mach-O (Mach Object): AppleのmacOSやiOSで使用される実行可能ファイル、オブジェクトファイル、共有ライブラリのフォーマットです。Mach-Oファイルは、ヘッダ、ロードコマンド、セグメント、セクションなどから構成され、シンボルテーブルやデバッグ情報も含まれます。6lが生成する実行可能ファイルがMach-O形式であった場合、machsymseg関数はMach-Oのシンボル関連のセクションを操作していた可能性があります。
  • 6l: Go言語の初期のツールチェインにおけるリンカの一つです。Go言語はクロスコンパイルを重視しており、6lは64ビットIntelアーキテクチャ(amd64)向けのリンカを指していました。Goのツールチェインは、ターゲットアーキテクチャごとに異なるリンカ(例: 8l for 386, 5l for ARM)を持っていました。

技術的詳細

このコミットは、src/cmd/6l/asm.cファイル内の変更です。asm.cは、リンカのバックエンドの一部であり、アセンブリコードの生成やオブジェクトファイルの構造化に関連する処理を行っていたと考えられます。

変更点を見ると、machsymsegという関数が呼び出されている箇所が修正されています。この関数は、おそらくMach-O形式の実行可能ファイルにおけるシンボルセグメント(またはシンボルテーブルに関連するセクション)の情報を設定するためのものです。

元のコードでは、machsymsegの呼び出しにおいて、シンボルテーブルとラインカバレッジ情報(lcsize)のファイルオフセットを計算するために、vという変数が使用されていました。vは、データセクションのサイズ(datsize)とシンボルテーブルのサイズ(symsize)に基づいてインクリメントされていました。

// 変更前
v += rnd(datsize, INITRND);
machsymseg(v,symsize);      /* fileoffset,filesize */
v += symsize;
machsymseg(v,lcsize);       /* fileoffset,filesize */

このコードは、シンボルテーブルがメモリ上で移動された際に、vがその新しいオフセットを正確に反映していなかった可能性を示唆しています。つまり、vが指すアドレスが、実際にシンボルテーブルが配置されたアドレスとずれてしまっていたため、デバッガが参照するmachテーブル内の情報が不正になっていたと考えられます。

修正後のコードでは、machsymsegの呼び出しでvの代わりにsymoという変数が使用されています。

// 変更後
machsymseg(symo+8,symsize);     /* fileoffset,filesize */
machsymseg(symo+8+symsize,lcsize);      /* fileoffset,filesize */

symoは、おそらくシンボルテーブルの開始オフセットを正確に保持している変数であると推測されます。symo+8というオフセットが使われているのは、Mach-Oのシンボルテーブルの構造や、特定のヘッダ情報が8バイト分存在するためかもしれません。この変更により、machsymseg関数はシンボルテーブルとラインカバレッジ情報の正しいファイルオフセットを受け取るようになり、デバッガがこれらの情報を正確に解決できるようになりました。

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

src/cmd/6l/asm.c ファイルの asmb 関数内。

--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -409,10 +409,8 @@ asmb(void)\
 				7, 5,			/* protects */
 				0, 0);			/* sections flags */
 
-			v += rnd(datsize, INITRND);
-			machsymseg(v,symsize);	/* fileoffset,filesize */
-			v += symsize;
-			machsymseg(v,lcsize);	/* fileoffset,filesize */
+			machsymseg(symo+8,symsize);	/* fileoffset,filesize */
+			machsymseg(symo+8+symsize,lcsize);	/* fileoffset,filesize */
 		}
 		break;
 	case 7:

コアとなるコードの解説

変更は、asmb関数内の特定のcaseブロック(おそらくMach-O形式の出力に関連する部分)で行われています。

  • 削除された行:

    v += rnd(datsize, INITRND);
    machsymseg(v,symsize);  /* fileoffset,filesize */
    v += symsize;
    machsymseg(v,lcsize);   /* fileoffset,filesize */
    

    これらの行は、vという変数を使ってシンボルテーブルとラインカバレッジ情報のオフセットを計算し、machsymsegに渡していました。rnd(datsize, INITRND)は、データセクションのサイズを特定の境界(INITRND)にアラインメントするための関数です。この計算方法が、シンボルテーブルの実際の配置とずれていたことが問題でした。

  • 追加された行:

    machsymseg(symo+8,symsize);     /* fileoffset,filesize */
    machsymseg(symo+8+symsize,lcsize);      /* fileoffset,filesize */
    

    これらの行では、vの代わりにsymoという変数が使用されています。symoは、シンボルテーブルの開始オフセットを正確に保持していると推測されます。+8というオフセットは、Mach-Oのシンボルテーブルの構造や、その前に存在する特定のメタデータ(例えば、シンボルテーブルのサイズやオフセットを示すヘッダ)のサイズを考慮している可能性があります。これにより、machsymsegはシンボルテーブルとラインカバレッジ情報の正しいファイルオフセットを受け取るようになり、デバッガがこれらの情報を正確に解決できるようになりました。

この修正は、リンカが生成する実行可能ファイルの内部構造、特にデバッグ情報に関連する部分の正確性を向上させるものであり、Go言語のデバッグ体験の安定化に貢献しました。

関連リンク

  • Go言語の初期のリンカに関する議論やドキュメントは、現在のGoの公式ドキュメントからは見つけにくい可能性があります。当時のメーリングリストやGoの初期のソースコードリポジトリを深く掘り下げる必要があるかもしれません。
  • Mach-Oファイルフォーマットに関する一般的な情報は、Appleの開発者ドキュメントや関連する技術記事で確認できます。

参考にした情報源リンク

  • Go言語のGitHubリポジトリ (コミットの直接リンク)
  • Mach-Oファイルフォーマットに関する一般的な情報源 (例: Wikipedia, Apple Developer Documentation)
  • リンカ、シンボルテーブル、デバッガに関する一般的なコンピュータサイエンスの知識。
  • Go言語の初期のツールチェインに関する歴史的な情報(Goのブログ記事や初期の設計ドキュメントなど)。