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

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

このコミットは、Goコンパイラツールチェーンの一部であるcmd/goにおいて、macOS (Darwin) 環境でのビルド時にGCCリンカオプション-fno-commonをデフォルトで追加する変更を導入しています。これにより、特定のリンカの問題(Issue 3253の一部)が解決されます。

コミット

  • コミットハッシュ: 9b70c70ffb3f42d6f413bbff894621f8f1e4de05
  • 作者: Shenghou Ma minux.ma@gmail.com
  • コミット日時: 2012年3月16日 金曜日 12:05:09 -0400

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

https://github.com/golang/go/commit/9b70c70ffb3f42d6f413bbff894621f8f1e4de05

元コミット内容

cmd/go: add -fno-common by default on Darwin
        Fixes part of issue 3253.
        We still need to support scattered relocations though.

R=golang-dev, bsiegert, rsc, iant
CC=golang-dev
https://golang.org/cl/5822050

変更の背景

この変更は、GoプログラムをmacOS (Darwin) 上でビルドする際に発生していた特定の問題に対処するために行われました。コミットメッセージには「Fixes part of issue 3253」と記載されており、これはGoの内部的な課題追跡システムにおける問題番号を示しています。

当時のmacOSのコンパイラ(特にGCC)と、Goのリンカ(6l/8l、Mach-O形式を扱う)の間には、共通シンボル(common symbols)の扱いに不整合がありました。一部のコンパイラは、未初期化のグローバル変数を常に-fno-commonが設定されているかのように振る舞うことがあり、Goのリンカがこれを前提としていたため、リンカエラーや予期せぬ動作を引き起こす可能性がありました。

具体的には、GoのリンカはMach-O形式のオブジェクトファイルを処理する際に、未初期化のグローバル変数が.bssセクションに明示的に配置されていることを期待していました。しかし、コンパイラがこれらの変数を「共通シンボル」として扱う場合、リンカはそれらを適切に解決できないことがありました。この不整合を解消し、ビルドの安定性を向上させるために、macOS環境でのビルド時に明示的に-fno-commonフラグをGCCに渡すように変更されました。

コミットメッセージの「We still need to support scattered relocations though.」という記述は、この変更が問題3253の「一部」を解決するものであり、まだ「scattered relocations」(分散配置された再配置情報)に関する別の課題が残っていることを示唆しています。

前提知識の解説

1. GCCの-fno-commonフラグ

  • 共通シンボル (Common Symbols): C言語やFortranにおいて、初期化されていないグローバル変数は、デフォルトで「共通シンボル」として扱われることがあります。これは、異なるコンパイル単位(ソースファイル)で同じ名前の未初期化グローバル変数が複数定義されていても、リンカがそれらを単一の定義にマージすることを許可する仕組みです。これにより、メモリを節約したり、柔軟なプログラミングを可能にしたりする利点がありますが、C++のOne Definition Rule (ODR) のような厳格なルールを持つ言語では、予期せぬ動作やバグの原因となることもあります。共通シンボルは、オブジェクトファイルの.commセクションに配置されることがあります。
  • .bssセクション: .bss (Block Started by Symbol) セクションは、オブジェクトファイルおよび実行可能ファイルの一部であり、初期化されていない静的変数およびグローバル変数を保持します。これらの変数は、プログラムの起動時にオペレーティングシステムによってゼロで初期化されます。
  • -fno-commonの役割: GCCの-fno-commonフラグは、コンパイラに対して、初期化されていないグローバル変数を共通シンボルとして扱わず、明示的に.bssセクションに配置するように指示します。これにより、リンカはこれらの変数をより厳密に扱い、複数の定義が存在する場合にエラーを検出できるようになります。Goのビルドプロセスでは、Goのリンカが特定のシンボル配置を期待しているため、このフラグが必要とされました。

2. Mach-OリンカとGoのリンカ (6l/8l)

  • Mach-O (Mach Object): Mach-Oは、macOS、iOS、watchOS、tvOSなどのAppleのオペレーティングシステムで使用される実行可能ファイル、オブジェクトコード、共有ライブラリ、およびコアダンプのファイル形式です。WindowsのPE (Portable Executable) やLinuxのELF (Executable and Linkable Format) に相当します。Mach-Oファイルは、ヘッダ、ロードコマンド、セグメント(テキスト、データ、BSSなど)で構成されます。
  • リンカの役割: リンカは、コンパイラによって生成された複数のオブジェクトファイルとライブラリを結合し、最終的な実行可能ファイルやライブラリを生成するツールです。リンカの主要なタスクには、シンボル解決(異なるオブジェクトファイル間で参照される変数や関数のアドレスを解決する)と、再配置(コード内のアドレス参照を実際のメモリ位置に調整する)があります。
  • Goのリンカ (6l/8l): Go言語には、独自のツールチェーンがあり、その中にはリンカも含まれます。6lはamd64アーキテクチャ(64ビット)用のリンカ、8lは386アーキテクチャ(32ビット)用のリンカを指します。これらのリンカは、Goのオブジェクトファイルを処理し、最終的な実行可能ファイルを生成する役割を担っています。macOS上では、これらのGoリンカがMach-O形式のファイルを生成します。

3. Scattered Relocations (分散再配置)

  • 再配置 (Relocation): 再配置とは、コンパイル時にアドレスが確定できないシンボル(変数や関数の参照)について、リンカが最終的な実行可能ファイル内で正しいメモリアドレスに修正するプロセスです。例えば、ある関数が別のファイルで定義されたグローバル変数を参照する場合、コンパイラはその変数の最終的なアドレスを知りません。リンカがすべてのオブジェクトファイルを結合する際に、この参照を実際のメモリアドレスに「再配置」します。
  • Scattered Relocations: 「分散再配置」という用語は、再配置情報がオブジェクトファイル内で連続的ではなく、散らばって配置されている状態を指す可能性があります。これは、特定のリンカの最適化や、複雑なコード生成パターンによって発生することがあります。コミットメッセージで「We still need to support scattered relocations though.」と述べられていることから、GoのリンカがMach-O形式の分散再配置を完全にサポートすることに、まだ課題が残っていたことが示唆されます。これは、-fno-commonの追加とは別の、より複雑なリンカの挙動に関する問題であったと考えられます。

技術的詳細

このコミットの技術的な核心は、GoのビルドシステムがmacOS上でGCCを呼び出す際に、-fno-commonフラグを自動的に追加するように変更された点にあります。

Goのビルドプロセスでは、Cgo(GoとC/C++コードを連携させるためのメカニズム)を使用する場合や、Goランタイムの一部がCで書かれている場合など、GCCがコンパイルやリンクのために呼び出されることがあります。macOSのGCCコンパイラは、未初期化のグローバル変数を共通シンボルとして扱う傾向があり、これがGoのリンカ(6l/8l)がMach-O形式の実行ファイルを生成する際の期待と異なっていました。

Goのリンカは、未初期化のグローバル変数が.bssセクションに明示的に配置されていることを前提としていました。しかし、GCCがこれらの変数を共通シンボルとして扱うと、リンカはそれらを適切に解決できず、シンボルが見つからない、または重複するなどのリンカエラーが発生する可能性がありました。

-fno-commonフラグをGCCに渡すことで、GCCは未初期化のグローバル変数を共通シンボルとしてではなく、.bssセクションに直接配置するようになります。これにより、Goのリンカが期待する形式でシンボルが提供され、リンカの問題が解消されます。

この変更は、Goのビルドシステムが異なるプラットフォームのコンパイラの挙動の差異を吸収し、一貫したビルド結果を保証するための具体的な対応策の一つです。コミットメッセージにある「Fixes part of issue 3253」は、この問題がより広範なリンカの課題の一部であり、-fno-commonの追加がその解決に向けた一歩であったことを示しています。残りの「scattered relocations」の問題は、リンカのより深いレベルでの再配置処理に関するものであり、このコミットでは対処されていません。

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

変更はsrc/cmd/go/build.goファイル内のgccCmd関数にあります。

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1403,6 +1403,14 @@ func (b *builder) gccCmd(objdir string) []string {
 		        ta = append(a, "-pthread")
 		}
 	}
+
+	// On OS X, some of the compilers behave as if -fno-common
+	// is always set, and the Mach-O linker in 6l/8l assumes this.
+	// See http://golang.org/issue/3253.
+	if goos == "darwin" {
+		a = append(a, "-fno-common")
+	}
+
 	return a
 }

コアとなるコードの解説

変更はsrc/cmd/go/build.goファイルのbuilder構造体のgccCmdメソッド内で行われています。このメソッドは、GoのビルドプロセスにおいてGCCを呼び出す際に使用されるコマンドライン引数を構築する役割を担っています。

追加されたコードブロックは以下の通りです。

	// On OS X, some of the compilers behave as if -fno-common
	// is always set, and the Mach-O linker in 6l/8l assumes this.
	// See http://golang.org/issue/3253.
	if goos == "darwin" {
		a = append(a, "-fno-common")
	}
  • if goos == "darwin": この条件文は、現在のオペレーティングシステムがmacOS(Goではdarwinと識別される)であるかどうかをチェックしています。この変更がmacOSに特化したものであることを示しています。
  • a = append(a, "-fno-common"): goosdarwinである場合、GCCに渡すコマンドライン引数のスライスa-fno-commonフラグを追加しています。これにより、macOS上でのGoのビルド時にGCCが呼び出される際、未初期化のグローバル変数が共通シンボルとしてではなく、.bssセクションに明示的に配置されるようになります。

この変更により、Goのリンカ(6l/8l)がMach-O形式のオブジェクトファイルを処理する際に期待するシンボル配置と、GCCが生成するオブジェクトファイルのシンボル配置との間の不整合が解消され、ビルドの安定性が向上しました。

関連リンク

  • GitHubコミットページ: https://github.com/golang/go/commit/9b70c70ffb3f42d6f413bbff894621f8f1e4de05
  • Go Issue 3253: コミットメッセージに記載されているhttp://golang.org/issue/3253は、当時のGoの課題追跡システムにおける問題番号です。現在のGitHubのGoリポジトリでは、この番号のIssueは別の内容(golang/vscode-goのクラッシュレポートなど)を指しているため、当時の具体的なIssueの内容を直接参照することは難しい可能性があります。これは、GoのIssueトラッカーが時間とともに移行または再編成されたためと考えられます。
  • Go Change List (CL) 5822050: コミットメッセージに記載されているhttps://golang.org/cl/5822050は、Goのコードレビューシステム(Gerritベース)における変更リストのIDです。これは、このコミットがマージされる前のレビュープロセスを示すものです。

参考にした情報源リンク

  • GCC -fno-common flag explanation: https://stackoverflow.com/questions/14332041/what-does-fno-common-do (Stack Overflow)
  • Web search for "golang issue 3253": 検索結果は現在のGoリポジトリの異なるIssueを指しており、当時のIssueの具体的な内容を特定するには至りませんでした。
  • Web search for "golang.org cl 5822050": 検索結果は見つかりませんでした。