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

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

このコミットは、Go言語の標準ライブラリ crypto/sha512 パッケージにおけるビルドエラーを修正するものです。具体的には、386 (Intel 80386互換アーキテクチャ、32ビットシステム) 環境でのビルドが失敗する問題に対処しています。SHA512ハッシュ関数のブロック処理の実装において、386 アーキテクチャ向けのアセンブリ実装がまだ存在しないにもかかわらず、ビルドタグによってその実装がコンパイル対象に含まれてしまうことが原因でした。

コミット

commit 9a7fb683599536af53fefba693dceff3810cdc8d
Author: Joel Sing <jsing@google.com>
Date:   Tue Jan 7 23:50:31 2014 +1100

    crypto/sha512: avoid duplicate block declaration on 386
    
    Unbreak the build - we do not have a sha512 block implementation in
    386 assembly (yet).
    
    R=golang-codereviews, dave
    CC=golang-codereviews
    https://golang.org/cl/48520043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/9a7fb683599536af53fefba693dceff3810cdc8d

元コミット内容

crypto/sha512: avoid duplicate block declaration on 386

このコミットメッセージは、crypto/sha512 パッケージにおいて、386 アーキテクチャで重複するブロック宣言を回避することを目的としていることを示しています。具体的には、386 向けのアセンブリ実装が存在しないためにビルドが壊れるのを防ぐ、という内容です。

変更の背景

Go言語の標準ライブラリ crypto/sha512 は、セキュアハッシュアルゴリズムSHA-512の実装を提供します。暗号学的ハッシュ関数は、多くの場合、パフォーマンス向上のために特定アーキテクチャ向けのアセンブリ言語で最適化された実装を持ちます。これは、Goのような高水準言語で書かれたコードよりも、CPUのレジスタや命令セットを直接操作することで、より高速な処理を実現できるためです。

このコミットが行われた時点では、crypto/sha512 パッケージには amd64 (64ビットIntel/AMDアーキテクチャ) 向けのアセンブリ最適化された block 関数(SHA-512のコアとなるブロック処理を行う関数)が存在していました。しかし、386 (32ビットIntel/AMDアーキテクチャ) 向けのアセンブリ実装はまだ準備されていませんでした。

Goのビルドシステムでは、ファイルの先頭に記述される「ビルドタグ」という特殊なコメント行を用いて、特定のファイルがどの環境(OSやアーキテクチャなど)でコンパイルされるべきかを制御します。問題となっていた sha512block_decl.go ファイルは、アセンブリ実装された block 関数のGo側の宣言(Goコードからアセンブリ関数を呼び出すための宣言)を含んでいました。このファイルには当初 // +build 386 amd64 というビルドタグが付与されており、これは「このファイルは 386 または amd64 アーキテクチャでビルドされるべきである」という意味になります。

386 環境でビルドする際、sha512block_decl.go がコンパイル対象に含まれるにもかかわらず、対応する 386 向けのアセンブリ実装 (sha512block_386.s のようなファイル) が存在しないため、リンカが block 関数の定義を見つけられず、ビルドエラーが発生していました。このエラーは「重複する宣言」として報告されることがありますが、実態は「宣言はあるが定義がない」というリンカエラーです。

このコミットの目的は、386 環境でのビルドを「壊さない」こと、つまりビルドエラーを解消することでした。

前提知識の解説

Go言語のビルドタグ (Build Tags)

Go言語には、ソースコードファイルのコンパイルを条件付きで行うための「ビルドタグ」という仕組みがあります。これは、ファイルの先頭に // +build tag1 tag2 のような形式で記述される特殊なコメント行です。ビルドタグは、Goコンパイラがそのファイルをコンパイルに含めるかどうかを決定するために使用されます。

  • // +build tag1 tag2: 論理OR条件。tag1 または tag2 のいずれかが有効な場合にファイルがコンパイルされます。
  • // +build tag1,tag2: 論理AND条件。tag1tag2 の両方が有効な場合にファイルがコンパイルされます。
  • // +build !tag: 論理NOT条件。tag が有効でない場合にファイルがコンパイルされます。

一般的なタグには、オペレーティングシステム (linux, windows, darwin など)、アーキテクチャ (amd64, 386, arm など)、Goのバージョン (go1.18 など)、またはカスタムタグがあります。このコミットでは、アーキテクチャタグ 386amd64 が使用されています。

SHA-512ハッシュ関数

SHA-512 (Secure Hash Algorithm 512-bit) は、NIST (National Institute of Standards and Technology) によってFIPS PUB 180-4で定義された暗号学的ハッシュ関数の一つです。入力されたデータから固定長の512ビット(64バイト)のハッシュ値(メッセージダイジェスト)を生成します。主な特徴は以下の通りです。

  • 一方向性: ハッシュ値から元のデータを復元することは計算上困難です。
  • 衝突耐性: 異なる入力から同じハッシュ値が生成されること(衝突)は計算上困難です。
  • 雪崩効果: 入力データのごくわずかな変更でも、ハッシュ値が大きく変化します。

SHA-512は、データの完全性検証、デジタル署名、パスワードの保存など、様々なセキュリティ関連の用途で利用されます。内部的には、入力データを固定長のブロックに分割し、各ブロックに対して複雑な一連のビット演算(ビットシフト、論理演算、加算など)を繰り返し適用することでハッシュ値を計算します。このブロック処理は計算負荷が高いため、特にパフォーマンスが求められる環境では、アセンブリ言語による最適化が施されることがあります。

アセンブリ言語による最適化

Go言語は、C言語と同様に、パフォーマンスが重要な部分でアセンブリ言語のコードを組み込むことができます。これは、特に暗号処理や低レベルのシステム操作など、最大限の性能を引き出す必要がある場合に用いられます。アセンブリ言語は特定のCPUアーキテクチャの命令セットに直接対応するため、コンパイラが生成する汎用的な機械語よりも効率的なコードを書くことが可能です。

Goでは、アセンブリコードは .s 拡張子を持つファイルに記述され、Goの関数として呼び出せるようにエクスポートされます。Goのビルドシステムは、これらのアセンブリファイルをGoのソースコードと一緒にコンパイルし、最終的なバイナリにリンクします。

技術的詳細

このコミットの技術的な核心は、Goのビルドタグの挙動と、アセンブリ実装の有無によるリンカの動作にあります。

src/pkg/crypto/sha512/sha512block_decl.go ファイルは、Goコードからアセンブリで実装された block 関数を呼び出すための宣言を提供します。この宣言は、Goコンパイラに対して「block という名前の関数が外部(この場合はアセンブリファイル)で定義されている」と伝えます。

変更前のビルドタグ // +build 386 amd64 は、この宣言ファイルが 386 または amd64 のいずれかのアーキテクチャでビルドされる場合にコンパイル対象となることを意味していました。

  • amd64 環境の場合: sha512block_decl.go がコンパイルされ、対応する sha512block_amd64.s (仮称) のようなアセンブリファイルもコンパイル・リンクされます。これにより、block 関数の宣言と定義が揃い、ビルドは成功します。
  • 386 環境の場合: sha512block_decl.go がコンパイルされます。しかし、この時点では 386 向けのアセンブリ実装ファイル (sha512block_386.s のようなファイル) が存在しませんでした。結果として、Goコンパイラは block 関数の宣言を認識しますが、リンカが最終的なバイナリを生成する際に、その宣言に対応する実体(定義)を見つけることができません。これが「undefined reference to block」のようなリンカエラー、またはコミットメッセージにある「duplicate block declaration」という形で報告されるビルドの失敗につながっていました。

このコミットは、sha512block_decl.go ファイルのビルドタグを // +build amd64 に変更することで、この問題を解決しています。この変更により、sha512block_decl.goamd64 アーキテクチャでのみコンパイルされるようになります。

  • amd64 環境の場合: 以前と同様にコンパイル・リンクが成功します。
  • 386 環境の場合: sha512block_decl.go はコンパイル対象から除外されます。これにより、block 関数のアセンブリ実装が存在しない 386 環境では、この関数の宣言自体もコンパイルされなくなります。その結果、リンカが未定義のシンボルを探すこともなくなり、ビルドエラーが解消されます。

386 環境では、アセンブリ最適化された block 関数が利用できないため、Go言語で書かれたフォールバックの実装(通常は sha512.go などに存在する)が代わりに利用されることになります。これにより、機能的には問題なく動作しますが、パフォーマンスはアセンブリ最適化版に劣る可能性があります。コミットメッセージの「(yet)」という言葉は、将来的に 386 向けのアセンブリ実装が追加される可能性を示唆しています。

コアとなるコードの変更箇所

変更は src/pkg/crypto/sha512/sha512block_decl.go ファイルの1箇所のみです。

--- a/src/pkg/crypto/sha512/sha512block_decl.go
+++ b/src/pkg/crypto/sha512/sha512block_decl.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build 386 amd64
+// +build amd64
 
 package sha512
 

コアとなるコードの解説

この変更は、ファイルの先頭にあるビルドタグの行を修正しています。

  • 変更前: // +build 386 amd64
    • この行は、このファイルが 386 または amd64 のいずれかのアーキテクチャでビルドされる場合にコンパイル対象となることを示していました。
  • 変更後: // +build amd64
    • この行は、このファイルが amd64 アーキテクチャでのみコンパイル対象となることを示しています。

このシンプルな変更により、386 環境でビルドする際に、アセンブリ実装が存在しない block 関数の宣言がコンパイルされることを防ぎ、結果としてビルドエラーを解消しています。386 環境では、このファイルがスキップされるため、block 関数のGo言語による純粋な実装が使用されることになります。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • SHA-512の仕様に関する公開情報
  • Go言語のビルドシステムに関する一般的な知識
  • コミットメッセージと差分情報
  • Goのソースコードリポジトリ (golang/go)
  • Go Code Review (golang.org/cl)
  • GoのIssue Tracker (golang.org/issue) (このコミットに関連するIssueが存在する可能性)