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

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

このコミットは、Go言語のリンカ (cmd/ld) における isobj 変数の残存する使用箇所を削除し、Cgoビルドの不具合を修正することを目的としています。具体的には、symtab.c 内で isobj の代わりに linkmode == LinkExternal を使用するように変更されています。

コミット

commit b35019fe9ad730216bacc665fa8144c49be695ad
Author: Rémy Oudompheng <oudomphe@phare.normalesup.org>
Date:   Wed Mar 20 08:32:11 2013 +0100

    cmd/ld: remove remaining occurrence of isobj.
    
    Fixes cgo builds.
    
    R=golang-dev, minux.ma
    CC=golang-dev
    https://golang.org/cl/7784044

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

https://github.com/golang/go/commit/b35019fe9ad730216bacc665fa8144c49be695ad

元コミット内容

Goリンカ (cmd/ld) から isobj 変数の残りの出現箇所を削除します。これにより、Cgoビルドに関する問題が修正されます。

変更の背景

このコミットの主な背景は、Goリンカのコードベースのクリーンアップと、Cgo (C言語との相互運用) を使用したGoプログラムのビルドにおける既知の不具合の修正です。

isobj 変数は、Goリンカの初期の設計段階で使用されていた可能性のあるフラグで、オブジェクトファイルがどのように処理されるかを示すものでした。しかし、Goリンカの進化に伴い、この変数は冗長になったか、あるいはより汎用的なメカニズム (linkmode など) に置き換えられるべきものとなりました。

Cgoビルドは、GoコードとCコードをリンクする複雑なプロセスを伴います。リンカがオブジェクトファイルの処理方法を誤解すると、シンボル解決の失敗や不正なアドレス計算など、ビルドエラーが発生する可能性があります。このコミットは、isobj の不適切な使用がCgoビルドに悪影響を与えていたことを示唆しており、その削除と適切な linkmode の使用によってこの問題を解決しようとしています。

前提知識の解説

  • Goリンカ (cmd/ld): Go言語のコンパイラツールチェーンの一部であり、Goのソースコードから生成されたオブジェクトファイルや、Cgoによって生成されたCのオブジェクトファイルなどを結合して実行可能なバイナリを生成する役割を担います。シンボル解決、セクションの配置、外部ライブラリとのリンクなど、バイナリ生成の最終段階を管理します。
  • Cgo: GoプログラムからC言語のコードを呼び出すためのGoの機能です。Cgoを使用すると、既存のCライブラリをGoプロジェクトに統合したり、パフォーマンスが重要な部分をCで記述したりすることができます。Cgoを使用する際には、GoコンパイラとCコンパイラが連携し、最終的にはGoリンカがGoとCのオブジェクトファイルをリンクします。
  • isobj: このコミットで削除された変数です。Goリンカの内部で使用されていたブール型のフラグで、おそらく現在の処理対象がオブジェクトファイルであるかどうかを示していました。しかし、その役割は linkmode のようなより詳細なリンキングモードを示す変数に置き換えられたと考えられます。
  • linkmode: Goリンカにおけるリンキングモードを示す変数です。Goリンカは、内部リンク (Goのオブジェクトファイルのみをリンクする場合) や外部リンク (Cgoを使用する場合など、外部リンカに依存する場合) など、複数のリンキングモードをサポートしています。
  • LinkExternal: linkmode の値の一つで、外部リンカ (通常はGCCなどのCコンパイラツールチェーンに含まれるリンカ) を使用して最終的なリンクを行うことを示します。Cgoビルドでは、Cのオブジェクトファイルをリンクするために外部リンカが必要となるため、このモードが使用されます。
  • symtab.c: Goリンカのソースコードファイルの一つで、シンボルテーブルの管理に関連するロジックが含まれています。シンボルテーブルは、プログラム内の関数や変数などの名前 (シンボル) と、それらがメモリ上のどこに配置されるか (アドレス) のマッピングを保持します。
  • lib.h: Goリンカの共通ヘッダーファイルで、リンカ全体で共有されるグローバル変数や関数プロトタイプなどが宣言されています。

技術的詳細

このコミットの技術的な核心は、Goリンカがオブジェクトファイルのオフセットを計算する際に、もはや isobj という古いグローバル変数に依存しないようにした点です。

以前のコードでは、putelfsym 関数内でELFシンボルを配置する際に、isobj が真である場合にのみ addr -= xo->sect->vaddr; というオフセット調整を行っていました。これは、オブジェクトファイル内のアドレスがセクションの仮想アドレスからの相対オフセットとして扱われるべき場合に適用されるロジックでした。

しかし、この isobj フラグは、リンカの全体的な状態を正確に反映していなかったか、あるいはより適切な linkmode 変数によってその役割が代替されるべきでした。特にCgoビルドのような外部リンカを使用するシナリオでは、リンカの動作モードが重要になります。

このコミットでは、isobj 変数自体が src/cmd/ld/lib.h から完全に削除されました。そして、src/cmd/ld/symtab.c 内の putelfsym 関数における条件分岐が、if(isobj) から if(linkmode == LinkExternal) に変更されました。

この変更は、以下の重要な意味を持ちます。

  1. 正確なリンキングモードの反映: isobj という曖昧なフラグに依存する代わりに、リンカが現在「外部リンキングモード」で動作しているかどうかを明示的にチェックするようになりました。LinkExternal モードは、Cgoビルドのように外部リンカが最終的なバイナリ生成に関与する場合に設定されます。
  2. Cgoビルドの修正: Cgoビルドでは、GoのオブジェクトファイルとCのオブジェクトファイルが混在し、最終的に外部リンカによって結合されます。このプロセスにおいて、シンボルのアドレスオフセットの計算が isobj の誤った状態によって狂っていた可能性があります。linkmode == LinkExternal を使用することで、外部リンカが期待する形式でシンボル情報が正しく処理されるようになり、Cgoビルドの不具合が解消されます。
  3. コードのクリーンアップ: 不要になった isobj 変数を削除することで、リンカのコードベースが整理され、保守性が向上します。

この変更により、Goリンカはより堅牢になり、特にCgoを使用する複雑なビルドシナリオにおいて、シンボル解決とアドレス計算の正確性が保証されるようになりました。

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

--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -143,7 +143,6 @@ EXTERN	int	nldflag;
 EXTERN	char**	ldflag;
 EXTERN	int	havedynamic;
 EXTERN	int	iscgo;
-EXTERN	int	isobj;
 EXTERN	int	elfglobalsymndx;
 EXTERN	int flag_race;
 EXTERN	int flag_shared;
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index 6c69953cf1..698194f849 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -136,7 +136,7 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
 		return;
 
 	off = putelfstr(s);
-	if(isobj)
+	if(linkmode == LinkExternal)
 		addr -= xo->sect->vaddr;
 	putelfsyment(off, addr, size, (bind<<4)|(type&0xf), xo->sect->elfsect->shnum, (x->type & SHIDDEN) ? 2 : 0);
 	x->elfsym = numelfsym++;

コアとなるコードの解説

このコミットは、Goリンカの2つのファイルに影響を与えています。

  1. src/cmd/ld/lib.h:

    • EXTERN int isobj; の行が削除されています。これは、isobj というグローバル変数の宣言がリンカ全体から完全に削除されたことを意味します。これにより、この変数がもはやリンカのどの部分でも使用されないことが保証されます。
  2. src/cmd/ld/symtab.c:

    • putelfsym 関数内の条件分岐が変更されています。
    • 変更前: if(isobj)
      • これは、isobj フラグが真である場合に、シンボルのアドレス addr からセクションの仮想アドレス xo->sect->vaddr を減算するというロジックでした。この減算は、シンボルアドレスをセクションの開始からの相対オフセットに変換するために行われます。
    • 変更後: if(linkmode == LinkExternal)
      • isobj の代わりに、linkmodeLinkExternal であるかどうかをチェックするようになりました。LinkExternal は、リンカが外部リンカ (例: GCC) を使用して最終的なバイナリを生成するモードであることを示します。Cgoビルドではこのモードが使用されます。
      • この変更により、シンボルアドレスのオフセット調整が、外部リンカが必要とする形式で正確に行われるようになります。これにより、Cgoビルドにおけるシンボル解決の不整合が解消され、正しい実行可能ファイルが生成されるようになります。

この変更は、Goリンカの内部ロジックをより正確で堅牢なものにし、特にCgoのような複雑なビルドシナリオでの信頼性を向上させています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (Goリンカ、Cgoに関する情報)
  • Go言語のソースコード (特に cmd/ld ディレクトリ)
  • ELF (Executable and Linkable Format) の仕様に関する一般的な知識
  • リンカの動作に関する一般的な知識
  • Gitのコミットログと差分表示