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

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

このコミットは、Go言語のコマンドラインツールである cmd/go のビルドプロセスを定義する src/cmd/go/build.go ファイルに対する変更です。具体的には、C言語との相互運用を可能にする cgo 機能が、Linux/ARMアーキテクチャ上で適切に動作するようにするための修正が含まれています。build.go は、Goプログラムのコンパイル、リンク、および外部Cライブラリとの連携(cgoの場合)のロジックを管理するGoツールチェインの重要な部分です。

コミット

このコミットは、Shenghou Maによって2012年5月4日に行われました。Go言語の cmd/go ツールにおいて、Linux/ARM環境での cgo サポートを強化することを目的としています。これは、Goのチェンジリスト (CL) 5601044(cgo: Linux/ARMサポート)の一部であり、その第4弾にあたります。

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

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

元コミット内容

commit e7a0a7595a7d895e40c0e067762a85bbe189b644
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Fri May 4 18:29:40 2012 +0800

    cmd/go: cgo for Linux/ARM
            Part 4 of CL 5601044 (cgo: Linux/ARM support)
    
    R=golang-dev, dave, rsc
    CC=golang-dev
    https://golang.org/cl/5989058

変更の背景

この変更の背景には、Go言語がARMアーキテクチャ、特にLinuxオペレーティングシステム上でのサポートを拡大するという目標がありました。cgo はGoプログラムからC言語のコードを呼び出す、またはその逆を行うための重要なメカニズムです。しかし、異なるアーキテクチャやOS環境では、コンパイラやリンカの挙動、ABI (Application Binary Interface) の違いなどにより、特定の調整が必要となることがよくあります。

このコミットは、GoのビルドツールがLinux/ARM環境で cgo を使用する際に、GCC (GNU Compiler Collection) リンカに対して特定のフラグ (-pie) を一時的に適用することで、インポートされたシンボル(関数や変数など)が正確に解決されるようにするためのものです。また、ARMアーキテクチャの特定の命令セット (-marm) を明示的に指定することで、互換性と正しいコード生成を保証しています。これは、Goが様々なプラットフォームでシームレスに動作するための継続的な取り組みの一環です。

前提知識の解説

cgo

cgo はGo言語の機能の一つで、GoプログラムからC言語の関数を呼び出したり、C言語のプログラムからGo言語の関数を呼び出したりすることを可能にします。これにより、既存のCライブラリをGoプロジェクトで再利用したり、パフォーマンスが重要な部分をCで記述したりすることができます。cgo を使用すると、GoツールチェインはCコンパイラ(通常はGCC)を呼び出してCコードをコンパイルし、Goコードとリンクします。

ARMアーキテクチャ

ARM (Advanced RISC Machine) は、モバイルデバイス、組み込みシステム、IoTデバイスなどで広く使用されているRISC (Reduced Instruction Set Computer) ベースのプロセッサアーキテクチャです。低消費電力と高い性能効率が特徴です。ARMプロセッサには、ARMモード(32ビット命令)とThumbモード(16ビット命令、コードサイズ削減が目的)など、複数の命令セットがあります。

Linux/ARM

LinuxオペレーティングシステムがARMアーキテクチャ上で動作する環境を指します。Raspberry Piなどのシングルボードコンピュータや、多くのAndroidデバイスの基盤となっています。

cmd/go

cmd/go はGo言語の公式コマンドラインツールです。go buildgo rungo testgo get など、Go開発者が日常的に使用する様々なコマンドを提供します。このツールは、Goソースコードのコンパイル、リンク、パッケージ管理、テスト実行など、Goプロジェクトのライフサイクル全体を管理します。

gccCmdgccld

src/cmd/go/build.go 内の関数で、GoツールチェインがCコンパイラ(GCC)を呼び出す際に使用されます。

  • gccCmd: GCCのコンパイルオプションを構築します。
  • gccld: GCCのリンカを呼び出して、オブジェクトファイルをリンクします。

-marm-mthumb

GCCコンパイラのオプションで、ARMアーキテクチャの命令セットを指定します。

  • -marm: 32ビットのARM命令セットを使用するようにコンパイラに指示します。これは、より一般的なARM命令セットです。
  • -mthumb: 16ビットのThumb命令セットを使用するようにコンパイラに指示します。Thumb命令はコードサイズを削減できますが、一部の機能やパフォーマンス特性がARM命令とは異なります。このコミットでは、明示的に -marm を使用し、「not thumb」とコメントされていることから、Thumbモードではなく標準のARM命令セットが必要とされていることがわかります。

-pie (Position-Independent Executable)

-pie はGCCリンカのオプションで、生成される実行ファイルが位置独立コード (PIC: Position-Independent Code) を含むようにします。PICは、プログラムがメモリ内の任意のアドレスにロードされても正しく実行できるように設計されたコードです。

  • セキュリティ: ASLR (Address Space Layout Randomization) と組み合わせて、バッファオーバーフロー攻撃などのセキュリティ脆弱性を軽減するのに役立ちます。
  • 共有ライブラリ: 共有ライブラリは通常、PICとしてコンパイルされます。
  • シンボル解決: 動的リンカが実行時にシンボルを解決する際に、特に複雑なリンキングシナリオ(cgoのようにGoとCが混在する場合)で正確なアドレス解決を保証するために重要になることがあります。

このコミットでは、Linux/ARM環境での cgo の中間リンクステップで -pie が一時的に必要とされています。これは、「正確なインポートシンボル (accurate imported sym)」を得るためと説明されており、GoとCのコードが混在するバイナリにおいて、動的リンカが外部シンボル(Cライブラリの関数など)のアドレスを正しく解決するために、位置独立なコードが必要となる特定のリンキング挙動があることを示唆しています。

goosgoarch

Go言語のビルド環境変数を表します。

  • goos: ターゲットオペレーティングシステム(例: linux, windows, darwin)。
  • goarch: ターゲットアーキテクチャ(例: amd64, arm, arm64)。 これらの変数は、クロスコンパイルや特定のプラットフォーム向けビルドの際にGoツールチェインの挙動を制御するために使用されます。

技術的詳細

このコミットは、Linux/ARM環境における cgo のビルドプロセスに二つの主要な技術的調整を加えています。

  1. ARM命令セットの明示的な指定 (-marm): src/cmd/go/build.gogccCmd 関数内で、goarch"arm" の場合に、GCCコンパイラオプションに -marm を追加するロジックが導入されました。これは、GoツールチェインがCコードをコンパイルする際に、ARMプロセッサの標準的な32ビット命令セットを使用することを保証します。ARMアーキテクチャにはThumb命令セットのような代替命令セットも存在しますが、cgo を介してGoとCのコードが連携する際には、特定のABIやリンキングの要件を満たすために、標準のARM命令セットでコンパイルすることが不可欠であったと考えられます。コメントの「not thumb」は、この選択の意図を明確に示しています。

  2. -pie フラグの一時的な適用: src/cmd/go/build.gocgo 関数内で、goarch"arm" かつ goos"linux" の場合に、gccld (GCCリンカ)を呼び出す直前に cgoLDFLAGS (cgoリンカフラグ) に -pie を追加し、gccld の呼び出し直後にそのフラグを削除する処理が追加されました。

    • なぜ -pie が必要か: コミットメッセージには「we need to use -pie for Linux/ARM to get accurate imported sym」とあります。これは、Linux/ARM環境で cgo を使用して生成される中間オブジェクトファイル(dynobj)が、外部からインポートされるシンボル(例えば、Cライブラリの関数)のアドレスを正確に解決するために、位置独立なコードとしてリンクされる必要があることを意味します。動的リンカが実行時にこれらのシンボルを解決する際、特にARMのような特定のアーキテクチャでは、位置独立性がシンボル解決の正確性に寄与する場合があります。これは、アドレス空間のランダム化や、共有ライブラリのロードアドレスが実行ごとに異なる場合に、シンボル参照が正しくオフセットされることを保証するためです。
    • なぜ一時的か: -pie フラグは gccld の呼び出し前に追加され、呼び出し後に削除されます。これは、-pie が最終的なGo実行ファイル全体に適用されるのではなく、cgo が生成する特定の中間動的オブジェクト (dynobj) のリンク時にのみ必要とされることを示しています。最終的なGoプログラムのリンキングには、-pie が不要、あるいは望ましくない場合があるため、このように一時的に適用することで、必要なリンキング挙動を達成しつつ、最終成果物への影響を最小限に抑えています。

これらの変更は、Goの cgo がLinux/ARM環境で堅牢かつ正確に動作するための、低レベルかつプラットフォーム固有のリンキングおよびコンパイルの課題に対処するものです。

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

src/cmd/go/build.go ファイルに以下の変更が加えられました。

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1394,6 +1394,8 @@ func (b *builder) gccCmd(objdir string) []string {
 		a = append(a, "-m32")
 	case "6":
 		a = append(a, "-m64")
+	case "5":
+		a = append(a, "-marm") // not thumb
 	}
 	// gcc-4.5 and beyond require explicit "-pthread" flag
 	// for multithreading with pthread library.
@@ -1513,9 +1515,15 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,\
 		outObj = append(outObj, ofile)
 	}
 	dynobj := obj + "_cgo_.o"
+	if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym
+		cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
+	}
 	if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
 		return nil, nil, err
 	}
+	if goarch == "arm" && goos == "linux" { // but we don't need -pie for normal cgo programs
+		cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
+	}
 
 	if _, ok := buildToolchain.(gccgcToolchain); ok {
 		// we don't use dynimport when using gccgo.

コアとなるコードの解説

gccCmd 関数内の変更

 	case "6":
 		a = append(a, "-m64")
+	case "5":
+		a = append(a, "-marm") // not thumb
 	}

この部分では、goarch の値に基づいてGCCコンパイラに渡すアーキテクチャ固有のフラグを追加しています。case "5"goarch == "arm" に対応します。つまり、ターゲットアーキテクチャがARMの場合、GCCに対して -marm フラグを追加しています。これにより、GCCは32ビットのARM命令セットでCコードをコンパイルするようになります。コメントの // not thumb は、Thumb命令セットではなく、標準のARM命令セットを使用する意図を明確に示しています。これは、cgo が正しく機能するために特定のABI(Application Binary Interface)に準拠したコードが必要であることを示唆しています。

cgo 関数内の変更

 	dynobj := obj + "_cgo_.o"
+	if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym
+		cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
+	}
 	if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
 		return nil, nil, err
 	}
+	if goarch == "arm" && goos == "linux" { // but we don't need -pie for normal cgo programs
+		cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
+	}

このブロックは、cgo が生成する中間オブジェクトファイル (_cgo_.o) をリンクする際の挙動を制御します。

  • if goarch == "arm" && goos == "linux": この条件は、ターゲットがLinux上のARMアーキテクチャである場合にのみ、以下のロジックが適用されることを意味します。
  • cgoLDFLAGS = append(cgoLDFLAGS, "-pie"): b.gccld 関数(GCCリンカを呼び出す)の直前に、リンカフラグのリスト cgoLDFLAGS-pie を追加しています。これにより、_cgo_.o ファイルが位置独立実行可能ファイルとしてリンクされます。コメントにあるように、これは「正確なインポートシンボル (accurate imported sym)」を得るために必要です。
  • if err := b.gccld(...): ここで実際にGCCリンカが呼び出され、_cgo_.o がリンクされます。
  • cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]: b.gccld の呼び出しが成功した後、追加された -pie フラグを cgoLDFLAGS から削除しています。これは、-pie がこの特定の中間リンクステップにのみ必要であり、その後のGoプログラム全体の最終リンクには不要であることを示しています。コメントの「but we don't need -pie for normal cgo programs」がこの意図を補強しています。

これらの変更により、GoツールチェインはLinux/ARM環境で cgo を使用する際に、GCCコンパイラとリンカに対して適切なオプションを渡し、クロス言語リンキングにおけるシンボル解決の課題を克服し、安定した動作を保証しています。

関連リンク

参考にした情報源リンク

  • Go言語公式ドキュメント: https://go.dev/doc/
  • GCC (GNU Compiler Collection) ドキュメント: https://gcc.gnu.org/onlinedocs/
  • ARMアーキテクチャリファレンスマニュアル (ARM Holdings): https://developer.arm.com/documentation/
  • Position-Independent Code (PIC) および Position-Independent Executable (PIE) に関する情報 (Linux man pages, GNU Binutils documentationなど)# [インデックス 13027] ファイルの概要

このコミットは、Go言語のコマンドラインツールである cmd/go のビルドプロセスを定義する src/cmd/go/build.go ファイルに対する変更です。具体的には、C言語との相互運用を可能にする cgo 機能が、Linux/ARMアーキテクチャ上で適切に動作するようにするための修正が含まれています。build.go は、Goプログラムのコンパイル、リンク、および外部Cライブラリとの連携(cgoの場合)のロジックを管理するGoツールチェインの重要な部分です。

コミット

このコミットは、Shenghou Maによって2012年5月4日に行われました。Go言語の cmd/go ツールにおいて、Linux/ARM環境での cgo サポートを強化することを目的としています。これは、Goのチェンジリスト (CL) 5601044(cgo: Linux/ARMサポート)の一部であり、その第4弾にあたります。

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

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

元コミット内容

commit e7a0a7595a7d895e40c0e067762a85bbe189b644
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Fri May 4 18:29:40 2012 +0800

    cmd/go: cgo for Linux/ARM
            Part 4 of CL 5601044 (cgo: Linux/ARM support)
    
    R=golang-dev, dave, rsc
    CC=golang-dev
    https://golang.org/cl/5989058

変更の背景

この変更の背景には、Go言語がARMアーキテクチャ、特にLinuxオペレーティングシステム上でのサポートを拡大するという目標がありました。cgo はGoプログラムからC言語のコードを呼び出す、またはその逆を行うための重要なメカニズムです。しかし、異なるアーキテクチャやOS環境では、コンパイラやリンカの挙動、ABI (Application Binary Interface) の違いなどにより、特定の調整が必要となることがよくあります。

このコミットは、GoのビルドツールがLinux/ARM環境で cgo を使用する際に、GCC (GNU Compiler Collection) リンカに対して特定のフラグ (-pie) を一時的に適用することで、インポートされたシンボル(関数や変数など)が正確に解決されるようにするためのものです。また、ARMアーキテクチャの特定の命令セット (-marm) を明示的に指定することで、互換性と正しいコード生成を保証しています。これは、Goが様々なプラットフォームでシームレスに動作するための継続的な取り組みの一環です。

前提知識の解説

cgo

cgo はGo言語の機能の一つで、GoプログラムからC言語の関数を呼び出したり、C言語のプログラムからGo言語の関数を呼び出したりすることを可能にします。これにより、既存のCライブラリをGoプロジェクトで再利用したり、パフォーマンスが重要な部分をCで記述したりすることができます。cgo を使用すると、GoツールチェインはCコンパイラ(通常はGCC)を呼び出してCコードをコンパイルし、Goコードとリンクします。

ARMアーキテクチャ

ARM (Advanced RISC Machine) は、モバイルデバイス、組み込みシステム、IoTデバイスなどで広く使用されているRISC (Reduced Instruction Set Computer) ベースのプロセッサアーキテクチャです。低消費電力と高い性能効率が特徴です。ARMプロセッサには、ARMモード(32ビット命令)とThumbモード(16ビット命令、コードサイズ削減が目的)など、複数の命令セットがあります。

Linux/ARM

LinuxオペレーティングシステムがARMアーキテクチャ上で動作する環境を指します。Raspberry Piなどのシングルボードコンピュータや、多くのAndroidデバイスの基盤となっています。

cmd/go

cmd/go はGo言語の公式コマンドラインツールです。go buildgo rungo testgo get など、Go開発者が日常的に使用する様々なコマンドを提供します。このツールは、Goソースコードのコンパイル、リンク、パッケージ管理、テスト実行など、Goプロジェクトのライフサイクル全体を管理します。

gccCmdgccld

src/cmd/go/build.go 内の関数で、GoツールチェインがCコンパイラ(GCC)を呼び出す際に使用されます。

  • gccCmd: GCCのコンパイルオプションを構築します。
  • gccld: GCCのリンカを呼び出して、オブジェクトファイルをリンクします。

-marm-mthumb

GCCコンパイラのオプションで、ARMアーキテクチャの命令セットを指定します。

  • -marm: 32ビットのARM命令セットを使用するようにコンパイラに指示します。これは、より一般的なARM命令セットです。
  • -mthumb: 16ビットのThumb命令セットを使用するようにコンパイラに指示します。Thumb命令はコードサイズを削減できますが、一部の機能やパフォーマンス特性がARM命令とは異なります。このコミットでは、明示的に -marm を使用し、「not thumb」とコメントされていることから、Thumbモードではなく標準のARM命令セットが必要とされていることがわかります。

-pie (Position-Independent Executable)

-pie はGCCリンカのオプションで、生成される実行ファイルが位置独立コード (PIC: Position-Independent Code) を含むようにします。PICは、プログラムがメモリ内の任意のアドレスにロードされても正しく実行できるように設計されたコードです。

  • セキュリティ: ASLR (Address Space Layout Randomization) と組み合わせて、バッファオーバーフロー攻撃などのセキュリティ脆弱性を軽減するのに役立ちます。
  • 共有ライブラリ: 共有ライブラリは通常、PICとしてコンパイルされます。
  • シンボル解決: 動的リンカが実行時にシンボルを解決する際に、特に複雑なリンキングシナリオ(cgoのようにGoとCが混在する場合)で正確なアドレス解決を保証するために重要になることがあります。

このコミットでは、Linux/ARM環境での cgo の中間リンクステップで -pie が一時的に必要とされています。これは、「正確なインポートシンボル (accurate imported sym)」を得るためと説明されており、GoとCのコードが混在するバイナリにおいて、動的リンカが外部シンボル(Cライブラリの関数など)のアドレスを正しく解決するために、位置独立なコードが必要となる特定のリンキング挙動があることを示唆しています。

goosgoarch

Go言語のビルド環境変数を表します。

  • goos: ターゲットオペレーティングシステム(例: linux, windows, darwin)。
  • goarch: ターゲットアーキテクチャ(例: amd64, arm, arm64)。 これらの変数は、クロスコンパイルや特定のプラットフォーム向けビルドの際にGoツールチェインの挙動を制御するために使用されます。

技術的詳細

このコミットは、Linux/ARM環境における cgo のビルドプロセスに二つの主要な技術的調整を加えています。

  1. ARM命令セットの明示的な指定 (-marm): src/cmd/go/build.gogccCmd 関数内で、goarch"arm" の場合に、GCCコンパイラオプションに -marm を追加するロジックが導入されました。これは、GoツールチェインがCコードをコンパイルする際に、ARMプロセッサの標準的な32ビット命令セットを使用することを保証します。ARMアーキテクチャにはThumb命令セットのような代替命令セットも存在しますが、cgo を介してGoとCのコードが連携する際には、特定のABIやリンキングの要件を満たすために、標準のARM命令セットでコンパイルすることが不可欠であったと考えられます。コメントの「not thumb」は、この選択の意図を明確に示しています。

  2. -pie フラグの一時的な適用: src/cmd/go/build.gocgo 関数内で、goarch"arm" かつ goos"linux" の場合に、gccld (GCCリンカ)を呼び出す直前に cgoLDFLAGS (cgoリンカフラグ) に -pie を追加し、gccld の呼び出し直後にそのフラグを削除する処理が追加されました。

    • なぜ -pie が必要か: コミットメッセージには「we need to use -pie for Linux/ARM to get accurate imported sym」とあります。これは、Linux/ARM環境で cgo を使用して生成される中間オブジェクトファイル(dynobj)が、外部からインポートされるシンボル(例えば、Cライブラリの関数)のアドレスを正確に解決するために、位置独立なコードとしてリンクされる必要があることを意味します。動的リンカが実行時にこれらのシンボルを解決する際、特にARMのような特定のアーキテクチャでは、位置独立性がシンボル解決の正確性に寄与する場合があります。これは、アドレス空間のランダム化や、共有ライブラリのロードアドレスが実行ごとに異なる場合に、シンボル参照が正しくオフセットされることを保証するためです。
    • なぜ一時的か: -pie フラグは gccld の呼び出し前に追加され、呼び出し後に削除されます。これは、-pie が最終的なGo実行ファイル全体に適用されるのではなく、cgo が生成する特定の中間動的オブジェクト (dynobj) のリンク時にのみ必要とされることを示しています。最終的なGoプログラムのリンキングには、-pie が不要、あるいは望ましくない場合があるため、このように一時的に適用することで、必要なリンキング挙動を達成しつつ、最終成果物への影響を最小限に抑えています。

これらの変更は、Goの cgo がLinux/ARM環境で堅牢かつ正確に動作するための、低レベルかつプラットフォーム固有のリンキングおよびコンパイルの課題に対処するものです。

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

src/cmd/go/build.go ファイルに以下の変更が加えられました。

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1394,6 +1394,8 @@ func (b *builder) gccCmd(objdir string) []string {
 		a = append(a, "-m32")
 	case "6":
 		a = append(a, "-m64")
+	case "5":
+		a = append(a, "-marm") // not thumb
 	}
 	// gcc-4.5 and beyond require explicit "-pthread" flag
 	// for multithreading with pthread library.
@@ -1513,9 +1515,15 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,\
 		outObj = append(outObj, ofile)
 	}
 	dynobj := obj + "_cgo_.o"
+	if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym
+		cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
+	}
 	if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
 		return nil, nil, err
 	}
+	if goarch == "arm" && goos == "linux" { // but we don't need -pie for normal cgo programs
+		cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
+	}
 
 	if _, ok := buildToolchain.(gccgcToolchain); ok {
 		// we don't use dynimport when using gccgo.

コアとなるコードの解説

gccCmd 関数内の変更

 	case "6":
 		a = append(a, "-m64")
+	case "5":
+		a = append(a, "-marm") // not thumb
 	}

この部分では、goarch の値に基づいてGCCコンパイラに渡すアーキテクチャ固有のフラグを追加しています。case "5"goarch == "arm" に対応します。つまり、ターゲットアーキテクチャがARMの場合、GCCに対して -marm フラグを追加しています。これにより、GCCは32ビットのARM命令セットでCコードをコンパイルするようになります。コメントの // not thumb は、Thumb命令セットではなく、標準のARM命令セットを使用する意図を明確に示しています。これは、cgo が正しく機能するために特定のABI(Application Binary Interface)に準拠したコードが必要であることを示唆しています。

cgo 関数内の変更

 	dynobj := obj + "_cgo_.o"
+	if goarch == "arm" && goos == "linux" { // we need to use -pie for Linux/ARM to get accurate imported sym
+		cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
+	}
 	if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
 		return nil, nil, err
 	}
+	if goarch == "arm" && goos == "linux" { // but we don't need -pie for normal cgo programs
+		cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
+	}

このブロックは、cgo が生成する中間オブジェクトファイル (_cgo_.o) をリンクする際の挙動を制御します。

  • if goarch == "arm" && goos == "linux": この条件は、ターゲットがLinux上のARMアーキテクチャである場合にのみ、以下のロジックが適用されることを意味します。
  • cgoLDFLAGS = append(cgoLDFLAGS, "-pie"): b.gccld 関数(GCCリンカを呼び出す)の直前に、リンカフラグのリスト cgoLDFLAGS-pie を追加しています。これにより、_cgo_.o ファイルが位置独立実行可能ファイルとしてリンクされます。コメントにあるように、これは「正確なインポートシンボル (accurate imported sym)」を得るために必要です。
  • if err := b.gccld(...): ここで実際にGCCリンカが呼び出され、_cgo_.o がリンクされます。
  • cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]: b.gccld の呼び出しが成功した後、追加された -pie フラグを cgoLDFLAGS から削除しています。これは、-pie がこの特定の中間リンクステップにのみ必要であり、その後のGoプログラム全体の最終リンクには不要であることを示しています。コメントの「but we don't need -pie for normal cgo programs」がこの意図を補強しています。

これらの変更により、GoツールチェインはLinux/ARM環境で cgo を使用する際に、GCCコンパイラとリンカに対して適切なオプションを渡し、クロス言語リンキングにおけるシンボル解決の課題を克服し、安定した動作を保証しています。

関連リンク

参考にした情報源リンク