[インデックス 16611] ファイルの概要
このコミットは、Go言語のツールチェイン(具体的には cmd/6a
アセンブラと cmd/6l
リンカ)に、IntelのPCLMULQDQ(Carry-less Multiplication Quadword)命令のサポートを追加するものです。これにより、Goプログラム内でこの特殊な命令を利用できるようになり、バイナリフィールドにおける乗算などの特定の暗号化処理やデータ処理のパフォーマンスが向上する可能性があります。
コミット
commit 6bea504b9407a1ce8ac3f6909f4e728be5b18764
Author: Adam Langley <agl@golang.org>
Date: Fri Jun 21 15:17:13 2013 -0400
cmd/6a, cmd/6l: add PCLMULQDQ instruction.
This Intel instruction implements multiplication in binary fields.
R=golang-dev, minux.ma, dave, rsc
CC=golang-dev
https://golang.org/cl/10428043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6bea504b9407a1ce8ac3f6909f4e728be5b18764
元コミット内容
cmd/6a, cmd/6l: add PCLMULQDQ instruction.
このIntel命令はバイナリフィールドにおける乗算を実装します。
変更の背景
このコミットの背景には、特定の計算処理、特に暗号化アルゴリズムにおけるパフォーマンスの最適化があります。PCLMULQDQ命令は、IntelのSSE(Streaming SIMD Extensions)命令セットの一部として導入されたもので、主にAES(Advanced Encryption Standard)などのブロック暗号におけるGCM(Galois/Counter Mode)モードでの認証タグ生成や、CRC(Cyclic Redundancy Check)計算など、バイナリフィールド(GF(2^n))での乗算をハードウェアレベルで高速化するために設計されました。
Go言語は、ネットワークプログラミングやシステムプログラミングにおいて高いパフォーマンスが求められる場面で広く利用されています。暗号化処理は多くのアプリケーションで不可欠であり、その性能は全体のボトルネックとなることがあります。PCLMULQDQ命令のサポートを追加することで、Goプログラムがこれらの特定の計算をCPUの専用ハードウェア機能を利用して実行できるようになり、ソフトウェアによる実装と比較して大幅な速度向上を期待できます。
当時のGo言語の標準ライブラリや、Goで書かれたアプリケーションが、PCLMULQDQ命令を利用するような暗号化処理やデータ完全性チェックを効率的に行えるようにすることが、この変更の主な動機と考えられます。
前提知識の解説
1. Intel PCLMULQDQ 命令
PCLMULQDQ(Carry-less Multiplication Quadword)は、IntelのSSE命令セットの一部として、Westmereマイクロアーキテクチャ(2010年頃)で導入された命令です。この命令は、64ビットの2つの入力(クワッドワード)に対して、キャリーなし乗算(carry-less multiplication)を実行します。
- キャリーなし乗算: 通常の整数乗算とは異なり、ビットごとのXOR演算を基本とし、キャリー(繰り上がり)を伝播させません。これは、有限体GF(2^n)における多項式乗算に相当します。
- 用途: 主に以下の分野で利用されます。
- 暗号化: AES-GCM(Galois/Counter Mode)の認証タグ生成。GCMは、認証付き暗号化モードであり、その認証部分でGF(2^128)上の乗算が頻繁に用いられます。PCLMULQDQ命令は、この乗算をハードウェアで高速化します。
- データ完全性チェック: CRC(Cyclic Redundancy Check)計算。CRCは、データ転送や保存におけるエラー検出に用いられるチェックサムの一種であり、その計算はバイナリフィールドでの多項式除算に基づいています。PCLMULQDQは、CRC計算の高速化にも寄与します。
- ハッシュ関数: 特定のハッシュ関数の実装。
2. Go言語のツールチェイン (cmd/6a
, cmd/6l
)
Go言語のビルドプロセスは、複数のツールで構成されています。このコミットで言及されている cmd/6a
と cmd/6l
は、それぞれアセンブラとリンカを指します。
cmd/6a
(アセンブラ): Go言語のコンパイラは、最終的にアセンブリコードを生成します。6a
は、x86-64アーキテクチャ(Goでは通常amd64
と呼ばれる)向けのアセンブラであり、アセンブリ言語のニーモニック(例:MOVQ
,ADDQ
など)を機械語の命令に変換する役割を担います。新しいCPU命令をGoプログラムから利用できるようにするためには、まずこのアセンブラがその命令を認識し、正しく機械語に変換できるようにする必要があります。cmd/6l
(リンカ):6l
は、x86-64アーキテクチャ向けのリンカであり、アセンブラによって生成されたオブジェクトファイルや、他のライブラリのオブジェクトファイルを結合して、実行可能なバイナリを生成します。リンカは、命令のオペコードやフォーマットに関する知識を持ち、最終的な実行ファイルにそれらを正しく配置する役割を担います。新しい命令が追加された場合、リンカもその命令を正しく処理できるように更新される必要があります。
Go言語のツールチェインは、特定のアーキテクチャ(この場合は amd64
)に対して、アセンブラ、リンカ、コンパイラなどがセットで提供されます。6
はx86-64アーキテクチャを指す慣例的なプレフィックスです。
3. バイナリフィールド(有限体GF(2^n))
バイナリフィールド、またはガロア体GF(2^n)は、数学の一分野である抽象代数学における有限体の一種です。コンピュータサイエンス、特に暗号学や符号理論において非常に重要です。
- 要素: GF(2^n)の要素は、nビットのバイナリベクトル(またはn-1次以下の多項式)として表現されます。
- 演算:
- 加算: ビットごとのXOR演算に対応します。
- 乗算: キャリーなし乗算に対応します。これは、既約多項式を法とする多項式乗算として定義されます。PCLMULQDQ命令は、このキャリーなし乗算をハードウェアで実行します。
- 重要性: 多くの現代の暗号アルゴリズム(例: AES、楕円曲線暗号の一部)やエラー訂正符号(例: Reed-Solomon符号)は、このバイナリフィールド上での演算を基礎としています。
このコミットは、Go言語がこれらの低レベルなCPU命令をサポートすることで、Goで書かれたアプリケーションが、暗号化やデータ処理の分野でより高いパフォーマンスを発揮できるようにするための基盤を強化するものです。
技術的詳細
このコミットは、Go言語のx86-64(amd64)アセンブラ (src/cmd/6a/lex.c
) とリンカ (src/cmd/6l/6.out.h
, src/cmd/6l/optab.c
) にPCLMULQDQ命令のサポートを追加しています。
1. アセンブラ (src/cmd/6a/lex.c
) への変更
src/cmd/6a/lex.c
は、Goのアセンブラの字句解析器(lexer)の一部です。このファイルには、アセンブリ命令のニーモニックとそれに対応する内部表現(オペコード)のマッピングが定義されています。
- 変更内容:
struct inst
の定義リストに"PCLMULQDQ"
という文字列と、それに対応する内部オペコードAPCLMULQDQ
が追加されています。LTYPEX
: これは、命令のタイプを示すフラグで、おそらく特定のオペランドタイプや命令の特性を示すものです。APCLMULQDQ
: これは、Goのアセンブラが内部的にPCLMULQDQ命令を識別するために使用する定数です。
この変更により、Goのアセンブラは、ソースコード中の PCLMULQDQ
というニーモニックを認識し、それを内部的な命令表現に変換できるようになります。
2. リンカ (src/cmd/6l/6.out.h
) への変更
src/cmd/6l/6.out.h
は、Goのリンカが使用するヘッダファイルで、主に命令のオペコードやその他の定数を定義しています。
- 変更内容:
enum as
の定義にAPCLMULQDQ
という新しいエントリが追加されています。enum as
: これは、Goのリンカが扱うアセンブリ命令の内部的な列挙型(enum)です。各アセンブリ命令は、この列挙型によって一意に識別されます。
この変更は、アセンブラで追加された APCLMULQDQ
定数とリンカが連携できるようにするためのもので、リンカがこの新しい命令を認識し、処理できるようにするために必要です。
3. リンカ (src/cmd/6l/optab.c
) への変更
src/cmd/6l/optab.c
は、Goのリンカが命令のオペコードテーブルを定義しているファイルです。このテーブルは、各アセンブリ命令がどのような機械語のバイト列に変換されるか、またどのようなオペランドを伴うかといった情報を含んでいます。
- 変更内容:
Optab optab[]
という命令テーブルに、APCLMULQDQ
に対応するエントリが追加されています。{ APCLMULQDQ, yxshuf, Pq, 0x3a,0x44,0 }
:APCLMULQDQ
: 命令の内部識別子。yxshuf
: 命令の形式やオペランドのタイプを示すフラグまたは関数ポインタ。PCLMULQDQは、SHUFP*
命令群と似たオペランド形式を持つため、yxshuf
が使われている可能性があります。これは、2つのソースオペランドと1つの即値オペランド(imm8)を取る命令の一般的なパターンです。Pq
: 命令のプレフィックスバイト(0x66)とオペランドサイズ(64ビット)を示すフラグ。PCLMULQDQは通常、64ビットオペランドで動作し、0x66
プレフィックスを必要とします。0x3a, 0x44, 0
: これらはPCLMULQDQ命令の実際のオペコードバイト列の一部です。0x3a
: VEXプレフィックスを使用しない場合の命令の最初のバイト(0F 3A
の3A
)。0x44
: 命令の2番目のバイト(0F 3A 44
)。0
: これは、命令のModR/MバイトやSIBバイト、または即値オペランドのオフセットなどを示す可能性があります。PCLMULQDQ命令は、0F 3A 44 /r ib
の形式を持ち、/r
はModR/Mバイトの一部としてレジスタとメモリ/レジスタオペランドを指定し、ib
は8ビットの即値オペランドです。
この変更により、Goのリンカは PCLMULQDQ
命令を正しく機械語に変換し、生成される実行ファイルに組み込むことができるようになります。
全体的な影響
これらの変更は、Go言語のコンパイラがPCLMULQDQ命令を生成できるようになるための基盤を構築します。Goのコンパイラは、特定の組み込み関数や、go:asm
ディレクティブを使用したアセンブリコードを通じて、この新しい命令を利用できるようになります。これにより、Goで書かれた暗号ライブラリや、バイナリフィールド演算を多用するアプリケーションが、CPUのハードウェアアクセラレーションを活用してパフォーマンスを向上させることが可能になります。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は、Go言語のツールチェインにおけるアセンブラとリンカの定義ファイルです。
-
src/cmd/6a/lex.c
:--- a/src/cmd/6a/lex.c +++ b/src/cmd/6a/lex.c @@ -1019,6 +1019,7 @@ struct "AESKEYGENASSIST", LTYPEX, AAESKEYGENASSIST, "PSHUFD", LTYPEX, APSHUFD, "USEFIELD", LTYPEN, AUSEFIELD, + "PCLMULQDQ", LTYPEX, APCLMULQDQ, 0 };
この変更は、アセンブラが
PCLMULQDQ
というニーモニックを認識し、それを内部的な命令コードAPCLMULQDQ
にマッピングするためのものです。 -
src/cmd/6l/6.out.h
:--- a/src/cmd/6l/6.out.h +++ b/src/cmd/6l/6.out.h @@ -766,6 +766,8 @@ enum ANPTRS, APTRS, + APCLMULQDQ, + ALAST };
この変更は、リンカが使用する命令コードの列挙型に
APCLMULQDQ
を追加し、リンカがこの新しい命令を内部的に識別できるようにするためのものです。 -
src/cmd/6l/optab.c
:--- a/src/cmd/6l/optab.c +++ b/src/cmd/6l/optab.c @@ -1344,6 +1344,8 @@ Optab optab[] = { ANPTRS }, { APTRS }, + { APCLMULQDQ, yxshuf, Pq, 0x3a,0x44,0 }, + { AEND }, 0 };
この変更は、リンカの命令テーブルに
PCLMULQDQ
命令のエントリを追加し、その命令がどのような機械語のバイト列に変換されるか(オペコード0x3a, 0x44
、プレフィックスPq
、オペランド形式yxshuf
など)を定義しています。
コアとなるコードの解説
これらの変更は、Go言語のビルドシステムがPCLMULQDQ命令を「理解」し、Goプログラム内でこの命令を使用できるようにするための基本的なステップです。
-
src/cmd/6a/lex.c
の変更:- Goのアセンブラは、アセンブリ言語のソースコードを読み込み、それを機械語に変換します。このファイルは、アセンブラが認識する命令のニーモニック(例:
MOVQ
,ADDQ
)とその内部表現の対応付けを定義しています。 "PCLMULQDQ", LTYPEX, APCLMULQDQ,
という行を追加することで、アセンブラはPCLMULQDQ
というテキストを読み込んだときに、それがAPCLMULQDQ
という内部的な命令コードに対応することを認識します。LTYPEX
は、この命令が特定のオペランドタイプ(おそらくXMMレジスタを使用するSIMD命令)を持つことを示唆しています。
- Goのアセンブラは、アセンブリ言語のソースコードを読み込み、それを機械語に変換します。このファイルは、アセンブラが認識する命令のニーモニック(例:
-
src/cmd/6l/6.out.h
の変更:- このヘッダファイルは、Goのリンカが使用する定数やデータ構造を定義しています。
enum as
は、Goのリンカが扱うすべてのアセンブリ命令の内部的な識別子を列挙したものです。 APCLMULQDQ,
を追加することで、リンカはPCLMULQDQ
命令を他の命令と同様に、一意の内部識別子で参照できるようになります。これは、リンカが命令を処理する際の内部ロジックで必要となります。
- このヘッダファイルは、Goのリンカが使用する定数やデータ構造を定義しています。
-
src/cmd/6l/optab.c
の変更:- このファイルは、Goのリンカがアセンブリ命令を実際の機械語のバイト列に変換するための「オペコードテーブル」を定義しています。各エントリは、特定の命令(
APCLMULQDQ
)がどのようなオペランド形式(yxshuf
)、どのようなプレフィックス(Pq
)、そしてどのようなオペコードバイト(0x3a, 0x44, 0
)を持つかを指定します。 yxshuf
: これは、PCLMULQDQ命令が持つオペランドの形式を示します。PCLMULQDQは通常、2つのXMMレジスタと1つの即値オペランド(imm8)を取ります。yxshuf
は、このようなシャッフル命令に似たオペランド形式を処理するための内部的なルーチンを指している可能性があります。Pq
: これは、命令が64ビットオペランドを使用し、0x66
というオペランドサイズプレフィックスを必要とすることを示します。PCLMULQDQは通常、64ビットのクワッドワードを処理するため、このプレフィックスが必要です。0x3a, 0x44, 0
: これらはPCLMULQDQ命令の実際の機械語オペコードの一部です。Intelの命令セットリファレンスによると、PCLMULQDQ命令のオペコードは0F 3A 44 /r ib
です。ここで0F
はエスケープバイト、3A
は命令の主要なオペコード、44
は命令のサブオペコード、/r
はModR/Mバイトの一部としてレジスタとメモリ/レジスタオペランドを指定し、ib
は8ビットの即値オペランドです。0x3a, 0x44
はこのオペコードの主要部分に対応し、0
は即値オペランドのオフセットや、ModR/Mバイトの特定のビットフィールドを示す可能性があります。
- このファイルは、Goのリンカがアセンブリ命令を実際の機械語のバイト列に変換するための「オペコードテーブル」を定義しています。各エントリは、特定の命令(
これらの変更が組み合わされることで、Go言語のビルドシステムは、PCLMULQDQ命令を含むアセンブリコードを正しくコンパイルし、実行可能なバイナリを生成できるようになります。これにより、Go開発者は、Goの組み込みアセンブラ機能(go:asm
ディレクティブなど)を通じて、この高性能なCPU命令を直接利用し、特定の計算処理のパフォーマンスを最適化することが可能になります。
関連リンク
- Intel® 64 and IA-32 Architectures Software Developer’s Manuals: PCLMULQDQ命令の詳細な仕様は、Intelの公式ドキュメントで確認できます。
- AES-GCM: PCLMULQDQ命令が主に利用される暗号化モードに関する情報。
- Go言語のアセンブリ: Go言語でアセンブリコードを記述する方法に関する公式ドキュメント。
参考にした情報源リンク
- Go言語のコミット履歴:
- Intel PCLMULQDQ Instruction:
- https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_clmulepi64_si128 (Intel Intrinsics Guide)
- https://en.wikipedia.org/wiki/CLMUL_instruction_set (Wikipedia)
- Go言語のツールチェインに関する一般的な情報:
- https://go.dev/doc/ (Go言語公式ドキュメント)
- https://go.dev/src/cmd/ (Go言語のソースコードリポジトリ)
- バイナリフィールド(有限体):
- https://en.wikipedia.org/wiki/Finite_field (Wikipedia)
- https://en.wikipedia.org/wiki/Galois_field_arithmetic (Wikipedia)
- CRC (Cyclic Redundancy Check):
- Go言語の内部構造に関するブログ記事や解説:
- Go言語のコンパイラやリンカの内部構造に関する情報は、公式ドキュメント以外にも、Goコミュニティのブログ記事や技術解説が参考になります。