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

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

このコミットは、Go言語のgo vetツールがアセンブリコード内の変数名を正しく検証できるように、多数のアセンブリファイルにおける変数名の更新を行っています。具体的には、関数引数や戻り値の命名規則をgo vetasmdeclチェックに準拠させるための変更が広範囲にわたって適用されています。これにより、アセンブリコードと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 vetasmdeclチェックは、Goの関数プロトタイプで定義された引数名や戻り値名と、アセンブリコード内でそれらが参照される際の命名規則との厳密な一致を期待するようになりました。

このコミットは、既存のアセンブリコードが新しいgo vetasmdeclチェックに合格するように、変数名を更新することを目的としています。これにより、アセンブリコードの可読性と保守性が向上し、Goコンパイラとアセンブリコード間のインターフェースの整合性が静的に保証されるようになります。

前提知識の解説

Go言語におけるアセンブリ

Go言語は、パフォーマンスが重要な部分や、特定のハードウェア機能にアクセスする必要がある場合に、アセンブリ言語で記述されたコード(通常はPlan 9アセンブリ構文)をGoプログラムに組み込むことをサポートしています。これらのアセンブリ関数は、Goの関数として呼び出せるように、Goの関数プロトタイプと対応付けられます。

go vetツール

go vetは、Goのソースコードを静的に解析し、疑わしい構造や潜在的なエラーを報告するツールです。コンパイルは通るものの、実行時に問題を引き起こす可能性のあるコードパターンを検出するのに役立ちます。

go vetasmdeclチェック

go vetasmdeclチェックは、Goの関数宣言と、それに対応するアセンブリ関数の引数および戻り値の宣言が一致しているかを検証します。このチェックは、特に以下の点に注目します。

  1. 引数と戻り値の命名規則: アセンブリコード内で関数引数や戻り値を参照する際、Goの関数プロトタイプで定義された名前を使用することが推奨されます。例えば、Goの関数がfunc foo(s []byte, c byte) (ret int)と宣言されている場合、アセンブリコードではs+0(FP)ではなくs_len+4(FP)のように、引数名とオフセットを組み合わせた形式で参照することが期待されます。
  2. 暗黙的な戻り値: Goの関数プロトタイプで戻り値に明示的な名前が付けられていない場合、go vetはアセンブリコード内でその戻り値をretという名前で参照することを期待します。
  3. 64ビット値の扱い: 32ビットアーキテクチャで64ビット値を扱う場合、go vetは変数の下位32ビットを_lo、上位32ビットを_hiというサフィックスを付けて参照する慣習を考慮します(例: x_lo+0(FP), x_hi+4(FP))。
  4. フレームポインタ (FP): Goのアセンブリでは、FP(フレームポインタ)疑似レジスタを使用して、関数引数や戻り値にアクセスします。arg+offset(FP)の形式で記述され、argは引数または戻り値の名前、offsetFPからのオフセットを示します。

このasmdeclチェックは、アセンブリコードの正確性を高め、Goコードとの連携における潜在的なバグを防ぐ上で重要な役割を果たします。

技術的詳細

このコミットでは、Go標準ライブラリ内の多数の386.samd64.sarm.sといったアセンブリファイルが修正されています。これらのファイルは、bytescryptohashmathreflectruntimesync/atomicといったパッケージに属しており、特定のアーキテクチャ向けに最適化された低レベルな処理を実装しています。

具体的な変更内容は、主に以下のパターンに集約されます。

  1. 汎用的な戻り値変数名の変更:

    • r+オフセット(FP)という形式で参照されていた戻り値が、ret+オフセット(FP)に変更されています。これは、Goの関数プロトタイプで戻り値に明示的な名前が付けられていない場合に、go vetが期待する命名規則に合わせたものです。
    • 例: MOVL $-1, r+16(FP)MOVL $-1, ret+16(FP) に変更。
  2. 引数名の明確化:

    • s+オフセット(FP)のように、型情報のみで参照されていた引数が、s_len+オフセット(FP)のように、引数名と意味を明確にするサフィックス(例: _len, _hi, _lo)を付加した形式に変更されています。
    • 例: MOVL s+4(FP), CXMOVL s_len+4(FP), CX に変更。
    • x+0(FP)のような汎用的な引数名が、x_lo+0(FP)x_hi+4(FP)のように、64ビット値の低位・高位バイトを明示する形式に変更されています。これは、特に32ビットアーキテクチャで64ビット値を扱う際に重要です。
    • 例: MOVL x+4(FP), AXMOVL x_hi+4(FP), AX に変更。
  3. 特定の変数名の変更:

    • crypto/rc4パッケージでは、xPtryPtrといったポインタ変数名が、それぞれijといったより具体的な変数名に変更されています。これは、RC4アルゴリズムにおける状態変数の慣習的な命名に合わせたものです。
    • 例: MOVL xPtr+16(FP), AXMOVL 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 vetasmdeclチェックが期待するアセンブリコードの変数命名規則に準拠するためのものです。

  • 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アルゴリズムの状態を管理するインデックス変数ijが、以前はxpypという汎用的なポインタ名で参照されていました。これをijという、アルゴリズムの文脈に即した名前に変更することで、コードの可読性が大幅に向上しています。

これらの変更は、アセンブリコードの機能的な振る舞いを変えるものではなく、主にgo vetによる静的解析の警告を解消し、Go言語のコーディング規約とツールチェーンとの整合性を高めることを目的としています。これにより、Goプロジェクト全体のアセンブリコードの品質と保守性が向上します。

関連リンク

参考にした情報源リンク