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

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

このコミットは、Go言語のコンパイラおよびリンカに関連する修正であり、特にクロスコンパイル環境における問題に対処しています。GOARCH (ターゲットアーキテクチャ) と GOHOSTARCH (ホストアーキテクチャ) が異なる場合に発生するコンパイルエラーを修正することを目的としています。具体的には、ポインタサイズ (PtrSize) の定義が、コンパイル環境とターゲット環境で適切に扱われるように変更されています。

コミット

commit 54193689ccdf51833c157d55bbbab739bf44dc3b
Author: Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
Date:   Mon Sep 17 17:18:21 2012 -0400

    cmd/ld: fix compilation when GOARCH != GOHOSTARCH
    
    R=rsc, dave, minux.ma
    CC=golang-dev
    https://golang.org/cl/6493123

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

https://github.com/golang/go/commit/54193689ccdf51833c157d55bbbab739bf44dc3b

元コミット内容

cmd/ld: fix compilation when GOARCH != GOHOSTARCH

このコミットメッセージは、Goのリンカ (cmd/ld) が、ターゲットアーキテクチャ (GOARCH) とホストアーキテクチャ (GOHOSTARCH) が異なるクロスコンパイルのシナリオで、コンパイルエラーを起こす問題を修正したことを示しています。

変更の背景

Go言語は、異なるアーキテクチャやオペレーティングシステム向けにバイナリを生成する「クロスコンパイル」機能を強力にサポートしています。しかし、この機能を実現する上で、コンパイル時の環境(ホスト)と実行時の環境(ターゲット)の間で、特定の低レベルな定数(特にポインタのサイズなど)の解釈に齟齬が生じることがあります。

このコミットの背景にある問題は、sizeof(void*) の値が、コンパイルを実行しているホストシステムのポインタサイズを反映してしまうことにありました。Goのリンカ (cmd/ld) は、最終的なバイナリを生成する際に、ターゲットアーキテクチャのポインタサイズを正確に知る必要があります。もしホストとターゲットのアーキテクチャが異なる場合(例: 64ビットのLinuxマシンで32ビットのARMバイナリをビルドする場合)、sizeof(void*) はホストの64ビットポインタサイズ(8バイト)を返しますが、リンカが必要とするのはターゲットの32ビットポインタサイズ(4バイト)です。この不一致がコンパイルエラーや不正なバイナリ生成の原因となっていました。

この問題を解決するため、リンカが自身のコンテキストで定義する PtrSize というシンボルを優先的に使用するように変更し、sizeof(void*) の直接的な使用を避ける必要がありました。

前提知識の解説

  • クロスコンパイル (Cross-compilation): あるコンピュータシステム(ホスト)上で、それとは異なるアーキテクチャやOSを持つ別のコンピュータシステム(ターゲット)向けの実行可能ファイルを生成するプロセスです。Go言語は、環境変数 GOOS (ターゲットOS) と GOARCH (ターゲットアーキテクチャ) を設定することで、簡単にクロスコンパイルが可能です。
  • GOARCH: Goプログラムが実行されるターゲットのCPUアーキテクチャを指定する環境変数です(例: amd64, arm, 386)。
  • GOHOSTARCH: Goコンパイラやツールチェインが実行されているホストのCPUアーキテクチャを指定する環境変数です。通常は GOARCH と同じですが、クロスコンパイル時には異なります。
  • cmd/ld: Go言語のリンカです。コンパイラによって生成されたオブジェクトファイルを結合し、最終的な実行可能バイナリを生成する役割を担います。リンカは、ターゲットアーキテクチャのメモリレイアウトやポインタサイズなどの詳細を正確に把握している必要があります。
  • sizeof(void*): C言語の演算子で、void 型ポインタのサイズをバイト単位で返します。この値は、コンパイルを実行しているシステムのアーキテクチャ(ホストアーキテクチャ)に依存します。
  • PtrSize: Goのランタイムやツールチェイン内部で使われる、ポインタのサイズを表す定数です。クロスコンパイルの文脈では、この値はターゲットアーキテクチャのポインタサイズを正確に反映している必要があります。

技術的詳細

このコミットの技術的な核心は、Goのランタイムコード内でポインタサイズを定義する際に、ホストアーキテクチャに依存する sizeof(void*) の使用を避け、リンカがターゲットアーキテクチャに基づいて設定する PtrSize というシンボルを優先的に使用するように変更した点にあります。

具体的な変更は以下の通りです。

  1. src/pkg/runtime/mgc0.c から PtrSize の定義を削除: mgc0.c はGoのガベージコレクタの一部であり、以前はここで PtrSize = sizeof(void*); と定義されていました。この定義は、mgc0.c がコンパイルされるホスト環境のポインタサイズに依存していました。

  2. src/pkg/runtime/runtime.hPtrSize の定義を移動: PtrSize = sizeof(void*); の定義が runtime.h に移動されました。runtime.h はGoのランタイムの様々な部分でインクルードされるヘッダファイルです。この移動自体は、直接的なクロスコンパイルの問題を解決するものではありませんが、次のステップと組み合わさることで効果を発揮します。

  3. src/pkg/runtime/typekind.hPtrSize を使用し、クロスコンパイルに関するコメントを追加: これが最も重要な変更点です。

    • typekind.h は、Goの型システムにおける型の種類やサイズに関する定義を含んでいます。特に、CommonSize の計算に sizeof(void*) が使われていました。
    • このコミットでは、CommonSize の計算を 2*sizeof(void*) + 6*sizeof(void*) + 8 から 2*PtrSize + 6*PtrSize + 8 に変更しました。
    • さらに、以下の重要なコメントが追加されました:
      // PtrSize vs sizeof(void*): This file is also included from src/cmd/ld/...
      // which defines PtrSize to be different from sizeof(void*) when crosscompiling.
      
      このコメントは、typekind.h がリンカ (src/cmd/ld) からもインクルードされることを明示しています。リンカはクロスコンパイル時に、ターゲットアーキテクチャのポインタサイズを正確に反映した PtrSize を独自に定義します。これにより、typekind.h がリンカのコンテキストでコンパイルされる際には、リンカが定義した正しい PtrSize が使用され、ホストの sizeof(void*) との不一致が解消されます。

この一連の変更により、Goのツールチェインは、クロスコンパイル時でもターゲットアーキテクチャのポインタサイズを正確に認識し、それに基づいてバイナリを生成できるようになりました。

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

src/pkg/runtime/mgc0.c

--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -11,7 +11,6 @@
 
 enum {
 	Debug = 0,
-	PtrSize = sizeof(void*),
 	DebugMark = 0,  // run second pass to check mark
 	DataBlock = 8*1024,

enum 定義から PtrSize = sizeof(void*), の行が削除されました。

src/pkg/runtime/runtime.h

--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -118,6 +118,10 @@ enum
 	true	= 1,
 	false	= 0,
 };
+enum
+{
+\tPtrSize = sizeof(void*),
+};
 
 /*
  * structures

新しい enum ブロックが追加され、その中に PtrSize = sizeof(void*), が定義されました。これにより、PtrSize の定義が runtime.h に集約されました。

src/pkg/runtime/typekind.h

--- a/src/pkg/runtime/typekind.h
+++ b/src/pkg/runtime/typekind.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// PtrSize vs sizeof(void*): This file is also included from src/cmd/ld/...
+// which defines PtrSize to be different from sizeof(void*) when crosscompiling.
+
 enum {
 	KindBool = 1,
 	KindInt,
@@ -33,6 +36,6 @@ enum {\n \tKindNoPointers = 1<<7,\n \n \t// size of Type interface header + CommonType structure.\n-\tCommonSize = 2*sizeof(void*) + 6*sizeof(void*) + 8,\n+\tCommonSize = 2*PtrSize + 6*PtrSize + 8,\n };\n \n```
クロスコンパイル時の `PtrSize` と `sizeof(void*)` の違いに関する重要なコメントが追加されました。
`CommonSize` の計算式が `sizeof(void*)` から `PtrSize` を使用するように変更されました。

## コアとなるコードの解説

このコミットの核心は、Goのランタイムが内部的に使用するポインタサイズ (`PtrSize`) の定義と利用方法を改善し、クロスコンパイル時の正確性を保証することにあります。

1.  **`PtrSize` の定義の一元化と移動**:
    以前は `src/pkg/runtime/mgc0.c` のような特定のランタイムファイル内で `PtrSize = sizeof(void*);` と定義されていました。これは、そのファイルがコンパイルされるホスト環境のポインタサイズに依存していました。このコミットでは、この定義を `src/pkg/runtime/runtime.h` に移動しました。`runtime.h` はGoランタイムの多くの部分でインクルードされるため、`PtrSize` の定義がより中央集権的になりました。

2.  **リンカ (`cmd/ld`) との連携**:
    最も重要な変更は `src/pkg/runtime/typekind.h` で行われました。このファイルはGoの型情報に関する重要な定数を含んでおり、Goのリンカ (`cmd/ld`) もこのファイルをインクルードして型情報を処理します。
    *   クロスコンパイル時、リンカはターゲットアーキテクチャのポインタサイズを正確に知る必要があります。リンカは、自身のコンテキストで `PtrSize` というシンボルを、ターゲットアーキテクチャのポインタサイズとして定義します。
    *   以前のコードでは、`typekind.h` 内の `CommonSize` の計算に `sizeof(void*)` が直接使用されていました。これは、`typekind.h` がリンカのコンテキストでコンパイルされる場合でも、ホストの `sizeof(void*)` を参照してしまう問題がありました。
    *   このコミットでは、`CommonSize` の計算を `PtrSize` を使用するように変更しました。これにより、`typekind.h` がリンカによってコンパイルされる際には、リンカが定義したターゲットアーキテクチャの `PtrSize` が正しく使用されるようになります。
    *   追加されたコメント `// PtrSize vs sizeof(void*): This file is also included from src/cmd/ld/... which defines PtrSize to be different from sizeof(void*) when crosscompiling.` は、このメカニズムを明確に説明しています。

この修正により、Goのビルドシステムは、ホストとターゲットのアーキテクチャが異なる場合でも、ポインタサイズに関する正確な情報を共有し、正しいバイナリを生成できるようになりました。これは、Goのクロスコンパイル機能の堅牢性を高める上で重要な改善です。

## 関連リンク

*   Go言語のクロスコンパイルに関する公式ドキュメントやブログ記事:
    *   [Go Modules and Cross-Compilation](https://go.dev/doc/go1.11#modules) (Go 1.11以降のモジュールとクロスコンパイルに関する情報)
    *   [Go Cross Compilation](https://www.digitalocean.com/community/tutorials/how-to-build-go-executables-for-multiple-platforms-on-ubuntu-16-04) (一般的なクロスコンパイルのチュートリアル)
*   Goのツールチェイン (`cmd/ld` など) の内部構造に関する情報:
    *   [Go Compiler and Linker](https://go.dev/doc/articles/go_command) (Goコマンドの概要)
    *   [Go Internals](https://go.dev/doc/articles/go_internals) (Goの内部構造に関するより深い情報)

## 参考にした情報源リンク

*   Go言語のソースコード (特に `src/pkg/runtime` および `src/cmd/ld` ディレクトリ)
*   Go言語の公式ドキュメント
*   Goコミュニティの議論 (golang-devメーリングリストなど)
*   C言語の `sizeof` 演算子に関する一般的な知識
*   クロスコンパイルに関する一般的なソフトウェア開発の知識