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

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

このコミットは、Go言語のリンカ (cmd/ld) におけるELFシステムでのビルド問題を修正するものです。具体的には、ELF実行可能ファイルを生成する際に、Go言語が内部的に使用する.typelinkセクションの名前がセクションヘッダ文字列テーブル (shstrtab) に追加されていなかった問題を解決します。これにより、ELFシステム上でGoプログラムが正しくリンクされ、実行できるようになります。

コミット

commit 2e77bc48aa17a60d0e0902a4cddedf7e1840a0f7
Author: Russ Cox <rsc@golang.org>
Date:   Tue Nov 13 13:12:11 2012 -0500

    cmd/ld: fix build on elf systems
    
    TBR=iant
    CC=golang-dev
    https://golang.org/cl/6843050

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

https://github.com/golang/go/commit/2e77bc48aa17a60d0e0902a4cddedf7e1840a0f7

元コミット内容

cmd/ld: fix build on elf systems

TBR=iant
CC=golang-dev
https://golang.org/cl/6843050

変更の背景

Go言語のプログラムは、コンパイル後にリンカ (cmd/ld) によって実行可能ファイルに変換されます。LinuxなどのUnix系システムでは、実行可能ファイルや共有ライブラリの標準フォーマットとしてELF (Executable and Linkable Format) が広く用いられています。

Goのリンカは、生成するELFファイル内に様々なセクション(コード、データ、シンボル情報など)を配置します。その中には、Goランタイムが型情報やインターフェースの動的な解決のために利用する.typelinkという特殊なセクションも含まれています。

このコミットが作成された時点では、GoのリンカがELFファイルを生成する際に、.typelinkセクション自体は作成されていましたが、そのセクション名(.typelink)がELFファイルのセクションヘッダ文字列テーブル (shstrtab) に登録されていませんでした。

shstrtabは、ELFファイル内のすべてのセクションの名前を格納する重要なテーブルです。このテーブルにセクション名が登録されていないと、リンカやOS、デバッガなどのツールがそのセクションを正しく認識・処理できません。結果として、ELFシステム上でGoプログラムをビルドする際に、リンカが生成する実行可能ファイルが不正な状態となり、ビルドエラーや実行時エラーが発生する可能性がありました。

この修正は、.typelinkセクションがELFシステム上で正しく認識され、Goプログラムが期待通りに動作するために不可欠でした。

前提知識の解説

ELF (Executable and Linkable Format)

ELFは、Unix系オペレーティングシステム(Linux、BSDなど)で広く使用されている、実行可能ファイル、オブジェクトコード、共有ライブラリ、コアダンプなどを格納するための標準ファイル形式です。ELFファイルは、ヘッダ、プログラムヘッダテーブル、セクションヘッダテーブル、そして様々なセクションから構成されます。

  • セクション (Sections): ELFファイル内の論理的なデータブロックで、コード (.text)、初期化済みデータ (.data)、初期化されていないデータ (.bss)、読み取り専用データ (.rodata)、シンボルテーブル (.symtab) など、様々な種類の情報が格納されます。
  • セクションヘッダテーブル (Section Header Table): ELFファイル内の各セクションに関するメタデータ(名前、タイプ、アドレス、サイズ、オフセットなど)を記述するテーブルです。
  • セクションヘッダ文字列テーブル (Section Header String Table, shstrtab): セクションヘッダテーブル内のセクション名が格納されている文字列テーブルです。セクションヘッダテーブルの各エントリは、このshstrtabへのオフセットを持ち、そこからセクション名を取得します。

Go言語のリンカ (cmd/ld)

Go言語のビルドプロセスにおいて、コンパイラが生成したオブジェクトファイル(.oファイル)を結合し、最終的な実行可能ファイルを生成する役割を担うのがリンカです。Goのツールチェインには、各アーキテクチャ(例: 5lはARM、6lはx86-64、8lはx86)に対応するリンカが含まれています。これらのリンカは、Goランタイムの要件を満たすように、特定のセクション(例: .gosymtab, .gcbss, .typelinkなど)を持つ実行可能ファイルを生成します。

.typelinkセクション

.typelinkはGo言語特有のセクションであり、Goのランタイムが型情報やインターフェースの動的なディスパッチ、リフレクションなどを効率的に処理するために必要なデータが格納されています。このセクションは、Goプログラムの実行時に型関連の操作を高速化するために重要な役割を果たします。

技術的詳細

このコミットの技術的な核心は、ELFファイルの構造とGoリンカのセクション管理にあります。

ELFファイルでは、すべてのセクションはセクションヘッダテーブルに記述され、その名前はshstrtabに登録されている必要があります。Goのリンカは、Goプログラムの特性に合わせて様々なカスタムセクションを生成します。.typelinkもその一つです。

問題は、リンカが.typelinkセクションのデータをELFファイル内に正しく配置していたにもかかわらず、そのセクション名である文字列「.typelink」をshstrtabに追加する処理が漏れていた点にありました。

doelf()関数は、GoのリンカがELF形式の実行可能ファイルを生成する際に呼び出される主要な関数です。この関数内で、リンカは必要なセクション名をshstrtabに追加していきます。例えば、.note.gnu.build-id.rodata.gcdata.gcbss.gosymtabといったセクション名は既に追加されていました。しかし、.typelinkだけがこのリストから漏れていました。

この漏れにより、ELFファイルは形式的には有効なものの、.typelinkセクションが「名前のないセクション」として扱われるか、あるいはセクションヘッダテーブルから参照できない状態になっていました。これは、ELFファイルを解析するツール(readelfなど)や、場合によってはOSのローダーが、このセクションを正しく識別できない原因となります。Goランタイムが実行時にこのセクションにアクセスしようとした際に、問題が発生する可能性がありました。

修正は非常にシンプルで、doelf()関数内で他のセクション名と同様に、明示的に.typelinkshstrtabに追加することで、この問題を解決しています。これにより、ELFファイル内のすべてのセクションが正しく名前を持ち、リンカやシステムツールによって適切に処理されるようになります。

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

変更は、src/cmd/5l/asm.csrc/cmd/6l/asm.csrc/cmd/8l/asm.cの3つのファイルにわたって行われています。これらはそれぞれ、ARM、x86-64、x86アーキテクチャ向けのリンカのソースコードです。

各ファイルにおいて、doelf()関数内に以下の行が追加されています。

--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -527,6 +527,7 @@ doelf(void)
  	if(buildinfolen > 0)
  		elfstr[ElfStrNoteBuildInfo] = addstring(shstrtab, ".note.gnu.build-id");
  	addstring(shstrtab, ".rodata");
+	addstring(shstrtab, ".typelink");
  	addstring(shstrtab, ".gcdata");
  	addstring(shstrtab, ".gcbss");
  	addstring(shstrtab, ".gosymtab");

同様の変更がsrc/cmd/6l/asm.csrc/cmd/8l/asm.cにも適用されています。

コアとなるコードの解説

変更の中心は、addstring(shstrtab, ".typelink");という行の追加です。

  • shstrtab: これは、ELFファイルのセクションヘッダ文字列テーブルへの参照です。このテーブルは、ELFファイル内のすべてのセクションの名前を格納するために使用されます。
  • addstring(): この関数は、指定された文字列(この場合は.typelink)をshstrtabに追加し、その文字列がテーブル内で占めるオフセットを返します。このオフセットは、セクションヘッダテーブルのエントリからセクション名を参照するために使用されます。

この一行を追加することで、GoのリンカはELFファイルを生成する際に、.typelinkセクションの名前をshstrtabに明示的に登録するようになります。これにより、ELFファイルが完全に仕様に準拠し、.typelinkセクションが他のセクションと同様に、名前によって正しく識別・処理されるようになります。

この修正は、GoプログラムがELFベースのシステムで安定して動作するために不可欠な、基盤的なリンカの修正と言えます。

関連リンク

参考にした情報源リンク

  • ELF (Executable and Linkable Format) - Wikipedia: https://ja.wikipedia.org/wiki/Executable_and_Linkable_Format
  • Go言語のリンカに関する情報 (一般的なGoのビルドプロセス): https://go.dev/doc/articles/go-command (Goコマンドのドキュメント)
  • Goの内部セクションに関する議論 (例: .typelinkの役割など、より詳細な情報が必要な場合): GoのメーリングリストやIssueトラッカーの過去の議論が参考になる場合がありますが、このコミットの時点では公開されている詳細なドキュメントは少ない可能性があります。