[インデックス 17252] ファイルの概要
このコミットは、GoコンパイラとランタイムがARMアーキテクチャ上でCgo(GoとC言語の相互運用機能)を使用する際の互換性問題を解決するために行われました。具体的には、Goツールチェインが想定するARMv5Tアーキテクチャのベースラインと、GCCのデフォルト設定との間の不一致を解消し、BLX
命令のような特定の命令がCgoでコンパイルされたアセンブラコードで正しく使用できるようにします。
コミット
commit 3ec0427a074ccb31e2e4824f27aee9c8fe6de65d
Author: Carl Shapiro <cshapiro@google.com>
Date: Wed Aug 14 15:21:53 2013 -0700
cmd/go, runtime/cgo: explicitly target ARMv5T
The baseline architecture had been left to the GCC configured
default which can be more accomodating than the rest of the Go
toolchain. This prevented instructions used by the 5g compiler,
like BLX, from being used in GCC compiled assembler code.
R=golang-dev, dave, rsc, elias.naur, cshapiro
CC=golang-dev
https://golang.org/cl/12954043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3ec0427a074ccb31e2e4824f27aee9c8fe6de65d
元コミット内容
Goツールチェイン(特に5g
コンパイラ)が使用するBLX
命令のような特定の命令が、GCCでコンパイルされたアセンブラコードで正しく機能しない問題に対処するため、cmd/go
とruntime/cgo
が明示的にARMv5Tアーキテクチャをターゲットにするように変更されました。これまでは、ベースラインアーキテクチャがGCCのデフォルト設定に依存しており、それがGoツールチェインの他の部分よりも寛容であったため、互換性の問題が生じていました。
変更の背景
Goは、その初期から様々なアーキテクチャをサポートしてきましたが、異なるコンパイラやツールチェイン間での互換性を確保することは常に課題でした。特にARMのような多様な命令セットとバージョンを持つアーキテクチャでは、特定の命令の可用性や動作がコンパイラの設定に大きく依存します。
このコミットの背景には、Goの5g
コンパイラ(当時のGoコンパイラの一つで、現在はcmd/compile
に統合されています)が生成するコードと、Cgoを通じて呼び出されるGCCでコンパイルされたC/アセンブラコードとの間の相互運用性の問題がありました。具体的には、5g
コンパイラがBLX
命令を使用する一方で、GCCのデフォルト設定が必ずしもBLX
命令をサポートするアーキテクチャをターゲットにしていなかったため、リンケージエラーや実行時エラーが発生する可能性がありました。
この不一致を解消し、GoプログラムがCgoを介して外部のCコードと確実に連携できるようにするために、Goツールチェインが明示的にARMv5Tアーキテクチャをターゲットとするように変更する必要がありました。これにより、Goコンパイラが想定する命令セットと、Cgoが依存するGCCが生成するコードの命令セットが一致し、安定した動作が保証されます。
前提知識の解説
ARMアーキテクチャと命令セット
ARM(Advanced RISC Machine)は、モバイルデバイスや組み込みシステムで広く使用されているRISC(Reduced Instruction Set Computer)ベースのプロセッサアーキテクチャです。ARMアーキテクチャには、ARM命令セット(32ビット固定長命令)とThumb命令セット(16ビット固定長命令、コードサイズ削減に貢献)の2つの主要な命令セットがあります。
ARMv5Tアーキテクチャ
ARMv5Tは、ARMアーキテクチャのバージョンの一つで、Thumb命令セットをサポートする最初の主要なバージョンです。このバージョンで導入された重要な命令の一つがBLX
命令です。
BLX
命令
BLX
(Branch with Link and Exchange)命令は、ARMv5Tアーキテクチャで導入された命令で、以下の2つの主要な機能を持っています。
- 分岐とリンク:
BL
命令と同様に、指定されたアドレスに分岐し、戻りアドレスをリンクレジスタ(LR
またはR14
)に保存します。 - 命令セットの切り替え:
BLX
命令の最大の特徴は、呼び出し先がARM命令セットとThumb命令セットのどちらで記述されているかに応じて、プロセッサの実行状態(ARM状態またはThumb状態)を自動的に切り替えることができる点です。これは、ターゲットアドレスの最下位ビット(LSB)が0であればARM状態、1であればThumb状態に切り替えることで実現されます。この機能は「インターワーキング(Interworking)」と呼ばれ、異なる命令セットでコンパイルされたコード間でのシームレスな呼び出しを可能にします。
Goの5g
コンパイラ
5g
は、Goの初期のコンパイラの一つで、ARMアーキテクチャをターゲットとしていました。Goのコンパイラは、Go言語のセマンティクスを効率的に実行するために、特定のアーキテクチャ固有の命令を利用することがあります。
Cgo
Cgoは、GoプログラムからC言語の関数を呼び出したり、C言語のコードからGoの関数を呼び出したりするためのGoの機能です。Cgoを使用すると、既存のCライブラリをGoプログラムから利用したり、パフォーマンスが重要な部分をCで記述したりすることができます。Cgoは、GoのABI(Application Binary Interface)とCのABI(通常はAAPCS: ARM Architecture Procedure Call Standard)の間の橋渡しを行います。この橋渡しには、レジスタの使用方法、スタックフレームのレイアウト、引数と戻り値の渡し方など、低レベルの詳細が含まれます。
GCC
GCC(GNU Compiler Collection)は、C、C++、Goなど、多くのプログラミング言語をサポートするフリーのコンパイラシステムです。Cgoを使用する場合、GoプログラムはGCCを使用してCコードをコンパイルし、Goのランタイムとリンクします。
技術的詳細
このコミットの技術的な核心は、GoツールチェインがARMアーキテクチャ上でCgoを使用する際のコンパイラ設定の不一致を解消することにあります。
Goの5g
コンパイラは、ARMv5T以降のアーキテクチャで利用可能なBLX
命令を内部的に使用していました。BLX
命令は、ARMとThumb命令セット間の切り替えを可能にするため、Cgoのような異なる言語間の呼び出しにおいて非常に有用です。しかし、GCCのデフォルト設定が必ずしもARMv5Tをターゲットにしているとは限りませんでした。GCCがより古いARMアーキテクチャ(例えばARMv4Tなど、BLX
命令をサポートしないもの)をデフォルトでターゲットにしている場合、5g
コンパイラが生成したBLX
命令を含むGoのコードと、GCCがコンパイルしたCgoのアセンブラコードとの間でリンケージエラーや実行時エラーが発生する可能性がありました。
この問題を解決するため、コミットでは以下の2つの変更が行われました。
-
src/cmd/go/build.go
の変更:cmd/go
はGoのビルドツールであり、コンパイル時にGCCに渡すアーキテクチャ固有のフラグを決定します。この変更では、ARMアーキテクチャ(GOARCH
がarm
で、GOARM
が5
の場合)に対して、GCCに-march=armv5t
フラグを明示的に渡すようにしました。これにより、GCCはARMv5Tアーキテクチャをターゲットとしてコードを生成するようになり、BLX
命令が正しく認識され、使用できるようになります。-marm
フラグは、ThumbモードではなくARMモードでコードを生成することを保証します。 -
src/pkg/runtime/cgo/gcc_arm.S
の変更:runtime/cgo/gcc_arm.S
は、ARMアーキテクチャにおけるCgoのランタイムアセンブラコードです。このファイルには、GoとCの間で関数呼び出しを行うための低レベルのスタブが含まれています。 変更前は、setmg(m, g)
とfn()
の呼び出しに、mov lr, pc
とmov pc, rX
という命令の組み合わせを使用していました。これは、手動でリンクレジスタを更新し、プログラムカウンタを操作することで関数呼び出しを実現する方法です。 変更後には、これらの呼び出しがblx r5
とblx r4
に置き換えられました。blx
命令を使用することで、より効率的かつ安全に、そして命令セットの切り替えを考慮した関数呼び出しが可能になります。特に、Cgoを介して呼び出されるC関数がThumbモードでコンパイルされている場合でも、BLX
命令が自動的に命令セットを切り替えるため、互換性が向上します。
これらの変更により、Goツールチェイン全体がARMv5Tアーキテクチャに準拠するようになり、BLX
命令の利用が保証され、Cgoを介したGoとCの相互運用性が向上しました。
コアとなるコードの変更箇所
src/cmd/go/build.go
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -1837,7 +1837,7 @@ func (b *builder) gccArchArgs() []string {
case "6":
return []string{"-m64"}
case "5":
- return []string{"-marm"} // not thumb
+ return []string{"-marm", "-march=armv5t"} // not thumb
}
return nil
}
src/pkg/runtime/cgo/gcc_arm.S
--- a/src/pkg/runtime/cgo/gcc_arm.S
+++ b/src/pkg/runtime/cgo/gcc_arm.S
@@ -25,12 +25,8 @@ EXT(crosscall_arm2):
mov r5, r1
mov r0, r2
mov r1, r3
-\t// setmg(m, g)
-\tmov lr, pc
-\tmov pc, r5
-\t// fn()
-\tmov lr, pc
-\tmov pc, r4
+\tblx r5 // setmg(m, g)
+\tblx r4 // fn()
pop {r4, r5, r6, r7, r8, r9, r10, r11, ip, pc}
.globl EXT(__stack_chk_fail_local)
コアとなるコードの解説
src/cmd/go/build.go
の変更点
gccArchArgs()
関数は、Goのビルドプロセスにおいて、GCCに渡すアーキテクチャ固有のコンパイラフラグを生成します。
変更前は、GOARM
が5
の場合(つまりARMv5アーキテクチャをターゲットとする場合)、-marm
フラグのみを返していました。これは、ThumbモードではなくARMモードでコンパイルすることをGCCに指示するものです。
変更後には、-marm
に加えて-march=armv5t
フラグが追加されました。この-march=armv5t
は、GCCに対して明示的にARMv5Tアーキテクチャをターゲットとするように指示します。これにより、GCCはARMv5Tで利用可能な命令(例えばBLX
)を生成できるようになり、Goの5g
コンパイラが想定する命令セットとの互換性が確保されます。
src/pkg/runtime/cgo/gcc_arm.S
の変更点
このファイルは、ARMアーキテクチャにおけるCgoのクロス呼び出し(GoとCの間での関数呼び出し)を処理するアセンブラコードです。crosscall_arm2
というラベルは、Cgoの呼び出しエントリポイントの一つを示しています。
変更前は、setmg(m, g)
とfn()
という2つの関数呼び出しが、以下のような命令シーケンスで行われていました。
mov lr, pc
mov pc, r5
これは、手動でリンクレジスタ(lr
)に現在のプログラムカウンタ(pc
)の値を保存し、その後pc
を目的の関数アドレス(r5
またはr4
に格納されている)に設定することで、関数呼び出しを実現していました。この方法は、基本的な分岐とリンクのメカニズムですが、命令セットの切り替え(ARMとThumbのインターワーキング)を自動的に処理する機能はありません。
変更後には、これらの命令シーケンスがblx r5
とblx r4
に置き換えられました。
blx
命令は、前述の通り、分岐とリンクを行うだけでなく、呼び出し先の命令セットに応じてプロセッサの状態を自動的に切り替えることができます。これにより、Cgoを介して呼び出されるC関数がARMモードまたはThumbモードのどちらでコンパイルされていても、Goのランタイムがより堅牢に連携できるようになります。これは、特にCgoのような異なるコンパイラや言語のABIが混在する環境において、非常に重要な改善です。
関連リンク
- Go言語公式ドキュメント: https://go.dev/
- ARMアーキテクチャリファレンスマニュアル (ARMv5Tに関する情報を含む): https://developer.arm.com/documentation/
- GCC公式ドキュメント: https://gcc.gnu.org/onlinedocs/
参考にした情報源リンク
- ARMv5T Architecture and the
BLX
Instruction: - Go 5g Compiler and ARM Calling Conventions:
- cgo and ARM Calling Convention: