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

[インデックス 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/6acmd/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 3A3A)。
        • 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言語のツールチェインにおけるアセンブラとリンカの定義ファイルです。

  1. 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 にマッピングするためのものです。

  2. 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 を追加し、リンカがこの新しい命令を内部的に識別できるようにするためのものです。

  3. 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命令)を持つことを示唆しています。
  • src/cmd/6l/6.out.h の変更:

    • このヘッダファイルは、Goのリンカが使用する定数やデータ構造を定義しています。enum as は、Goのリンカが扱うすべてのアセンブリ命令の内部的な識別子を列挙したものです。
    • APCLMULQDQ, を追加することで、リンカは PCLMULQDQ 命令を他の命令と同様に、一意の内部識別子で参照できるようになります。これは、リンカが命令を処理する際の内部ロジックで必要となります。
  • 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言語のビルドシステムは、PCLMULQDQ命令を含むアセンブリコードを正しくコンパイルし、実行可能なバイナリを生成できるようになります。これにより、Go開発者は、Goの組み込みアセンブラ機能(go:asm ディレクティブなど)を通じて、この高性能なCPU命令を直接利用し、特定の計算処理のパフォーマンスを最適化することが可能になります。

関連リンク

参考にした情報源リンク