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

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

  • src/pkg/go/build/build.go: GoのビルドプロセスにおけるCGOの有効/無効を制御する設定ファイル。
  • src/pkg/runtime/sys_freebsd_arm.s: FreeBSD/ARMアーキテクチャ向けのGoランタイムのアセンブリコード。特にスレッドローカルストレージ (TLS) の読み取りに関連する部分。

コミット

  • コミットハッシュ: 1bb4f37fcec4b22b663c995b0ff6a19a639d112d
  • 作者: Shenghou Ma minux.ma@gmail.com
  • 日付: Mon Apr 21 00:09:22 2014 -0400
  • コミットメッセージ: runtime, go/build: re-enable cgo on FreeBSD. Fixes #7331.

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

https://github.com/golang/go/commit/1bb4f37fcec4b22b663c995b0ff6a19a639d112d

元コミット内容

runtime, go/build: re-enable cgo on FreeBSD.
Fixes #7331.

LGTM=dave, iant
R=golang-codereviews, dave, gobot, iant
CC=golang-codereviews
https://golang.org/cl/89150043

変更の背景

このコミットは、Go言語のCGO機能がFreeBSDオペレーティングシステムのARMアーキテクチャ環境で一時的に無効化されていた状態を解消し、再度有効化することを目的としています。コミットメッセージにある Fixes #7331 は、以前に報告された問題(おそらくCGOがFreeBSD/ARMで正しく動作しない、またはビルドできないといった問題)がこのコミットによって解決されたことを示唆しています。

CGOのサポートは、特定のプラットフォームやアーキテクチャにおいて、その環境特有のシステムコール、リンカの挙動、そして特にスレッドローカルストレージ (TLS) の実装といった複雑な要因に深く依存します。アセンブリコードの変更内容から判断すると、FreeBSD/ARM環境におけるTLSの読み取り方法に既存の問題があり、それがCGOの適切な動作を妨げていた可能性が高いと考えられます。このコミットは、そのTLS読み取りのメカニズムを修正することで、CGOがこの特定の環境で安定して機能するようにするためのものです。

前提知識の解説

  • CGO: Go言語の重要な機能の一つで、GoプログラムからC言語のコードを呼び出すことを可能にします。これにより、既存のCライブラリ(例:システムライブラリ、グラフィックライブラリなど)をGoアプリケーションで再利用したり、Goでは直接アクセスできない低レベルなOS機能やハードウェア操作を行ったりすることが可能になります。CGOは、GoとCの間のデータ型変換、スタックフレームの管理、スレッドモデルの調整など、両言語間の複雑なインターフェースを橋渡しする役割を担います。

  • FreeBSD: Unix系オペレーティングシステムの一つで、堅牢性、高性能、セキュリティの高さで知られています。サーバー、組み込みシステム、デスクトップなど幅広い用途で利用されています。Go言語は、Linux、macOS、Windowsなどと同様に、FreeBSDも主要なサポート対象プラットフォームとしています。

  • ARMアーキテクチャ: Advanced RISC Machinesの略で、主にモバイルデバイス(スマートフォン、タブレット)、組み込みシステム、IoTデバイス、最近ではサーバーやデスクトップPCにも採用されているCPUアーキテクチャです。低消費電力でありながら高い処理性能を発揮するRISC(Reduced Instruction Set Computer)設計が特徴です。Go言語は、ARMv5、ARMv6、ARMv7、ARM64(ARMv8)など、様々なARMプロセッサをサポートしています。

  • スレッドローカルストレージ (TLS): 各スレッドがそれぞれ独立したデータを保持するためのメモリ領域です。マルチスレッドプログラミングにおいて、グローバル変数や静的変数をスレッドごとに独立させたい場合に利用されます。Go言語のランタイムは、ゴルーチン(Goの軽量スレッド)のスケジューリング、スタック管理、およびCGOを介したCコードとの連携において、TLSを頻繁に利用します。特にCGOを使用する場合、GoランタイムとCライブラリがそれぞれ独自のスレッドモデルを持つことがあり、TLSの正しい管理は両者の協調動作に不可欠です。

  • アセンブリ言語: コンピュータのCPUが直接実行できる機械語に非常に近い低レベルなプログラミング言語です。Goランタイムの特定の低レベルな処理(例:ゴルーチンのコンテキストスイッチ、システムコールへの入り口、TLSへの高速アクセス、特定のハードウェア機能の利用)は、最高のパフォーマンスやOSとの直接的な連携を実現するために、アセンブリ言語で記述されることがよくあります。

技術的詳細

このコミットの主要な技術的変更点は、FreeBSD/ARM環境におけるCGOのサポートを再確立するために、Goのビルド設定とランタイムのアセンブリコードを修正した点にあります。

  1. src/pkg/go/build/build.go の変更: このファイルは、GoのビルドシステムがCGOを有効にするかどうかを決定するための設定を保持しています。cgoEnabled というマップは、"OS/ARCH" の形式でプラットフォームとアーキテクチャの組み合わせをキーとし、そのプラットフォームでCGOがサポートされているかどうかをブール値で示します。 このコミットでは、"freebsd/arm": true, というエントリがこのマップに追加されました。これにより、go build コマンドがFreeBSD上でARMアーキテクチャをターゲットとする際に、CGOを有効にしてビルドプロセスを進めるようになります。これは、GoプログラムがC言語のライブラリをリンクし、CGO機能を利用できるようになるための前提条件です。

  2. src/pkg/runtime/sys_freebsd_arm.s の変更: このファイルは、FreeBSD/ARMアーキテクチャに特化したGoランタイムのアセンブリコードを含んでいます。特に、runtime·read_tls_fallback(SB) という関数が修正されました。この関数は、Goランタイムがスレッドローカルストレージ (TLS) のベースアドレスを読み取るためのフォールバックメカニズムを提供します。

    • 変更前:

      MOVW $0xffff1000, R0
      MOVW (R0), R0
      

      このコードは、固定アドレス 0xffff1000 から値を読み取り、それをTLSポインタとして使用しようとしていました。このような固定アドレスへの依存は、OSのバージョン、リンカの挙動、またはメモリレイアウトの変更によって不安定になる可能性があり、特定の環境でのCGOの動作不良の原因となっていたと考えられます。

    • 変更後:

      WORD $0xee1d0f70 // mrc p15, 0, r0, c13, c0, 3
      RET
      

      WORD $0xee1d0f70 は、ARMアーキテクチャの MRC (Move from Coprocessor to Register) 命令の機械語表現です。この命令は、ARMプロセッサのシステム制御コプロセッサ15 (CP15) からレジスタR0に値を読み込むために使用されます。CP15は、ARMプロセッサのシステムレジスタ(例:TLSベースレジスタ)へのアクセスを管理します。 具体的に、mrc p15, 0, r0, c13, c0, 3 というアセンブリ命令は、ARMのTLSレジスタ(通常はTPIDRURWまたはTPIDRUROレジスタ)からTLSベースアドレスを読み取るための標準的かつ推奨される方法です。この命令を使用することで、OSやリンカの挙動に依存しない、より堅牢で移植性の高いTLSポインタの取得が可能になります。

    • // TODO(minux): this only supports ARMv6K+. というコメントは、この新しいTLS読み取り方法がARMv6K以降のアーキテクチャでのみサポートされることを示唆しています。これは、古いARMv5などのアーキテクチャではこの命令が利用できないか、異なる方法でTLSを扱う必要があることを意味し、このコミットが少なくともARMv6K+のFreeBSD/ARM環境でCGOを有効にするための修正であることを明確にしています。

これらの変更により、FreeBSD/ARM環境でGoランタイムがTLSを正しく初期化およびアクセスできるようになり、CGOを介したC言語コードとの連携が安定して行えるようになりました。

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

diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
index 8a390762dc..766a212562 100644
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -264,6 +264,7 @@ var cgoEnabled = map[string]bool{
 	"dragonfly/amd64": true,
 	"freebsd/386":     true,
 	"freebsd/amd64":   true,
+"freebsd/arm":     true,
 	"linux/386":       true,
 	"linux/amd64":     true,
 	"linux/arm":       true,
diff --git a/src/pkg/runtime/sys_freebsd_arm.s b/src/pkg/runtime/sys_freebsd_arm.s
index 31711de206..3ec95a6518 100644
--- a/src/pkg/runtime/sys_freebsd_arm.s
+++ b/src/pkg/runtime/sys_freebsd_arm.s
@@ -367,6 +367,7 @@ TEXT runtime·casp(SB),NOSPLIT,$0
 TEXT runtime·cas(SB),NOSPLIT,$0
 	B runtime·armcas(SB)
 
+// TODO(minux): this only supports ARMv6K+.
 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
-	MOVW $0xffff1000, R0
-	MOVW (R0), R0
+	WORD $0xee1d0f70 // mrc p15, 0, r0, c13, c0, 3
+	RET

コアとなるコードの解説

  • src/pkg/go/build/build.go の変更:

    • cgoEnabled マップは、GoのビルドシステムがCGOをサポートするOS/アーキテクチャの組み合わせを定義するために使用されます。
    • このコミットでは、このマップに "freebsd/arm": true, という新しいエントリが追加されました。これにより、GoコンパイラはFreeBSD上でARMアーキテクチャをターゲットとする際に、CGOを有効にしてビルドを実行するようになります。これは、GoプログラムがC言語のライブラリをリンクし、CGO機能を利用できるようになるためのビルド時設定です。
  • src/pkg/runtime/sys_freebsd_arm.s の変更:

    • runtime·read_tls_fallback(SB) 関数は、Goランタイムがスレッドローカルストレージ (TLS) のベースアドレスを読み取るためのフォールバックメカニズムを提供するアセンブリ関数です。

    • 変更前:

      MOVW $0xffff1000, R0
      MOVW (R0), R0
      

      このコードは、固定のメモリアドレス 0xffff1000 をTLSポインタの格納場所として直接参照しようとしていました。このようなハードコードされたアドレスは、OSのバージョンアップやメモリレイアウトの変更によって無効になる可能性があり、TLSポインタの取得に失敗する原因となっていました。

    • 変更後:

      WORD $0xee1d0f70 // mrc p15, 0, r0, c13, c0, 3
      RET
      

      WORD $0xee1d0f70 は、ARMプロセッサの MRC (Move from Coprocessor to Register) 命令の機械語表現です。この命令は、ARMアーキテクチャのシステム制御コプロセッサ15 (CP15) から、スレッドIDレジスタ(通常はTPIDRURWまたはTPIDRURO)の値を読み取り、それをR0レジスタに格納します。このレジスタは、現在のスレッドのTLSベースアドレスを保持するためにOSによって使用されます。 // mrc p15, 0, r0, c13, c0, 3 は、この機械語がどのようなアセンブリ命令に対応するかを示すコメントであり、命令の具体的なオペランドを示しています。 RET は、関数からのリターン命令です。

    • // TODO(minux): this only supports ARMv6K+. というコメントは、この新しいTLS読み取り方法がARMv6K以降のARMアーキテクチャでのみ有効であることを示しています。これは、古いARMバージョンではこの命令が利用できないか、異なるTLSアクセス方法が必要になる可能性を指摘しており、今後の改善点または既知の制約を示しています。

これらの変更により、FreeBSD/ARM環境におけるGoランタイムは、より標準的かつ堅牢な方法でTLSベースアドレスを取得できるようになり、CGOを介したC言語コードとの連携が安定して行えるようになりました。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (特に src/pkg/go/build/build.go および src/pkg/runtime/sys_freebsd_arm.s の該当コミット)
  • ARMアーキテクチャのリファレンスマニュアル (MRC命令およびCP15レジスタに関する情報)
  • スレッドローカルストレージ (TLS) の概念に関する一般的なプログラミング資料
  • FreeBSDのシステムプログラミングに関するドキュメント (TLSの実装に関する情報)