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

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

このコミットは、Go言語のリンカ (cmd/ld) におけるビルドエラーを修正するためのものです。具体的には、ELF (Executable and Linkable Format) ファイルのリンキング処理中に発生する R_*_NONE という特殊な再配置(relocation)タイプを明示的に無視することで、ビルドが成功するように変更が加えられています。コミットメッセージには、この再配置がなぜ使用されているのか不明であると記されており、一時的な対処としての側面が強いことが示唆されています。

コミット

commit 93fac8859c528520142e83d838a664aa37bf267f
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Fri Aug 17 09:11:58 2012 +0800

    cmd/ld: explicitly ignore R_*_NONE relocation to fix build
            I don't know why this relocation is used.
    
    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/6464070

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

https://github.com/golang/go/commit/93fac8859c528520142e83d838a664aa37bf267f

元コミット内容

cmd/ld: explicitly ignore R_*_NONE relocation to fix build I don't know why this relocation is used.

このコミットは、cmd/ld(Go言語のリンカ)において、R_*_NONE という再配置を明示的に無視することでビルドを修正するものです。コミットの作者は、なぜこの再配置が使用されているのか不明であると述べています。

変更の背景

この変更の背景には、Go言語のビルドプロセスにおいて、リンカが処理するELFファイル内で予期せぬ R_*_NONE 再配置が出現し、それが原因でビルドが失敗するという問題がありました。R_*_NONE は通常、何もしないことを意味する再配置タイプですが、リンカがこれを適切に処理できない場合、エラーを引き起こす可能性があります。

コミットメッセージにある「I don't know why this relocation is used.」という記述から、この問題が特定の環境やコンパイルオプション、あるいは生成されるオブジェクトファイルの特性に起因する、比較的稀なケースであった可能性が示唆されます。根本原因の特定が困難であったため、リンカ側でこの再配置を明示的に無視するという、より直接的な解決策が採用されたと考えられます。これにより、ビルドの安定性が確保されました。

前提知識の解説

ELF (Executable and Linkable Format)

ELFは、Unix系オペレーティングシステムで広く使用されている、実行可能ファイル、オブジェクトコード、共有ライブラリ、コアダンプの標準ファイル形式です。プログラムの実行に必要なコード、データ、シンボル、再配置情報などが構造化されて格納されています。

再配置 (Relocation)

再配置とは、リンカがオブジェクトファイルやライブラリを結合して実行可能ファイルを生成する際に、コードやデータ内のアドレス参照を修正するプロセスです。コンパイル時には、関数や変数の最終的なメモリ上のアドレスが確定していないため、仮のアドレスやオフセットが使用されます。リンカは、これらの仮のアドレスを実際のメモリ上のアドレスに「再配置」することで、プログラムが正しく実行されるようにします。

再配置エントリは、どのセクションのどのオフセットにある値を、どのシンボルに基づいて、どのような計算(再配置タイプ)で修正するか、といった情報を含んでいます。

R_*_NONE 再配置

R_*_NONE は、ELFの再配置タイプの一つで、数値としては通常 0 を持ちます。この再配置タイプは、**「何もしない」**ことを意味します。つまり、リンカがこのタイプの再配置エントリに遭遇した場合、対応するアドレスの値を変更する必要がないことを示します。

R_*_NONE が使用されるシナリオとしては、以下のようなものが考えられます。

  • 無視されるべきエントリ: 特定の状況下で、リンカが再配置エントリを生成するものの、実際にはその再配置が不要である場合。
  • デバッグ情報: デバッグ情報の一部として、ダミーの再配置エントリが生成されることがある。
  • リンカの内部処理: リンカが一時的に使用する内部的な再配置エントリで、最終的には無視されるもの。
  • 未参照のシンボル: 未参照のシンボルに対する再配置が、最終的に R_*_NONE に書き換えられる場合。

このコミットのケースでは、何らかの理由でこの R_*_NONE 再配置がリンカの処理を妨げていたため、明示的に無視する処理が追加されました。

技術的詳細

このコミットは、Go言語のリンカのELFファイル処理部分、具体的には src/cmd/ld/ldelf.c に変更を加えています。ldelf.c は、ELF形式のオブジェクトファイルやライブラリを読み込み、その中の再配置情報を処理する役割を担っています。

リンカは、オブジェクトファイルから再配置エントリを読み込み、それぞれの再配置タイプに基づいて適切な処理を行います。通常、再配置エントリは、シンボル情報と再配置タイプを組み合わせた「info」フィールドを持っています。

変更前のコードでは、info フィールドが 0 の場合に特別な処理は行われていませんでした。しかし、何らかの理由で info0 となる R_*_NONE 再配置がリンカの処理フローに問題を引き起こしていたと考えられます。これは、リンカが info0 の再配置を予期しない方法で解釈しようとしたか、あるいはその後の処理で不正なメモリアクセスやロジックエラーが発生したためかもしれません。

このコミットでは、info & 0xffffffff == 0 という条件を追加することで、info フィールドの下位32ビットが 0 である再配置(これは R_*_NONE 再配置に相当します)を検出しています。そして、この条件に合致した場合に continue ステートメントを実行することで、現在の再配置エントリの処理をスキップし、次の再配置エントリへと進むようにしています。

これにより、リンカは問題を引き起こしていた R_*_NONE 再配置を無視し、ビルドプロセスを正常に完了できるようになります。コミットメッセージにあるように、この再配置がなぜ発生するのか、その根本原因は不明なままでしたが、この変更によってビルドの問題は解決されました。これは、問題の症状を直接的に緩和する対処療法的な修正と言えます。

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

--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -658,6 +658,8 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)\n 				tp += 4;\n 			}\n 		}\n+		if(info & 0xffffffff == 0) // R_*_NONE relocation\n+			continue;\n 		if((info >> 32) == 0) { // absolute relocation, don't bother reading the null symbol\n 			rp->sym = S;\n 		} else {\n```

## コアとなるコードの解説

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

```c
		if(info & 0xffffffff == 0) // R_*_NONE relocation
			continue;
  • info: これは、現在の再配置エントリに関する情報(シンボルインデックスと再配置タイプ)を格納する変数です。ELFの再配置エントリでは、通常 r_info フィールドがこれに相当し、下位ビットに再配置タイプ、上位ビットにシンボルインデックスが格納されます。
  • info & 0xffffffff == 0: この条件式は、info 変数の下位32ビットがすべて 0 であるかどうかをチェックしています。
    • 0xffffffff は、32ビットのマスクです。info & 0xffffffff は、info の下位32ビットのみを抽出します。
    • ELFの仕様において、R_*_NONE 再配置タイプは通常 0 の値を持つため、この条件は R_*_NONE 再配置を効果的に識別します。
  • // R_*_NONE relocation: これはコメントで、この条件が R_*_NONE 再配置を検出するためのものであることを示しています。
  • continue;: このステートメントは、現在のループの残りの処理をスキップし、次の再配置エントリの処理へと移ることを指示します。これにより、R_*_NONE 再配置はリンカによって無視され、それ以降の処理が行われなくなります。

この変更により、リンカは R_*_NONE 再配置に遭遇してもエラーを発生させることなく、次の再配置へと進むことができるようになり、ビルドの失敗が回避されます。

関連リンク

参考にした情報源リンク