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

[インデックス 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/goruntime/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つの主要な機能を持っています。

  1. 分岐とリンク: BL命令と同様に、指定されたアドレスに分岐し、戻りアドレスをリンクレジスタ(LRまたはR14)に保存します。
  2. 命令セットの切り替え: 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つの変更が行われました。

  1. src/cmd/go/build.goの変更: cmd/goはGoのビルドツールであり、コンパイル時にGCCに渡すアーキテクチャ固有のフラグを決定します。この変更では、ARMアーキテクチャ(GOARCHarmで、GOARM5の場合)に対して、GCCに-march=armv5tフラグを明示的に渡すようにしました。これにより、GCCはARMv5Tアーキテクチャをターゲットとしてコードを生成するようになり、BLX命令が正しく認識され、使用できるようになります。-marmフラグは、ThumbモードではなくARMモードでコードを生成することを保証します。

  2. src/pkg/runtime/cgo/gcc_arm.Sの変更: runtime/cgo/gcc_arm.Sは、ARMアーキテクチャにおけるCgoのランタイムアセンブラコードです。このファイルには、GoとCの間で関数呼び出しを行うための低レベルのスタブが含まれています。 変更前は、setmg(m, g)fn()の呼び出しに、mov lr, pcmov pc, rXという命令の組み合わせを使用していました。これは、手動でリンクレジスタを更新し、プログラムカウンタを操作することで関数呼び出しを実現する方法です。 変更後には、これらの呼び出しがblx r5blx 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に渡すアーキテクチャ固有のコンパイラフラグを生成します。 変更前は、GOARM5の場合(つまり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 r5blx r4に置き換えられました。 blx命令は、前述の通り、分岐とリンクを行うだけでなく、呼び出し先の命令セットに応じてプロセッサの状態を自動的に切り替えることができます。これにより、Cgoを介して呼び出されるC関数がARMモードまたはThumbモードのどちらでコンパイルされていても、Goのランタイムがより堅牢に連携できるようになります。これは、特にCgoのような異なるコンパイラや言語のABIが混在する環境において、非常に重要な改善です。

関連リンク

参考にした情報源リンク