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

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

このコミットは、Go言語のリンカ (cmd/ld) における SDYNIMPORT シンボルのテストに関する修正です。特にWindowsビルドの問題を解決することを目的としています。

コミット

  • コミットハッシュ: 3a32367040a06b55fa93baddba2b57371079af90
  • 作者: Alex Brainman alex.brainman@gmail.com
  • コミット日時: 2013年5月2日 木曜日 13:02:00 +1000

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

https://github.com/golang/go/commit/3a32367040a06b55fa93baddba2b57371079af90

元コミット内容

cmd/ld: fix SDYNIMPORT symbol test

As advised by iant. Fixes windows build.

R=golang-dev, r
CC=golang-dev, iant
https://golang.org/cl/9110044

変更の背景

この変更は、Goリンカ (cmd/ld) が SDYNIMPORT シンボルを誤って処理していた問題を修正するために行われました。特に、この問題はWindows環境でのGoプログラムのビルドに影響を与えていました。コミットメッセージには「iantの助言による。Windowsビルドを修正する。」と明記されており、特定のビルド環境で発生するリンカの問題に対処するための修正であることが示唆されています。

GoプログラムがC言語のコードと連携するCgoを使用する場合、外部ライブラリのシンボルをどのようにリンクするかは非常に重要です。静的リンクと動的リンクの選択は、プログラムの配布方法や実行時の依存関係に影響を与えます。このコミットは、リンカが動的にインポートされるべきシンボルを正しく識別するための条件を厳密にすることで、Windowsビルドの安定性を向上させています。

前提知識の解説

このコミットを理解するためには、以下の概念について知っておく必要があります。

  • Goリンカ (cmd/ld): Go言語のコンパイラツールチェーンの一部であり、Goのソースコードから生成されたオブジェクトファイルを結合して実行可能ファイルを生成する役割を担います。Cgoを使用する場合、GoのコードとCのコードをリンクする複雑な処理も行います。
  • シンボル (Symbol): プログラム内の関数、変数、またはその他のエンティティの名前です。リンカはこれらのシンボルを解決し、それらがメモリ内のどこに配置されるかを決定します。
  • SDYNIMPORT: Goリンカが内部的に使用するシンボルタイプの一つで、動的にインポートされるシンボル(つまり、実行時に外部の共有ライブラリからロードされるシンボル)を示します。これは、Cgoを通じて外部のDLLや共有オブジェクトの関数を呼び出す際に特に重要になります。
  • cgo_import_staticcgo_import_dynamic: CgoがCの関数をGoから呼び出す際に使用するリンカディレクティブです。
    • cgo_import_static: シンボルを静的にリンクすることを示唆します。つまり、実行可能ファイルに直接組み込まれます。
    • cgo_import_dynamic: シンボルを実行時に動的にロードすることを示唆します。これは、共有ライブラリ(WindowsではDLL、Linuxでは.so)に依存します。
  • s->extname: リンカの内部データ構造におけるシンボルの外部名(外部リンケージを持つ名前)を指します。
  • s->dynimplib: リンカの内部データ構造における、シンボルが動的にインポートされるライブラリの名前を指します。これが nil でない場合、そのシンボルが特定の動的ライブラリからインポートされることを示します。
  • s->cgoexport: シンボルがCgoによってエクスポートされる(GoからCへ公開される)かどうかを示すフラグです。

技術的詳細

このコミットの核心は、src/cmd/ld/lib.c ファイル内の loadlib 関数における条件式の変更です。この関数は、リンカがライブラリをロードし、シンボルを処理する際に呼び出されます。

変更前のコードでは、シンボルを SDYNIMPORT タイプとしてマークする条件は以下の通りでした。

if(s->extname != nil && s->cgoexport == 0) {
    s->type = SDYNIMPORT;
} else {
    s->type = 0;
}

この条件は、「シンボルが外部名を持ち (s->extname != nil)、かつCgoによってエクスポートされていない (s->cgoexport == 0)」場合に、そのシンボルを動的インポートとして扱っていました。しかし、この条件だけでは不十分であり、特にWindows環境で問題を引き起こしていました。

Windowsでは、動的リンクのメカニズムが他のOS(Linuxなど)と異なる場合があります。シンボルが動的にインポートされるためには、それが実際に特定の動的インポートライブラリ (.lib ファイルなど) に関連付けられている必要があります。s->dynimplib は、この関連付けを示す重要な情報です。

変更後のコードでは、この s->dynimplib のチェックが追加されました。

if(s->extname != nil && s->dynimplib != nil && s->cgoexport == 0) {
    s->type = SDYNIMPORT;
} else {
    s->type = 0;
}

新しい条件は、「シンボルが外部名を持ち (s->extname != nil)、かつ動的インポートライブラリに関連付けられており (s->dynimplib != nil)、かつCgoによってエクスポートされていない (s->cgoexport == 0)」場合にのみ、そのシンボルを SDYNIMPORT として扱います。

この追加された条件により、リンカは本当に動的にインポートされるべきシンボルのみを SDYNIMPORT として正しく識別できるようになります。これにより、Windowsビルドにおけるリンカの誤ったシンボル解決が修正され、ビルドが成功するようになります。具体的には、s->dynimplibnil であるにもかかわらず SDYNIMPORT とマークされてしまうケースが排除され、リンカが不適切な動的インポートを試みることを防ぎます。

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

変更は src/cmd/ld/lib.c ファイルの loadlib 関数内で行われました。

--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -336,7 +336,7 @@ loadlib(void)
 				// cgo_import_static and cgo_import_dynamic,
 				// then we want to make it cgo_import_dynamic
 				// now.
-			if(s->extname != nil && s->cgoexport == 0) {
+			if(s->extname != nil && s->dynimplib != nil && s->cgoexport == 0) {
 				s->type = SDYNIMPORT;
 				} else
 				s->type = 0;

コアとなるコードの解説

上記の差分が示すように、if 文の条件式に s->dynimplib != nil という条件が追加されました。

  • 変更前: if(s->extname != nil && s->cgoexport == 0)
    • この条件は、シンボルが外部名を持ち、かつCgoによってエクスポートされていない場合に SDYNIMPORT とマークしていました。しかし、これだけでは、そのシンボルが実際に動的ライブラリからインポートされるべきかどうかを完全に判断できませんでした。
  • 変更後: if(s->extname != nil && s->dynimplib != nil && s->cgoexport == 0)
    • 新しい条件は、既存の条件に加えて、シンボルが動的インポートライブラリに関連付けられている (s->dynimplib != nil) ことを要求します。これにより、リンカは、外部名を持ち、Cgoによってエクスポートされておらず、かつ実際に動的ライブラリからインポートされることが意図されているシンボルのみを SDYNIMPORT として正しく分類するようになります。
    • この修正により、Windows環境で発生していた、本来動的インポートではないシンボルが誤って SDYNIMPORT とマークされ、リンカが不適切な処理を試みることでビルドエラーが発生する問題が解決されました。

関連リンク

参考にした情報源リンク

  • Go言語のリンカの動作に関する一般的な情報
  • Cgoのドキュメントと動的リンクに関する情報
  • Go言語のIssueトラッカーやメーリングリストでの関連議論 (特にWindowsビルドに関するもの)
  • SDYNIMPORT シンボルタイプに関するGoリンカのソースコード内のコメントや定義