[インデックス 12657] ファイルの概要
このコミットは、Go言語のランタイムにおけるARMアーキテクチャ向けのビルドに関する修正です。具体的には、src/pkg/runtime/asm_arm.s
ファイル内のアセンブリコードが変更されています。
コミット
- コミットハッシュ:
bd6404a4cc90aec9c9599ae97cd244dc09088588
- 作者: Russ Cox rsc@golang.org
- 日付: 2012年3月15日 木曜日 17:40:17 -0400
- コミットメッセージ:
runtime: fix arm build TBR=golang-dev CC=golang-dev https://golang.org/cl/5832047
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/bd6404a4cc90aec9c9599ae97cd244dc09088588
元コミット内容
runtime: fix arm build
TBR=golang-dev
CC=golang-dev
https://golang.org/cl/5832047
変更の背景
このコミットは、Go言語のランタイムがARMアーキテクチャ上で正しくビルドされない問題を修正するために行われました。Go言語はクロスプラットフォーム対応を目指しており、ARMのような異なるCPUアーキテクチャ上でも安定して動作する必要があります。ビルドエラーは、特定のアーキテクチャ向けのアセンブリコードがそのアーキテクチャの命令セットやアセンブラの挙動と合致していない場合に発生します。このケースでは、MOVL
命令の使用がARMビルドの問題を引き起こしていたと考えられます。
前提知識の解説
ARMアセンブリ言語
ARMアセンブリ言語は、ARMアーキテクチャのプロセッサが直接実行できる機械語命令を人間が読める形式で記述したものです。低レベルのプログラミングや、OSのカーネル、組み込みシステム、高性能なライブラリなどで使用されます。レジスタ、メモリ操作、分岐命令など、CPUの基本的な操作を直接制御します。
MOVW
とMOVL
命令の違い (ARMアセンブリ)
ARMアセンブリには、値をレジスタに移動させるためのいくつかの命令があります。このコミットで焦点となっているのは、MOVW
とMOVL
です。
-
MOVW
(Move Wide):- これは具体的なARM命令であり、16ビットの即値(immediate value)を下位16ビットにロードし、上位16ビットをゼロクリアして32ビットレジスタに格納します。
- 通常、
MOVT
(Move Top) 命令と組み合わせて使用され、完全な32ビットの即値をレジスタにロードします。MOVW
で下位16ビットをロードした後、MOVT
で上位16ビットをロードし、下位ビットには影響を与えません。
例:
MOVW R0, #0x1234 ; R0 は 0x00001234 になる MOVT R0, #0x5678 ; R0 は 0x56781234 になる (上位16ビットが更新され、下位16ビットは変更なし)
-
MOVL
(Move Literal / Pseudo-instruction):- これは通常、ARMアセンブラが提供する擬似命令 (pseudo-instruction) です。つまり、単一の直接的な機械語命令ではなく、プログラマの便宜のために提供されるものです。アセンブラは
MOVL
を1つ以上の実際の機械語命令に変換します。 - その主な役割は、32ビットまたは64ビットの即値、あるいはアドレス(PC相対アドレスや外部アドレスなど)をレジスタにロードすることです。これは、即値が単一の
MOV
命令に直接エンコードするには大きすぎる場合に特に役立ちます。 - アセンブラは、32ビット値の場合、
MOVW
とMOVT
のペアなど、最も効率的な命令シーケンスを自動的に決定して展開します。
例:
MOVL R0, #0x12345678 ; アセンブラはこれを以下のようなシーケンスに変換する: ; MOVW R0, #0x5678 ; MOVT R0, #0x1234
- これは通常、ARMアセンブラが提供する擬似命令 (pseudo-instruction) です。つまり、単一の直接的な機械語命令ではなく、プログラマの便宜のために提供されるものです。アセンブラは
重要な違い: MOVW
は具体的な命令であり、レジスタの下位16ビットをロードし、上位16ビットをゼロクリアします。一方、MOVL
は擬似命令であり、アセンブラが適切な命令シーケンス(多くの場合MOVW
とMOVT
の組み合わせ)に展開して、指定された値をレジスタ全体にロードします。
技術的詳細
このコミットは、GoランタイムのARMアセンブリコードにおけるruntime·stackguard
関数内の命令の誤用を修正しています。
runtime·stackguard
関数は、Goのランタイムにおいてスタックの境界チェックに関連する重要な役割を担っています。スタックオーバーフローを防ぐために、現在のスタックポインタ(R13
レジスタに格納されていることが多い)と、スタックガード(g_stackguard(g)
、現在のgoroutineのスタックガード値)を比較する必要があります。
元のコードでは、これらの値をレジスタにロードするためにMOVL
命令を使用していました。しかし、MOVL
は擬似命令であり、アセンブラがどのように展開するかはコンテキストに依存します。特に、MOVL
が単一のMOV
命令に展開される場合、それは32ビット値を完全にロードするのではなく、特定のビットパターンをロードする可能性があります。
この問題は、MOVL
がR13
(スタックポインタ)やg_stackguard(g)
のような32ビットの完全なアドレスまたは値をロードする際に、意図しない挙動を引き起こした可能性が考えられます。特に、MOVW
が下位16ビットをロードし、上位16ビットをゼロクリアするという特性を考えると、もしMOVL
が内部的にMOVW
に展開され、かつMOVT
がそれに続かない場合、レジスタの上位ビットが意図せずゼロになってしまい、スタックポインタやスタックガードの値が正しく比較されなくなる可能性があります。
この修正では、MOVL
をMOVW
に置き換えることで、この問題を解決しています。MOVW
は16ビットの即値をロードする命令ですが、このコンテキストでは、R13
やg_stackguard(g)
が指すアドレスや値が、MOVW
で処理できる範囲内であったか、あるいはアセンブラがMOVW
をより適切に処理するようになったか、またはこの特定の場所では上位ビットがゼロクリアされても問題ない(例えば、比較対象が下位16ビットのみで十分な場合や、後続の命令で上位ビットが適切に設定される場合)といった理由が考えられます。
しかし、一般的には32ビットレジスタに完全な32ビット値をロードする際にはMOVW
とMOVT
のペアを使用するのが一般的です。このコミットがMOVW
のみに変更していることから、この特定のruntime·stackguard
関数内のMOVL
の使用が、ARMビルドにおいて予期せぬレジスタ値の破損を引き起こし、MOVW
にすることでその問題が回避されたと推測されます。これは、アセンブラの特定のバージョンや、GoのランタイムがARM上でどのようにスタックを管理しているかという詳細に依存する可能性があります。
コアとなるコードの変更箇所
diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s
index 9c36ba0d69..423fda7a0c 100644
--- a/src/pkg/runtime/asm_arm.s
+++ b/src/pkg/runtime/asm_arm.s
@@ -315,8 +315,8 @@ casfail:
RET
TEXT runtime·stackguard(SB),7,$0
- MOVL R13, R1
- MOVL g_stackguard(g), R2
- MOVL R1, sp+0(FP)
- MOVL R2, limit+4(FP)
+ MOVW R13, R1
+ MOVW g_stackguard(g), R2
+ MOVW R1, sp+0(FP)
+ MOVW R2, limit+4(FP)
RET
コアとなるコードの解説
変更されたのは、src/pkg/runtime/asm_arm.s
ファイル内の runtime·stackguard
関数です。
元のコード:
TEXT runtime·stackguard(SB),7,$0
MOVL R13, R1
MOVL g_stackguard(g), R2
MOVL R1, sp+0(FP)
MOVL R2, limit+4(FP)
RET
修正後のコード:
TEXT runtime·stackguard(SB),7,$0
MOVW R13, R1
MOVW g_stackguard(g), R2
MOVW R1, sp+0(FP)
MOVW R2, limit+4(FP)
RET
この変更は、MOVL
命令をすべてMOVW
命令に置き換えています。
-
MOVL R13, R1
からMOVW R13, R1
:R13
は通常、スタックポインタ(SP)レジスタとして使用されます。この命令は、スタックポインタの値をR1
レジスタに移動しようとしています。MOVL
からMOVW
への変更は、R13
の値をR1
にロードする際の挙動を修正します。これにより、R1
にスタックポインタの正しい値が確実にロードされるようになります。
-
MOVL g_stackguard(g), R2
からMOVW g_stackguard(g), R2
:g_stackguard(g)
は、現在のgoroutine (g
) のスタックガード値(スタックの限界を示す値)を指します。この命令は、その値をR2
レジスタに移動しようとしています。- 同様に、
MOVL
からMOVW
への変更により、R2
にスタックガードの正しい値がロードされるようになります。
-
MOVL R1, sp+0(FP)
とMOVL R2, limit+4(FP)
からMOVW R1, sp+0(FP)
とMOVW R2, limit+4(FP)
:- これらの命令は、
R1
とR2
にロードされた値を、フレームポインタ(FP
)からのオフセットで示されるスタック上の特定のメモリ位置に格納しています。sp+0(FP)
とlimit+4(FP)
は、おそらくスタックフレーム内のローカル変数や引数の位置を示しています。 - ここでも
MOVL
からMOVW
への変更が行われていますが、これは前の2つのロード命令の修正と一貫性を保つため、またはストア命令の挙動がロード命令の挙動に依存するためと考えられます。
- これらの命令は、
全体として、この修正は、ARMアセンブリにおけるMOVL
擬似命令の特定のコンテキストでの挙動が、Goランタイムのスタックガードチェックに必要な正確な値のロードを妨げていた問題を解決しています。MOVW
に切り替えることで、レジスタにロードされる値の正確性が保証され、ARMビルドの問題が解消されたと考えられます。
関連リンク
- Go CL 5832047: https://golang.org/cl/5832047
参考にした情報源リンク
- ARM Assembly MOVW vs MOVL:
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGn58Q-ILqYp8hAqolwNt_uIXgfYc74sYIQz1WMqoGPlaBf4jbnB2BTKjfE7w5b1fpiP36lBOY_B8rYcmGZAGWIUm2QVQqz0ri6-nK2BgldZxdBEVLyiaFHY72Orm-uw5yv5J5_QOQ=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFyHGDgFVct7bQZI-v6Owp5LBXyLvSp3IOQGfXGCxhNgOGx4S3Zf1GvFejlE1hBHMQlh2xqyynLeUlOIya_khNrgKrKmudWLm5eG7N3RgHhbHeNhyY3oVe8D6oIwMVEeAiEDT5H8POBe0WQSafA7YSZB8dGTaq3cO6Fk557tRgULg==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEYHDy_u934L8jn2pGm7r3HZGxDnYOChCCpMW9CsvWkUyptzbk7WXQflTyEvh3aoIW7f65uwncX66-2oupGPmk-ZSzE9LAFStMVM80h-pmDjK9EKmeJzDmFas82HUXDNg1hyYS9WvUetGp3ZvQiALbFacZSBIgKvgElhBYsFxIOWkaqsOA=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHR4ojI8xBQ0LAb5y3FCeEhuXzRO7gk2krTlJ1ASONQRuKibx0xi9O7d5_RfSe2jN3pkEX4yWO8DRJXzkGVCPT1oMyCtGIPhXbfNTnPf4DVF0rD4ca0eOAvMislVXcMMm_zg3WdrV7xk6qSq4nswpQkZnhlSQoq44jIa1SY7YHxKQn0o7xrQ9J4WmA8Sni41Dp89WsKO0SkAUmsRMJnZRJ4GRc=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQErarJjbSA3qrW6q4MO7C1KXzBxa9ZbtWxOTHTtuwWZqcEwQIHLIEagBgk97RhfytILc5ON67Maz_2dN_vBYmmj1uNs44Y3gxgZ1sBjZ6XXympWvDMVoEpzgauglpXyqKKWr-UN07GUDJO25u6-W0txhH8na2YvHKV0sKicTeeq3kdwg3MOYIfrbcPqrSAg1G0u3cog3YKqmt-i97WZ_0EemQtA5nfJfIk=