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

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

このコミットは、Go言語のリンカであるcmd/ldがホストリンカを使用する際に、-rオプションを-rpathとして適切に渡すように修正するものです。これにより、共有ライブラリの検索パスが正しく設定され、実行時の動的リンクの問題が解決されます。

コミット

commit 8877a2dfee4cd37825f0df2fa7bb53573d04ae5b
Author: Ian Lance Taylor <iant@golang.org>
Date:   Thu Mar 28 09:37:32 2013 -0700

    cmd/ld: when using host linker pass -r option as -rpath
    
    R=golang-dev, daniel.morsing
    CC=golang-dev
    https://golang.org/cl/8070043

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

https://github.com/golang/go/commit/8877a2dfee4cd37825f0df2fa7bb53573d04ae5b

元コミット内容

cmd/ld: when using host linker pass -r option as -rpath

R=golang-dev, daniel.morsing
CC=golang-dev
https://golang.org/cl/8070043

変更の背景

Go言語のビルドシステムは、Go自身のリンカ(cmd/ld)を使用することもあれば、システムにインストールされているホストリンカ(例: gccが内部的に使用するld)を使用することもあります。特にCGO(C言語との相互運用)を使用する場合や、特定のプラットフォームではホストリンカが利用されます。

このコミット以前は、Goのビルドプロセスにおいて、共有ライブラリの検索パスを指定するための-rオプションが、ホストリンカに正しく伝達されていませんでした。その結果、ビルドされた実行ファイルが、実行時に必要な共有ライブラリを見つけられず、エラーとなる可能性がありました。

具体的には、Goのリンカが内部的に管理しているrpath(Run-time search path)情報が、ホストリンカに渡される際に、ホストリンカが期待する形式(-Wl,-rpath,)に変換されていなかったことが問題でした。この修正は、この変換を適切に行うことで、動的リンクされたGoプログラムが、実行時に必要な共有ライブラリを正しくロードできるようにすることを目的としています。

前提知識の解説

リンカ (Linker)

リンカは、コンパイラによって生成されたオブジェクトファイル(機械語コードとデータを含むファイル)を結合し、実行可能なプログラムや共有ライブラリを作成するツールです。このプロセスには、未解決のシンボル(関数や変数の参照)を解決し、それらを適切なメモリ位置にマッピングする作業が含まれます。

動的リンク (Dynamic Linking) と静的リンク (Static Linking)

  • 静的リンク: プログラムが必要とするすべてのライブラリコードが、コンパイル時に実行ファイルに直接組み込まれます。これにより、実行ファイルは自己完結型となり、他のライブラリファイルに依存しません。しかし、実行ファイルのサイズが大きくなり、ライブラリの更新があった場合にプログラム全体を再コンパイルする必要があります。
  • 動的リンク: プログラムが必要とするライブラリコードは、実行ファイルには組み込まれず、実行時にOSによってロードされます。これにより、実行ファイルのサイズが小さくなり、複数のプログラムで同じライブラリを共有できるためメモリ効率が向上します。また、ライブラリの更新があっても、プログラムを再コンパイルせずに新しいライブラリを利用できます。しかし、実行時にライブラリが見つからないとプログラムが起動できないという問題が発生する可能性があります。

RPATH (Run-time search path)

RPATHは、動的リンクされた実行ファイルが、実行時に共有ライブラリを検索するパスを指定するためのメカニズムです。通常、OSは共有ライブラリを検索するために、標準的なシステムディレクトリ(例: /lib, /usr/lib)や環境変数(例: LD_LIBRARY_PATH on Linux, DYLD_LIBRARY_PATH on macOS)を使用します。しかし、RPATHを使用すると、実行ファイル自体に特定の検索パスを埋め込むことができます。これにより、環境変数に依存せずに、アプリケーション固有のライブラリパスを指定することが可能になります。これは、特にアプリケーションが特定のディレクトリ構造に依存している場合や、システム全体に影響を与えずにライブラリの場所を制御したい場合に有用です。

cmd/ld

cmd/ldは、Go言語の標準リンカです。Goプログラムのビルドにおいて、Goのコンパイラが生成したオブジェクトファイルをリンクし、実行ファイルを生成する役割を担います。Goのリンカは、Go独自のランタイムやガベージコレクタ、スケジューラなど、Go言語の特性を考慮したリンク処理を行います。

ホストリンカ

ホストリンカとは、GoのビルドシステムがGo自身のリンカではなく、実行環境(ホストOS)に元々インストールされているリンカ(例: GNU ld)を使用する場合のリンカを指します。CGOを使用するGoプログラムは、C言語のコードをコンパイルしてリンクする必要があるため、通常はホストリンカが使用されます。

-Wl,option

-Wl,optionは、gccclangなどのコンパイラドライバが、内部的に呼び出すリンカにオプションを渡すための一般的な構文です。-Wl,の後に続く文字列が、リンカに直接渡されます。例えば、-Wl,-rpath,/path/to/libは、リンカに-rpath,/path/to/libというオプションを渡すことを意味します。

技術的詳細

このコミットの技術的な核心は、Goのリンカ(cmd/ld)がホストリンカを呼び出す際に、rpathの情報を正しく-Wl,-rpath,形式で渡すようにした点です。

Goのビルドプロセスでは、rpathという内部変数が、共有ライブラリの検索パスを保持しています。このrpathは、Goのビルド設定や、CGOのコンパイルオプションなどから設定されることがあります。

src/cmd/ld/lib.cファイルは、cmd/ldのリンカ処理の一部を担っており、特にhostlink関数は、Goのリンカが外部のホストリンカを呼び出す際の引数を構築する役割を持っています。

変更前は、hostlink関数内でrpath変数が設定されていても、それがホストリンカに渡されるargv(引数リスト)に追加されていませんでした。そのため、ホストリンカはGoのビルドプロセスが意図したrpath情報を認識できず、結果として実行時に共有ライブラリが見つからないという問題が発生していました。

このコミットでは、hostlink関数内に以下のコードが追加されました。

    if(rpath)
        argv[argc++] = smprint("-Wl,-rpath,%s", rpath);

このコードは、rpath変数が空でない(つまり、共有ライブラリの検索パスが指定されている)場合に、smprint関数を使用して-Wl,-rpath,%sという形式の文字列を生成し、それをホストリンカに渡す引数リストargvに追加します。%sの部分には、実際のrpathの値が埋め込まれます。

これにより、ホストリンカは-Wl,-rpath,/path/to/your/libsのような形式のオプションを受け取り、そのrpath情報を最終的な実行ファイルに埋め込むことができるようになります。結果として、ビルドされたGoプログラムは、実行時に指定されたパスで共有ライブラリを正しく検索し、ロードできるようになります。

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

変更はsrc/cmd/ld/lib.cファイルに集中しています。

--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -636,6 +636,9 @@ hostlink(void)\
 	argv[argc++] = "-o";
 	argv[argc++] = outfile;
 	
+	if(rpath)
+		argv[argc++] = smprint("-Wl,-rpath,%s", rpath);\
+\
 	// Force global symbols to be exported for dlopen, etc.
 	// NOTE: May not work on OS X or Windows. We'll see.
 	argv[argc++] = "-rdynamic";

具体的には、hostlink関数の内部で、出力ファイル名(-oオプション)が設定された直後に、rpathに関する処理が追加されています。

コアとなるコードの解説

追加された3行のコードは以下の通りです。

if(rpath)
    argv[argc++] = smprint("-Wl,-rpath,%s", rpath);
  1. if(rpath): これは、rpathというグローバル変数またはローカル変数が、共有ライブラリの検索パス情報を持っているかどうかをチェックしています。rpathがNULLや空文字列でない場合に、条件が真となります。つまり、rpathが設定されている場合にのみ、以下の処理が実行されます。
  2. smprint("-Wl,-rpath,%s", rpath): smprintは、Goのリンカ内部で使用される文字列フォーマット関数で、printfのようにフォーマットされた文字列を生成します。ここでは、-Wl,-rpath,というプレフィックスに続けて、rpath変数の内容を埋め込んだ文字列を生成しています。
    • -Wl,: これは、コンパイラドライバ(例: gcc)がリンカにオプションを渡すための標準的なプレフィックスです。
    • -rpath,%s: これは、リンカ(例: GNU ld)が共有ライブラリの検索パスを指定するために認識するオプションです。%sの部分には、rpath変数の値(実際のパス)が挿入されます。
  3. argv[argc++] = ...: 生成された文字列は、argv配列に追加されます。argvは、ホストリンカを呼び出す際のコマンドライン引数を格納する配列です。argc++は、引数の数をインクリメントし、次の引数を格納する位置を指すようにしています。

この変更により、Goのビルドシステムがrpathを設定した場合、その情報がホストリンカに-Wl,-rpath,という適切な形式で渡されるようになり、動的リンクされたGoプログラムが実行時に共有ライブラリを正しく見つけられるようになります。

関連リンク

  • Go言語の公式ドキュメント: https://golang.org/
  • Goのリンカに関する議論(Go issue trackerなど): 関連するissueやCL(Change List)を検索すると、より詳細な背景情報が見つかる可能性があります。

参考にした情報源リンク

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

このコミットは、Go言語のリンカである`cmd/ld`がホストリンカを使用する際に、`-r`オプションを`-rpath`として適切に渡すように修正するものです。これにより、共有ライブラリの検索パスが正しく設定され、実行時の動的リンクの問題が解決されます。

## コミット

commit 8877a2dfee4cd37825f0df2fa7bb53573d04ae5b Author: Ian Lance Taylor iant@golang.org Date: Thu Mar 28 09:37:32 2013 -0700

cmd/ld: when using host linker pass -r option as -rpath

R=golang-dev, daniel.morsing
CC=golang-dev
https://golang.org/cl/8070043

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

[https://github.com/golang/go/commit/8877a2dfee4cd37825f0df2fa7bb53573d04ae5b](https://github.com/golang/go/commit/8877a2dfee4cd37825f0df2fa7bb53573d04ae5b)

## 元コミット内容

cmd/ld: when using host linker pass -r option as -rpath

R=golang-dev, daniel.morsing CC=golang-dev https://golang.org/cl/8070043


## 変更の背景

Go言語のビルドシステムは、Go自身のリンカ(`cmd/ld`)を使用することもあれば、システムにインストールされているホストリンカ(例: `gcc`が内部的に使用する`ld`)を使用することもあります。特にCGO(C言語との相互運用)を使用する場合や、特定のプラットフォームではホストリンカが利用されます。

このコミット以前は、Goのビルドプロセスにおいて、共有ライブラリの検索パスを指定するための`-r`オプションが、ホストリンカに正しく伝達されていませんでした。その結果、ビルドされた実行ファイルが、実行時に必要な共有ライブラリを見つけられず、エラーとなる可能性がありました。

具体的には、Goのリンカが内部的に管理している`rpath`(Run-time search path)情報が、ホストリンカに渡される際に、ホストリンカが期待する形式(`-Wl,-rpath,`)に変換されていなかったことが問題でした。この修正は、この変換を適切に行うことで、動的リンクされたGoプログラムが、実行時に必要な共有ライブラリを正しくロードできるようにすることを目的としています。

## 前提知識の解説

### リンカ (Linker)

リンカは、コンパイラによって生成されたオブジェクトファイル(機械語コードとデータを含むファイル)を結合し、実行可能なプログラムや共有ライブラリを作成するツールです。このプロセスには、未解決のシンボル(関数や変数の参照)を解決し、それらを適切なメモリ位置にマッピングする作業が含まれます。

### 動的リンク (Dynamic Linking) と静的リンク (Static Linking)

*   **静的リンク**: プログラムが必要とするすべてのライブラリコードが、コンパイル時に実行ファイルに直接組み込まれます。これにより、実行ファイルは自己完結型となり、他のライブラリファイルに依存しません。しかし、実行ファイルのサイズが大きくなり、ライブラリの更新があった場合にプログラム全体を再コンパイルする必要があります。
*   **動的リンク**: プログラムが必要とするライブラリコードは、実行ファイルには組み込まれず、実行時にOSによってロードされます。これにより、実行ファイルのサイズが小さくなり、複数のプログラムで同じライブラリを共有できるためメモリ効率が向上します。また、ライブラリの更新があっても、プログラムを再コンパイルせずに新しいライブラリを利用できます。しかし、実行時にライブラリが見つからないとプログラムが起動できないという問題が発生する可能性があります。

### RPATH (Run-time search path)

RPATHは、動的リンクされた実行ファイルが、実行時に共有ライブラリを検索するパスを指定するためのメカニズムです。通常、OSは共有ライブラリを検索するために、標準的なシステムディレクトリ(例: `/lib`, `/usr/lib`)や環境変数(例: `LD_LIBRARY_PATH` on Linux, `DYLD_LIBRARY_PATH` on macOS)を使用します。しかし、RPATHを使用すると、実行ファイル自体に特定の検索パスを埋め込むことができます。これにより、環境変数に依存せずに、アプリケーション固有のライブラリパスを指定することが可能になります。これは、特にアプリケーションが特定のディレクトリ構造に依存している場合や、システム全体に影響を与えずにライブラリの場所を制御したい場合に有用です。

### `cmd/ld`

`cmd/ld`は、Go言語の標準リンカです。Goプログラムのビルドにおいて、Goのコンパイラが生成したオブジェクトファイルをリンクし、実行ファイルを生成する役割を担います。Goのリンカは、Go独自のランタイムやガベージコレクタ、スケジューラなど、Go言語の特性を考慮したリンク処理を行います。

### ホストリンカ

ホストリンカとは、GoのビルドシステムがGo自身のリンカではなく、実行環境(ホストOS)に元々インストールされているリンカ(例: GNU `ld`)を使用する場合のリンカを指します。CGOを使用するGoプログラムは、C言語のコードをコンパイルしてリンクする必要があるため、通常はホストリンカが使用されます。

### `-Wl,option`

`-Wl,option`は、`gcc`や`clang`などのコンパイラドライバが、内部的に呼び出すリンカにオプションを渡すための一般的な構文です。`-Wl,`の後に続く文字列が、リンカに直接渡されます。例えば、`-Wl,-rpath,/path/to/lib`は、リンカに`-rpath,/path/to/lib`というオプションを渡すことを意味します。

## 技術的詳細

このコミットの技術的な核心は、Goのリンカ(`cmd/ld`)がホストリンカを呼び出す際に、`rpath`の情報を正しく`-Wl,-rpath,`形式で渡すようにした点です。

Goのビルドプロセスでは、`rpath`という内部変数が、共有ライブラリの検索パスを保持しています。この`rpath`は、Goのビルド設定や、CGOのコンパイルオプションなどから設定されることがあります。

`src/cmd/ld/lib.c`ファイルは、`cmd/ld`のリンカ処理の一部を担っており、特に`hostlink`関数は、Goのリンカが外部のホストリンカを呼び出す際の引数を構築する役割を持っています。

変更前は、`hostlink`関数内で`rpath`変数が設定されていても、それがホストリンカに渡される`argv`(引数リスト)に追加されていませんでした。そのため、ホストリンカはGoのビルドプロセスが意図した`rpath`情報を認識できず、結果として実行時に共有ライブラリが見つからないという問題が発生していました。

このコミットでは、`hostlink`関数内に以下のコードが追加されました。

```c
    if(rpath)
        argv[argc++] = smprint("-Wl,-rpath,%s", rpath);

このコードは、rpath変数が空でない(つまり、共有ライブラリの検索パスが指定されている)場合に、smprint関数を使用して-Wl,-rpath,%sという形式の文字列を生成し、それをホストリンカに渡す引数リストargvに追加します。%sの部分には、実際のrpathの値が埋め込まれます。

これにより、ホストリンカは-Wl,-rpath,/path/to/your/libsのような形式のオプションを受け取り、そのrpath情報を最終的な実行ファイルに埋め込むことができるようになります。結果として、ビルドされたGoプログラムは、実行時に指定されたパスで共有ライブラリを正しく検索し、ロードできるようになります。

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

変更はsrc/cmd/ld/lib.cファイルに集中しています。

--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -636,6 +636,9 @@ hostlink(void)\
 	argv[argc++] = "-o";
 	argv[argc++] = outfile;
 	
+	if(rpath)
+		argv[argc++] = smprint("-Wl,-rpath,%s", rpath);\
+\
 	// Force global symbols to be exported for dlopen, etc.
 	// NOTE: May not work on OS X or Windows. We'll see.
 	argv[argc++] = "-rdynamic";

具体的には、hostlink関数の内部で、出力ファイル名(-oオプション)が設定された直後に、rpathに関する処理が追加されています。

コアとなるコードの解説

追加された3行のコードは以下の通りです。

if(rpath)
    argv[argc++] = smprint("-Wl,-rpath,%s", rpath);
  1. if(rpath): これは、rpathというグローバル変数またはローカル変数が、共有ライブラリの検索パス情報を持っているかどうかをチェックしています。rpathがNULLや空文字列でない場合に、条件が真となります。つまり、rpathが設定されている場合にのみ、以下の処理が実行されます。
  2. smprint("-Wl,-rpath,%s", rpath): smprintは、Goのリンカ内部で使用される文字列フォーマット関数で、printfのようにフォーマットされた文字列を生成します。ここでは、-Wl,-rpath,というプレフィックスに続けて、rpath変数の内容を埋め込んだ文字列を生成しています。
    • -Wl,: これは、コンパイラドライバ(例: gcc)がリンカにオプションを渡すための標準的なプレフィックスです。
    • -rpath,%s: これは、リンカ(例: GNU ld)が共有ライブラリの検索パスを指定するために認識するオプションです。%sの部分には、rpath変数の値(実際のパス)が挿入されます。
  3. argv[argc++] = ...: 生成された文字列は、argv配列に追加されます。argvは、ホストリンカを呼び出す際のコマンドライン引数を格納する配列です。argc++は、引数の数をインクリメントし、次の引数を格納する位置を指すようにしています。

この変更により、Goのビルドシステムがrpathを設定した場合、その情報がホストリンカに-Wl,-rpath,という適切な形式で渡されるようになり、動的リンクされたGoプログラムが実行時に共有ライブラリを正しく見つけられるようになります。

関連リンク

  • Go言語の公式ドキュメント: https://golang.org/
  • Goのリンカに関する議論(Go issue trackerなど): 関連するissueやCL(Change List)を検索すると、より詳細な背景情報が見つかる可能性があります。

参考にした情報源リンク