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

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

このコミットは、Go言語のリンカである6l (amd64アーキテクチャ用) と 8l (386アーキテクチャ用) において、ELF (Executable and Linkable Format) システムでのビルドを修正するものです。具体的には、ELFバイナリに.noptrdataセクションを追加することで、ポインタを含まないデータ領域の扱いを改善し、ガベージコレクションの効率化と正確性を確保します。

コミット

  • コミットハッシュ: cf52e39ee0e0b1a28a69a67866fea79728335f17
  • 作者: Shenghou Ma minux.ma@gmail.com
  • コミット日時: 2012年2月19日 (日) 13:16:47 -0500

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

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

元コミット内容

6l, 8l: fix build for ELF systems

R=rsc
CC=golang-dev
https://golang.org/cl/5677095

変更の背景

Go言語のランタイムは、ガベージコレクション (GC) を効率的かつ正確に行うために、メモリ上のどの領域にポインタが含まれているかを正確に知る必要があります。従来のELFバイナリでは、初期化されたデータは通常.dataセクションに、初期化されていないデータは.bssセクションに配置されます。しかし、これらのセクションにはポインタを含むデータと含まないデータが混在する可能性があります。

Goのガベージコレクタは、ヒープ上のオブジェクトだけでなく、グローバル変数やスタック上の値もスキャンして到達可能なオブジェクトを特定します。この際、データセクション内にポインタではない値(例えば整数や文字列のバイト列など)がポインタとして誤って解釈されると、ガベージコレクタが誤ったメモリ領域を参照したり、本来解放すべきメモリを解放しなかったりする問題が発生する可能性があります。

このコミットは、ELFシステムにおいて、ポインタを含まないグローバル変数を格納するための専用のセクションである.noptrdataを導入することで、この問題を解決しようとしています。これにより、ガベージコレクタは.noptrdataセクションをスキャンする必要がなくなり、GCの効率が向上し、正確性が保証されます。

前提知識の解説

ELF (Executable and Linkable Format)

ELFは、Unix系オペレーティングシステム(Linux、BSDなど)で広く使用されている実行可能ファイル、オブジェクトファイル、共有ライブラリの標準フォーマットです。ELFファイルは、プログラムのコード、データ、シンボル情報などを構造化して格納します。

主要なセクションには以下のようなものがあります。

  • .text: 実行可能な機械語コードが格納されます。
  • .data: 初期化されたグローバル変数や静的変数が格納されます。
  • .bss: 初期化されていないグローバル変数や静的変数が格納されます。プログラムの起動時にゼロで初期化されます。
  • .rodata: 読み取り専用のデータ(定数など)が格納されます。

Go言語のリンカ (6l, 8l)

Go言語のビルドプロセスでは、コンパイラがGoのソースコードをオブジェクトファイルに変換し、その後リンカがこれらのオブジェクトファイルと必要なライブラリを結合して最終的な実行可能バイナリを生成します。

  • 6l: go tool 6lとして知られ、amd64 (64-bit) アーキテクチャ向けのGoプログラムをリンクするために使用されます。
  • 8l: go tool 8lとして知られ、386 (32-bit) アーキテクチャ向けのGoプログラムをリンクするために使用されます。

これらのリンカは、Goランタイムの特性(特にガベージコレクション)を考慮して、ELFファイル内のセクションを適切に配置する役割を担っています。

Go言語における.noptrdataセクション

Go言語のガベージコレクタは、メモリ上のポインタを追跡することで、到達可能なオブジェクトを特定し、到達不能なオブジェクトを解放します。このプロセスを効率化し、誤ったポインタ解釈を防ぐために、Goは特定のデータセクションを導入しています。

.noptrdataセクションは、Goのランタイムが「ポインタを含まない」と認識しているグローバル変数を格納するために使用されます。例えば、純粋な数値データ、文字列のバイト配列、構造体でポインタフィールドを持たないものなどがここに含まれます。ガベージコレクタは、このセクション内のデータをポインタとしてスキャンする必要がないため、GCのオーバーヘッドを削減し、パフォーマンスを向上させることができます。

技術的詳細

このコミットの技術的詳細としては、GoリンカがELFバイナリを生成する際に、.noptrdataという新しいセクション名を認識し、それをELFファイルのセクションヘッダテーブルに適切に追加するように変更された点にあります。

具体的には、src/cmd/6l/asm.csrc/cmd/8l/asm.cenum定義にElfStrNoPtrDataという新しいエントリが追加され、これがELFセクション名文字列のインデックスとして使用されます。そして、doelf関数内で、このElfStrNoPtrDataに対応する文字列として実際に.noptrdatashstrtab(セクション名文字列テーブル)に追加されます。

これにより、Goコンパイラやリンカは、ポインタを含まないグローバル変数をこの.noptrdataセクションに配置するようになり、ELFバイナリの構造がGoのガベージコレクションの要件に適合するようになります。これは、特にクロスコンパイルや異なるOS/アーキテクチャ間でのGoプログラムの互換性と安定性を高める上で重要な変更です。

この変更は、Goのガベージコレクタがより正確に動作するための基盤を強化し、Goプログラムの実行時パフォーマンスと信頼性を向上させることに貢献します。

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

このコミットによる変更は、src/cmd/6l/asm.csrc/cmd/8l/asm.cの2つのファイルにわたります。両ファイルで同様の変更が行われています。

diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index 121aa8613e..b64a6dabbc 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -95,6 +95,7 @@ enum {
 	ElfStrGnuVersion,
 	ElfStrGnuVersionR,
 	ElfStrNoteNetbsdIdent,
+\tElfStrNoPtrData,
 	NElfStr
 };

@@ -569,6 +570,7 @@ doelf(void)

 	elfstr[ElfStrEmpty] = addstring(shstrtab, "");
 	elfstr[ElfStrText] = addstring(shstrtab, ".text");
+\telfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
 	elfstr[ElfStrData] = addstring(shstrtab, ".data");
 	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
 	if(HEADTYPE == Hnetbsd)
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index 54bda1ac84..27881d8088 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -91,6 +91,7 @@ enum {
 	ElfStrGnuVersion,
 	ElfStrGnuVersionR,
 	ElfStrNoteNetbsdIdent,
+\tElfStrNoPtrData,
 	NElfStr
 };

@@ -526,6 +527,7 @@ doelf(void)

 	elfstr[ElfStrEmpty] = addstring(shstrtab, "");
 	elfstr[ElfStrText] = addstring(shstrtab, ".text");
+\telfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
 	elfstr[ElfStrData] = addstring(shstrtab, ".data");
 	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
 	if(HEADTYPE == Hnetbsd)

コアとなるコードの解説

変更は主に2つの部分から構成されます。

  1. enumへのElfStrNoPtrDataの追加: src/cmd/6l/asm.csrc/cmd/8l/asm.cのそれぞれで、ELFセクション名を表す定数を定義しているenumブロックに、ElfStrNoPtrDataが追加されています。これは、リンカが内部的に.noptrdataセクションを識別するための新しい識別子です。

    enum {
    	// ... 既存の定義 ...
    	ElfStrNoteNetbsdIdent,
    	ElfStrNoPtrData, // <-- 追加された行
    	NElfStr
    };
    
  2. doelf関数内での.noptrdataセクション名の登録: doelf関数は、ELFファイルの生成に関連する処理を行う関数です。この関数内で、elfstr配列(ELFセクション名文字列へのポインタを格納する配列)に、新しく定義されたElfStrNoPtrDataに対応する文字列として実際に.noptrdataが追加されています。addstring(shstrtab, ".noptrdata")は、セクション名文字列テーブル (shstrtab) に文字列.noptrdataを追加し、そのインデックスを返します。

    doelf(void)
    {
    	// ... 既存の処理 ...
    	elfstr[ElfStrEmpty] = addstring(shstrtab, "");
    	elfstr[ElfStrText] = addstring(shstrtab, ".text");
    	elfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata"); // <-- 追加された行
    	elfstr[ElfStrData] = addstring(shstrtab, ".data");
    	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
    	// ... 既存の処理 ...
    }
    

これらの変更により、GoのリンカはELFバイナリを生成する際に、.noptrdataというセクションを認識し、Goコンパイラが生成したポインタを含まないデータをこのセクションに配置できるようになります。これは、Goのガベージコレクションの正確性と効率性をELFシステム上で保証するために不可欠な変更です。

関連リンク

参考にした情報源リンク

  • ELF (Executable and Linkable Format) - Wikipedia: https://ja.wikipedia.org/wiki/Executable_and_Linkable_Format
  • Go言語のガベージコレクションに関するドキュメントやブログ記事 (一般的な情報源として参照)
  • Go言語のリンカのソースコード (一般的な情報源として参照)
  • Goの.noptrdataセクションに関する議論やドキュメント (具体的な情報源として参照)
    • 例: Goのソースコード内のコメントや、Goの設計に関するドキュメントで.noptrdataについて言及されている箇所。
    • Goのガベージコレクションの仕組みに関する記事。

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

このコミットは、Go言語のリンカである6l (amd64アーキテクチャ用) と 8l (386アーキテクチャ用) において、ELF (Executable and Linkable Format) システムでのビルドを修正するものです。具体的には、ELFバイナリに.noptrdataセクションを追加することで、ポインタを含まないデータ領域の扱いを改善し、ガベージコレクションの効率化と正確性を確保します。

コミット

  • コミットハッシュ: cf52e39ee0e0b1a28a69a67866fea79728335f17
  • 作者: Shenghou Ma minux.ma@gmail.com
  • コミット日時: 2012年2月19日 (日) 13:16:47 -0500

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

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

元コミット内容

6l, 8l: fix build for ELF systems

R=rsc
CC=golang-dev
https://golang.org/cl/5677095

変更の背景

Go言語のランタイムは、ガベージコレクション (GC) を効率的かつ正確に行うために、メモリ上のどの領域にポインタが含まれているかを正確に知る必要があります。従来のELFバイナリでは、初期化されたデータは通常.dataセクションに、初期化されていないデータは.bssセクションに配置されます。しかし、これらのセクションにはポインタを含むデータと含まないデータが混在する可能性があります。

Goのガベージコレクタは、ヒープ上のオブジェクトだけでなく、グローバル変数やスタック上の値もスキャンして到達可能なオブジェクトを特定します。この際、データセクション内にポインタではない値(例えば整数や文字列のバイト列など)がポインタとして誤って解釈されると、ガベージコレクタが誤ったメモリ領域を参照したり、本来解放すべきメモリを解放しなかったりする問題が発生する可能性があります。

このコミットは、ELFシステムにおいて、ポインタを含まないグローバル変数を格納するための専用のセクションである.noptrdataを導入することで、この問題を解決しようとしています。これにより、ガベージコレクタは.noptrdataセクションをスキャンする必要がなくなり、GCの効率が向上し、正確性が保証されます。

前提知識の解説

ELF (Executable and Linkable Format)

ELFは、Unix系オペレーティングシステム(Linux、BSDなど)で広く使用されている実行可能ファイル、オブジェクトファイル、共有ライブラリの標準フォーマットです。ELFファイルは、プログラムのコード、データ、シンボル情報などを構造化して格納します。

主要なセクションには以下のようなものがあります。

  • .text: 実行可能な機械語コードが格納されます。
  • .data: 初期化されたグローバル変数や静的変数が格納されます。このセクションにはポインタを含むデータが格納されることがあります。
  • .bss: 初期化されていないグローバル変数や静的変数が格納されます。プログラムの起動時にゼロで初期化されます。
  • .rodata: 読み取り専用のデータ(定数など)が格納されます。

Go言語のリンカ (6l, 8l)

Go言語のビルドプロセスでは、コンパイラがGoのソースコードをオブジェクトファイルに変換し、その後リンカがこれらのオブジェクトファイルと必要なライブラリを結合して最終的な実行可能バイナリを生成します。

  • 6l: go tool 6lとして知られ、amd64 (64-bit) アーキテクチャ向けのGoプログラムをリンクするために使用されます。
  • 8l: go tool 8lとして知られ、386 (32-bit) アーキテクチャ向けのGoプログラムをリンクするために使用されます。

これらのリンカは、Goランタイムの特性(特にガベージコレクション)を考慮して、ELFファイル内のセクションを適切に配置する役割を担っています。

Go言語における.noptrdataセクションとガベージコレクション

Go言語のガベージコレクタは、メモリ上のポインタを追跡することで、到達可能なオブジェクトを特定し、到達不能なオブジェクトを解放します。このプロセスを効率化し、誤ったポインタ解釈を防ぐために、Goは特定のデータセクションを導入しています。

.noptrdataセクションは、Goのランタイムが「ポインタを含まない」と認識しているグローバル変数を格納するために使用されます。例えば、純粋な数値データ、文字列のバイト配列、構造体でポインタフィールドを持たないものなどがここに含まれます。

Goのガベージコレクタは、ヒープ上の動的に割り当てられたメモリを管理します。ガベージコレクタは、ルートオブジェクト(グローバル変数やゴルーチンのスタックなど)からポインタをたどって「生きている」オブジェクトを識別し、マークします。これらのポインタを介して到達できないメモリは「ガベージ」と見なされ、スイープフェーズで回収されます。

.noptrdataセクションは、明示的にポインタを含まないデータが格納されるため、Goのガベージコレクタはヒープメモリを管理するのと同じ方法でこのセクション内のメモリを直接管理したり「ガベージコレクション」したりすることはありません。.noptrdata内のデータは、コンパイルされたプログラムの静的イメージの一部であり、ヒープオブジェクトの動的な割り当てと解放サイクルには関係しません。したがって、未使用メモリの回収という文脈での「ガベージコレクション」は、.noptrdataセクションには適用されません。これにより、ガベージコレクタは.noptrdataセクションをスキャンする必要がなくなり、GCのオーバーヘッドを削減し、パフォーマンスを向上させることができます。

技術的詳細

このコミットの技術的詳細としては、GoリンカがELFバイナリを生成する際に、.noptrdataという新しいセクション名を認識し、それをELFファイルのセクションヘッダテーブルに適切に追加するように変更された点にあります。

具体的には、src/cmd/6l/asm.csrc/cmd/8l/asm.cenum定義にElfStrNoPtrDataという新しいエントリが追加され、これがELFセクション名文字列のインデックスとして使用されます。そして、doelf関数内で、このElfStrNoPtrDataに対応する文字列として実際に.noptrdatashstrtab(セクション名文字列テーブル)に追加されます。

これにより、Goコンパイラやリンカは、ポインタを含まないグローバル変数をこの.noptrdataセクションに配置するようになり、ELFバイナリの構造がGoのガベージコレクションの要件に適合するようになります。これは、特にクロスコンパイルや異なるOS/アーキテクチャ間でのGoプログラムの互換性と安定性を高める上で重要な変更です。

この変更は、Goのガベージコレクタがより正確に動作するための基盤を強化し、Goプログラムの実行時パフォーマンスと信頼性を向上させることに貢献します。

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

このコミットによる変更は、src/cmd/6l/asm.csrc/cmd/8l/asm.cの2つのファイルにわたります。両ファイルで同様の変更が行われています。

diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index 121aa8613e..b64a6dabbc 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -95,6 +95,7 @@ enum {
 	ElfStrGnuVersion,
 	ElfStrGnuVersionR,
 	ElfStrNoteNetbsdIdent,
+\tElfStrNoPtrData,
 	NElfStr
 };

@@ -569,6 +570,7 @@ doelf(void)

 	elfstr[ElfStrEmpty] = addstring(shstrtab, "");
 	elfstr[ElfStrText] = addstring(shstrtab, ".text");
+\telfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
 	elfstr[ElfStrData] = addstring(shstrtab, ".data");
 	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
 	if(HEADTYPE == Hnetbsd)
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index 54bda1ac84..27881d8088 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -91,6 +91,7 @@ enum {
 	ElfStrGnuVersion,
 	ElfStrGnuVersionR,
 	ElfStrNoteNetbsdIdent,
+\tElfStrNoPtrData,
 	NElfStr
 };

@@ -526,6 +527,7 @@ doelf(void)

 	elfstr[ElfStrEmpty] = addstring(shstrtab, "");
 	elfstr[ElfStrText] = addstring(shstrtab, ".text");
+\telfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata");
 	elfstr[ElfStrData] = addstring(shstrtab, ".data");
 	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
 	if(HEADTYPE == Hnetbsd)

コアとなるコードの解説

変更は主に2つの部分から構成されます。

  1. enumへのElfStrNoPtrDataの追加: src/cmd/6l/asm.csrc/cmd/8l/asm.cのそれぞれで、ELFセクション名を表す定数を定義しているenumブロックに、ElfStrNoPtrDataが追加されています。これは、リンカが内部的に.noptrdataセクションを識別するための新しい識別子です。

    enum {
    	// ... 既存の定義 ...
    	ElfStrNoteNetbsdIdent,
    	ElfStrNoPtrData, // <-- 追加された行
    	NElfStr
    };
    
  2. doelf関数内での.noptrdataセクション名の登録: doelf関数は、ELFファイルの生成に関連する処理を行う関数です。この関数内で、elfstr配列(ELFセクション名文字列へのポインタを格納する配列)に、新しく定義されたElfStrNoPtrDataに対応する文字列として実際に.noptrdataが追加されています。addstring(shstrtab, ".noptrdata")は、セクション名文字列テーブル (shstrtab) に文字列.noptrdataを追加し、そのインデックスを返します。

    doelf(void)
    {
    	// ... 既存の処理 ...
    	elfstr[ElfStrEmpty] = addstring(shstrtab, "");
    	elfstr[ElfStrText] = addstring(shstrtab, ".text");
    	elfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata"); // <-- 追加された行
    	elfstr[ElfStrData] = addstring(shstrtab, ".data");
    	elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
    	// ... 既存の処理 ...
    }
    

これらの変更により、GoのリンカはELFバイナリを生成する際に、.noptrdataというセクションを認識し、Goコンパイラが生成したポインタを含まないデータをこのセクションに配置できるようになります。これは、Goのガベージコレクションの正確性と効率性をELFシステム上で保証するために不可欠な変更です。

関連リンク

参考にした情報源リンク