[インデックス 15897] ファイルの概要
このコミットは、Go言語のgo vet
ツールがアセンブリコード内の変数名を正しく検証できるように、多数のアセンブリファイルにおける変数名の更新を行っています。具体的には、関数引数や戻り値の命名規則をgo vet
のasmdecl
チェックに準拠させるための変更が広範囲にわたって適用されています。これにより、アセンブリコードとGoの関数プロトタイプとの整合性が向上し、静的解析ツールによるコード品質の保証が強化されます。
コミット
commit 07720b67b3696d57509bcdc3cb10affa9e1c887d
Author: Russ Cox <rsc@golang.org>
Date: Fri Mar 22 12:57:55 2013 -0400
build: update assembly variable names for vet
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/7834046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/07720b67b3696d57509bcdc3cb10affa9e1c887d
元コミット内容
build: update assembly variable names for vet
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/7834046
変更の背景
この変更の背景には、Go言語の静的解析ツールであるgo vet
の機能強化があります。go vet
は、Goプログラムの潜在的なバグや疑わしい構成を検出するために使用されます。特に、アセンブリコードとGoの関数宣言との間の整合性をチェックするasmdecl
という機能が存在します。
以前のGoのアセンブリコードでは、関数引数や戻り値の参照に、単にスタックオフセット(例: s+0(FP)
)を使用するか、あるいは一般的な変数名(例: r+16(FP)
)を使用することがありました。しかし、go vet
のasmdecl
チェックは、Goの関数プロトタイプで定義された引数名や戻り値名と、アセンブリコード内でそれらが参照される際の命名規則との厳密な一致を期待するようになりました。
このコミットは、既存のアセンブリコードが新しいgo vet
のasmdecl
チェックに合格するように、変数名を更新することを目的としています。これにより、アセンブリコードの可読性と保守性が向上し、Goコンパイラとアセンブリコード間のインターフェースの整合性が静的に保証されるようになります。
前提知識の解説
Go言語におけるアセンブリ
Go言語は、パフォーマンスが重要な部分や、特定のハードウェア機能にアクセスする必要がある場合に、アセンブリ言語で記述されたコード(通常はPlan 9アセンブリ構文)をGoプログラムに組み込むことをサポートしています。これらのアセンブリ関数は、Goの関数として呼び出せるように、Goの関数プロトタイプと対応付けられます。
go vet
ツール
go vet
は、Goのソースコードを静的に解析し、疑わしい構造や潜在的なエラーを報告するツールです。コンパイルは通るものの、実行時に問題を引き起こす可能性のあるコードパターンを検出するのに役立ちます。
go vet
のasmdecl
チェック
go vet
のasmdecl
チェックは、Goの関数宣言と、それに対応するアセンブリ関数の引数および戻り値の宣言が一致しているかを検証します。このチェックは、特に以下の点に注目します。
- 引数と戻り値の命名規則: アセンブリコード内で関数引数や戻り値を参照する際、Goの関数プロトタイプで定義された名前を使用することが推奨されます。例えば、Goの関数が
func foo(s []byte, c byte) (ret int)
と宣言されている場合、アセンブリコードではs+0(FP)
ではなくs_len+4(FP)
のように、引数名とオフセットを組み合わせた形式で参照することが期待されます。 - 暗黙的な戻り値: Goの関数プロトタイプで戻り値に明示的な名前が付けられていない場合、
go vet
はアセンブリコード内でその戻り値をret
という名前で参照することを期待します。 - 64ビット値の扱い: 32ビットアーキテクチャで64ビット値を扱う場合、
go vet
は変数の下位32ビットを_lo
、上位32ビットを_hi
というサフィックスを付けて参照する慣習を考慮します(例:x_lo+0(FP)
,x_hi+4(FP)
)。 - フレームポインタ (FP): Goのアセンブリでは、
FP
(フレームポインタ)疑似レジスタを使用して、関数引数や戻り値にアクセスします。arg+offset(FP)
の形式で記述され、arg
は引数または戻り値の名前、offset
はFP
からのオフセットを示します。
このasmdecl
チェックは、アセンブリコードの正確性を高め、Goコードとの連携における潜在的なバグを防ぐ上で重要な役割を果たします。
技術的詳細
このコミットでは、Go標準ライブラリ内の多数の386.s
、amd64.s
、arm.s
といったアセンブリファイルが修正されています。これらのファイルは、bytes
、crypto
、hash
、math
、reflect
、runtime
、sync/atomic
といったパッケージに属しており、特定のアーキテクチャ向けに最適化された低レベルな処理を実装しています。
具体的な変更内容は、主に以下のパターンに集約されます。
-
汎用的な戻り値変数名の変更:
r+オフセット(FP)
という形式で参照されていた戻り値が、ret+オフセット(FP)
に変更されています。これは、Goの関数プロトタイプで戻り値に明示的な名前が付けられていない場合に、go vet
が期待する命名規則に合わせたものです。- 例:
MOVL $-1, r+16(FP)
がMOVL $-1, ret+16(FP)
に変更。
-
引数名の明確化:
s+オフセット(FP)
のように、型情報のみで参照されていた引数が、s_len+オフセット(FP)
のように、引数名と意味を明確にするサフィックス(例:_len
,_hi
,_lo
)を付加した形式に変更されています。- 例:
MOVL s+4(FP), CX
がMOVL s_len+4(FP), CX
に変更。 x+0(FP)
のような汎用的な引数名が、x_lo+0(FP)
やx_hi+4(FP)
のように、64ビット値の低位・高位バイトを明示する形式に変更されています。これは、特に32ビットアーキテクチャで64ビット値を扱う際に重要です。- 例:
MOVL x+4(FP), AX
がMOVL x_hi+4(FP), AX
に変更。
-
特定の変数名の変更:
crypto/rc4
パッケージでは、xPtr
やyPtr
といったポインタ変数名が、それぞれi
やj
といったより具体的な変数名に変更されています。これは、RC4アルゴリズムにおける状態変数の慣習的な命名に合わせたものです。- 例:
MOVL xPtr+16(FP), AX
がMOVL i+16(FP), AX
に変更。 crypto/sha1
パッケージのsha1block_amd64.s
では、p+8(FP)
がp_base+8(FP)
に変更され、ポインタのベースアドレスであることを明確にしています。
これらの変更は、アセンブリコードの機能自体を変更するものではなく、あくまでgo vet
による静的解析の精度を高め、開発者がアセンブリコードの意図をより正確に理解できるようにするためのものです。
コアとなるコードの変更箇所
このコミットは多数のファイルにわたる変更ですが、その本質は変数名の変更にあります。以下に代表的な変更箇所をいくつか示します。
src/pkg/bytes/asm_386.s
--- a/src/pkg/bytes/asm_386.s
+++ b/src/pkg/bytes/asm_386.s
@@ -4,21 +4,21 @@
TEXT ·IndexByte(SB),7,$0
MOVL s+0(FP), SI
- MOVL s+4(FP), CX
+ MOVL s_len+4(FP), CX
MOVB c+12(FP), AL
MOVL SI, DI
CLD; REPN; SCASB
JZ 3(PC)
- MOVL $-1, r+16(FP)
+ MOVL $-1, ret+16(FP)
RET
SUBL SI, DI
SUBL $1, DI
- MOVL DI, r+16(FP)
+ MOVL DI, ret+16(FP)
RET
TEXT ·Equal(SB),7,$0
- MOVL a+4(FP), BX
- MOVL b+16(FP), CX
+ MOVL a_len+4(FP), BX
+ MOVL b_len+16(FP), CX
MOVL $0, AX
CMPL BX, CX
JNE eqret
@@ -29,5 +29,5 @@ TEXT ·Equal(SB),7,$0
JNE eqret
MOVL $1, AX
eqret:
- MOVB AX, r+24(FP)
+ MOVB AX, ret+24(FP)
RET
src/pkg/crypto/rc4/rc4_amd64.s
--- a/src/pkg/crypto/rc4/rc4_amd64.s
+++ b/src/pkg/crypto/rc4/rc4_amd64.s
@@ -37,13 +37,13 @@
*/
TEXT ·xorKeyStream(SB),7,$0
- MOVQ len+16(FP), BX // rbx = ARG(len)
- MOVQ in+8(FP), SI // in = ARG(in)
- MOVQ out+0(FP), DI // out = ARG(out)
- MOVQ d+24(FP), BP // d = ARG(data)
- MOVQ xp+32(FP), AX
+ MOVQ n+16(FP), BX // rbx = ARG(len)
+ MOVQ src+8(FP), SI // in = ARG(in)
+ MOVQ dst+0(FP), DI // out = ARG(out)
+ MOVQ state+24(FP), BP // d = ARG(data)
+ MOVQ i+32(FP), AX
MOVBQZX 0(AX), CX // x = *xp
- MOVQ yp+40(FP), AX
+ MOVQ j+40(FP), AX
MOVBQZX 0(AX), DX // y = *yp
LEAQ (SI)(BX*1), R9 // limit = in+len
@@ -170,8 +170,8 @@ l2: CMPQ SI, R9 // cmp in with in+len
JMP l2
finished:
- MOVQ yp+40(FP), BX
+ MOVQ j+40(FP), BX
MOVB DX, 0(BX)
- MOVQ xp+32(FP), AX
+ MOVQ i+32(FP), AX
MOVB CX, 0(AX)
RET
src/pkg/math/exp2_386.s
--- a/src/pkg/math/exp2_386.s
+++ b/src/pkg/math/exp2_386.s
@@ -5,7 +5,7 @@
// func Exp2(x float64) float64
TEXT ·Exp2(SB),7,$0
// test bits for not-finite
- MOVL x+4(FP), AX
+ MOVL x_hi+4(FP), AX
ANDL $0x7ff00000, AX
CMPL AX, $0x7ff00000
JEQ not_finite
@@ -19,20 +19,20 @@ TEXT ·Exp2(SB),7,$0
FADDDP F0, F1 // F0=2**(x-int(x)), F1=int(x)
FSCALE // F0=2**x, F1=int(x)
FMOVDP F0, F1 // F0=2**x
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
not_finite:
// test bits for -Inf
- MOVL x+4(FP), BX
- MOVL x+0(FP), CX
+ MOVL x_hi+4(FP), BX
+ MOVL x_lo+0(FP), CX
CMPL BX, $0xfff00000
JNE not_neginf
CMPL CX, $0
JNE not_neginf
- MOVL $0, r+8(FP)
- MOVL $0, r+12(FP)
+ MOVL $0, ret_lo+8(FP)
+ MOVL $0, ret_hi+12(FP)
RET
not_neginf:
- MOVL CX, r+8(FP)
- MOVL BX, r+12(FP)
+ MOVL CX, ret_lo+8(FP)
+ MOVL BX, ret_hi+12(FP)
RET
コアとなるコードの解説
上記のコード変更は、go vet
のasmdecl
チェックが期待するアセンブリコードの変数命名規則に準拠するためのものです。
s+4(FP)
からs_len+4(FP)
:bytes.IndexByte
関数のs
引数はバイトスライスであり、Goではスライスはポインタ、長さ、容量の3つの要素で構成されます。s+0(FP)
はスライスのデータポインタ、s+4(FP)
はスライスの長さ(32ビットシステムの場合)を指します。go vet
は、引数の意味をより明確にするために、s_len
のようにサフィックスを付加した命名を推奨しています。r+16(FP)
からret+16(FP)
:IndexByte
関数の戻り値はint
型であり、Goの関数プロトタイプでは戻り値に明示的な名前が付けられていません。このような場合、go vet
はアセンブリコード内で戻り値をret
という名前で参照することを期待します。これにより、アセンブリコードがGoの関数シグネチャとより密接に連携していることを示します。a+4(FP)
からa_len+4(FP)
、b+16(FP)
からb_len+16(FP)
:bytes.Equal
関数もバイトスライスを引数に取るため、同様にスライスの長さを表す部分に_len
サフィックスが追加されています。x+4(FP)
からx_hi+4(FP)
、x+0(FP)
からx_lo+0(FP)
:math.Exp2
関数はfloat64
型の引数x
を取ります。32ビットシステムでは、64ビットの浮動小数点数は2つの32ビットワードとして扱われます。go vet
は、これらのワードを_lo
(下位)と_hi
(上位)サフィックスで区別することを推奨しており、これによりコードの意図が明確になります。xp+32(FP)
からi+32(FP)
、yp+40(FP)
からj+40(FP)
:crypto/rc4.xorKeyStream
関数では、RC4アルゴリズムの状態を管理するインデックス変数i
とj
が、以前はxp
とyp
という汎用的なポインタ名で参照されていました。これをi
とj
という、アルゴリズムの文脈に即した名前に変更することで、コードの可読性が大幅に向上しています。
これらの変更は、アセンブリコードの機能的な振る舞いを変えるものではなく、主にgo vet
による静的解析の警告を解消し、Go言語のコーディング規約とツールチェーンとの整合性を高めることを目的としています。これにより、Goプロジェクト全体のアセンブリコードの品質と保守性が向上します。
関連リンク
- Go Assembly Language (Go公式ドキュメント): https://go.dev/doc/asm
go vet
documentation: https://pkg.go.dev/cmd/vetgo vet
asmdecl
check: https://go.dev/src/cmd/vet/README (このREADME内でasmdecl
に関する記述があります)
参考にした情報源リンク
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH1xnlZUD-lINUKSP8dzmfcebF9pKkg-JRtkhWT14y19d2nxr9CnZfcql84I7n1fSlfxNofl6b6jVxpkp1RM_enrJh8e3RADQ0P-3zhHiWkyVDe1CQ=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEveTEjlm4r_W98u8AuBxdmYwm1WLmwid85rGLqS1BC0-CPL0XXBepelNZknOAlkskbTMQYoRvedVT8Zi9krdiX6_1Fnv9kHwlYyyncuyNFW3qZcFSHLWgcHijQeGa59PNAoBuBwjrcAxU0
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGIvJ9zNlsMILCGtIQkG-x2HXpRr1HAL6x4AKn-ZNXnRCcqOcM6BSgEtAXKoJgsJScbWhtc-4msHu0tXH-X_tn9Q9nFSBMTa99z-U1sVBU4qrlx4EXYngoHVvZD
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEZ9t3x9VBC_AmHfOyfizYhiPvrnaDl7_2kQORyYeY4RvUcbsj4MrsdjWCoUPT1CBxBLpNw4NqHU3MVxBw3g2pZglwmzY4RQ9mtHgRXgD9oNA==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFXD4-0UEAFPhdTg9wXGzP1YnWtO6TIJloqB5FTYlTzcSLiikrO5OfPNy6fzuxfYLadpx6hq8GLGm8_GJ1oPzKXjbVdwYcOjoM1wq2WreTZ9pw4cB3RnVA7rg6t6yjBN3HfcSJY2h_rSe9fV9Y1xkYovInj