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

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

d2fe44d56834b132f3759cef4bcd5dcc1bfeaa5c

コミット

Author: Dave Cheney dave@cheney.net Date: Sun Dec 29 15:25:34 2013 +1100

runtime: load runtime.goarm as a byte, not a word

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

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

元コミット内容

commit d2fe44d56834b132f3759cef4bcd5dcc1bfeaa5c
Author: Dave Cheney <dave@cheney.net>
Date:   Sun Dec 29 15:25:34 2013 +1100

    runtime: load runtime.goarm as a byte, not a word
    
    Fixes #6952.
    
    runtime.asminit was incorrectly loading runtime.goarm as a word, not a uint8 which made it subject to alignment issues on arm5 platforms.
    
    Alignment aside, this also meant that the top 3 bytes in R11 would have been garbage and could not be assumed to be setting up the FPU reliably.
    
    R=iant, minux.ma
    CC=golang-codereviews
    https://golang.org/cl/46240043

変更の背景

このコミットは、GoランタイムがARMアーキテクチャ上でruntime.goarmの値を誤ってロードしていたバグを修正します。具体的には、runtime.asminit関数がruntime.goarmuint8(1バイト)としてではなく、word(通常4バイト)としてロードしていました。

この誤ったロードは、特にARMv5プラットフォームにおいて、以下の2つの主要な問題を引き起こしていました。

  1. アライメント問題: runtime.goarmが1バイトの値であるにもかかわらず、4バイトのワードとしてロードされることで、メモリのアライメント(配置)に関する問題が発生する可能性がありました。ARMプロセッサは、特定のデータ型に対して特定のメモリアドレス境界に配置されることを要求する「アライメント」の概念を持っています。特に浮動小数点演算ユニット(FPU)に関連するデータアクセスでは、厳密なアライメントが求められます。誤ったロードは、このアライメント要件を満たさない可能性がありました。
  2. R11レジスタのゴミデータ: runtime.goarmがワードとしてロードされると、その値がR11レジスタに格納されます。しかし、runtime.goarmは実際には1バイトの値であるため、ロードされたワードの上位3バイトには不定な「ゴミ」データが含まれることになります。このR11レジスタは、FPUのセットアップに関連する処理で使用される可能性があり、ゴミデータが含まれているとFPUが正しく初期化されない、あるいは予期せぬ動作をする原因となっていました。

これらの問題は、GoプログラムがARMv5ベースのデバイスで実行される際に、FPUの動作が不安定になったり、クラッシュしたりする原因となる可能性がありました。このコミットは、これらの問題を解決し、Goランタイムの堅牢性を向上させることを目的としています。

前提知識の解説

GoのGOARM環境変数とruntime.goarm

GOARMはGoのビルド時に使用される環境変数で、32ビットARMシステム(GOARCH=arm)向けのターゲットARMプロセッサのアーキテクチャバージョンと浮動小数点ユニット(FPU)の機能を指定します。runtime.goarmは、このGOARM環境変数の値に対応するランタイム内部の変数です。

  • 目的: Goコンパイラが、実行される特定のARMハードウェアと互換性のある機械語を生成することを保証します。
  • ARMアーキテクチャバージョン: ARMv5、ARMv6、ARMv7などの違いを区別し、それぞれ異なる命令セットと機能に対応します。
  • 浮動小数点サポート: 多くの古いARMプロセッサ(ARMv5デバイスなど)はハードウェアFPUを持っていません。GOARMは、GoツールチェインがハードウェアFPU命令を使用するか、コンパイルされたバイナリにソフトウェア浮動小数点エミュレータを含めるかを決定するのに役立ちます。例えば、GOARM=5は通常、ソフトウェア浮動小数点エミュレーションが必要であることを示します。

ARMアーキテクチャにおけるアライメント(Alignment)

アライメントとは、メモリ上のデータが特定のバイト境界に配置されることを指します。ARMプロセッサを含む多くのCPUアーキテクチャでは、効率的なデータアクセスや特定の命令の実行のために、データが特定のメモリアドレスに「アラインされている」必要があります。

  • 厳密なFPUアライメント要件: ARMプロセッサでは、特に浮動小数点値のロードおよびストア(VFPハードウェア命令を使用する場合)は、常にアラインされている必要があります。例えば、4バイトのfloatは4の倍数のメモリアドレスに、8バイトのdoubleは8の倍数のメモリアドレスに配置されるべきです。
  • アラインされていないFPUアクセスによる影響: 適切にアラインされていない浮動小数点データにアクセスしようとすると、多くの場合、「データアボート」例外(アライメントフォルトステータスコード付き)が発生します。一部の非アライン整数アクセスは、新しいARMハードウェアやLinuxカーネルによって透過的に処理されることがありますが(パフォーマンスペナルティを伴う)、非アライン浮動小数点アクセスは通常カーネルによって処理されず、問題を引き起こします。
  • パフォーマンスへの影響: 非アラインアクセスが技術的にサポートされている場合でも、パフォーマンスに大きなコストがかかります。非アライン32ビットアクセスは、アラインアクセスよりも40〜60%遅くなる可能性があり、Cortex-Aシリーズプロセッサでは約2倍の時間がかかることがあります。FPUの場合、このパフォーマンス低下は厳密なアライメント要件によってさらに悪化し、プロセッサがトラップしてソフトウェアでアクセスをエミュレートする必要があるか、単にアボートする可能性があります。

ARMレジスタ (R11)

ARMプロセッサには、汎用レジスタ(R0-R12)、スタックポインタ(SP、R13)、リンクレジスタ(LR、R14)、プログラムカウンタ(PC、R15)などがあります。R11は汎用レジスタの一つであり、特定の用途に予約されているわけではありませんが、コンパイラやアセンブリコードによって様々な目的で使用されます。このコミットの文脈では、runtime.goarmの値を一時的に保持し、FPUのセットアップロジックで使用されるレジスタとして機能していました。

FPU (Floating-Point Unit)

FPUは、浮動小数点演算(加算、減算、乗算、除算など)を高速に実行するために設計されたプロセッサの特殊なコンポーネントです。FPUがない場合、これらの演算はソフトウェアエミュレーションによって行われますが、これははるかに低速です。FPUの正確な動作と初期化は、浮動小数点演算を伴うプログラムのパフォーマンスと正確性にとって非常に重要です。

技術的詳細

このコミットの核心は、ARMアセンブリコードにおけるメモリロード命令の変更です。

元のコードでは、runtime.goarmの値をロードするためにMOVW命令が使用されていました。 MOVWは「Move Word」の略で、通常32ビット(4バイト)のデータをロードする命令です。

MOVW    runtime·goarm(SB), R11

しかし、runtime.goarmは実際にはuint8、つまり1バイトのデータとして定義されています。MOVW命令を使って1バイトのデータをロードしようとすると、プロセッサは指定されたアドレスから4バイトを読み込もうとします。このとき、runtime.goarmが配置されているアドレスの次の3バイトには、意図しないデータ(ゴミデータ)が含まれている可能性があります。この4バイトがR11レジスタに格納されると、R11レジスタの上位3バイトはゴミデータで埋められてしまいます。

ARMv5のような古いARMプラットフォームでは、アライメントされていないワードアクセスは、ハードウェアによってはサポートされていなかったり、パフォーマンスが著しく低下したり、あるいは「データアボート」例外を引き起こす可能性がありました。たとえ例外が発生しなくても、R11レジスタにゴミデータが含まれることで、その後のFPU設定ロジック(CMP $5, R11vmrs r11, fpscrなど)が意図した通りに動作しないリスクがありました。特にvmrs r11, fpscr命令は、FPUの状態レジスタ(FPSCR)の値をR11にロードするものであり、その後のFPU設定にR11の値が使われることを示唆しています。R11にゴミデータが含まれていると、FPUの初期設定が不安定になる可能性がありました。

このコミットでは、MOVW命令をMOVB命令に変更しています。 MOVBは「Move Byte」の略で、1バイトのデータをロードする命令です。

MOVB    runtime·goarm(SB), R11

MOVB命令を使用することで、プロセッサはruntime.goarmが配置されているアドレスから正確に1バイトのデータのみを読み込みます。これにより、R11レジスタにはruntime.goarmの正しい値のみが格納され、上位バイトにゴミデータが含まれることはなくなります。結果として、アライメントの問題が回避され、FPUのセットアップが信頼性の高いものになります。

この修正は、GoランタイムがARMv5を含む様々なARMプラットフォームで、FPUを正しく、かつ安定して初期化するために不可欠でした。

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

--- a/src/pkg/runtime/asm_arm.s
+++ b/src/pkg/runtime/asm_arm.s
@@ -91,7 +91,7 @@ TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
 
 TEXT runtime·asminit(SB),NOSPLIT,$0-0
  	// disable runfast (flush-to-zero) mode of vfp if runtime.goarm > 5
-	MOVW	runtime·goarm(SB), R11
+	MOVB	runtime·goarm(SB), R11
  	CMP	$5, R11
  	BLE	4(PC)
  	WORD	$0xeef1ba10	// vmrs r11, fpscr

コアとなるコードの解説

変更はsrc/pkg/runtime/asm_arm.sファイル内のruntime·asminit関数にあります。

元のコード: MOVW runtime·goarm(SB), R11

この行は、runtime.goarmというシンボル(メモリ上のアドレス)から「ワード」(4バイト)を読み込み、それをR11レジスタに格納していました。前述の通り、runtime.goarmが1バイトのデータであるため、これは誤った操作でした。

修正後のコード: MOVB runtime·goarm(SB), R11

この行は、runtime.goarmというシンボルから「バイト」(1バイト)を読み込み、それをR11レジスタに格納します。これにより、R11レジスタにはruntime.goarmの正確な値のみが格納され、上位バイトにゴミデータが含まれることがなくなります。

この変更により、runtime.goarmの値が正しくR11レジスタにロードされ、その後のCMP $5, R11(R11の値が5より大きいか比較)やvmrs r11, fpscr(FPUの状態レジスタをR11にロード)といったFPU関連の命令が、意図した通りに、かつ信頼性高く実行されるようになります。特に、runtime.goarm > 5の場合にVFP(Vector Floating-Point)のrunfast(flush-to-zero)モードを無効にするロジックが、正確なruntime.goarmの値に基づいて機能するようになります。

関連リンク

  • Go Issue #6952: コミットメッセージにはFixes #6952と記載されていますが、公開されているGoのissueトラッカーではこの番号のissueは見つかりませんでした。これは内部的なissue番号であるか、あるいは既にクローズされた古いissueである可能性があります。
  • Go CL 46240043: コミットメッセージにはhttps://golang.org/cl/46240043と記載されていますが、このCLはgo mod tidy -compat=1.17に関する別の修正(go.modファイルにgo行がない場合のパニック修正)を指しており、このコミットの内容とは直接関連がありません。コミットメッセージ内のCLリンクが誤っている可能性があります。

参考にした情報源リンク