[インデックス 18786] ファイルの概要
このコミットは、Goコンパイラのcmd/cc
、cmd/5c
、cmd/6c
、cmd/8c
ツールチェーンにlinkarchinit
関数を導入し、特にnacl/amd64p32
アーキテクチャのサポートを追加するものです。これにより、Goコンパイラが特定の環境(Google Native Clientのamd64p32
)向けにビルドされる際に、適切なリンカモデル(amd64p32
)を動的に選択できるようになります。
コミット
- コミットハッシュ:
d4896fb8766f8b7ac37ba421fbfbffb0f56ee8d4
- Author: Dave Cheney dave@cheney.net
- Date: Fri Mar 7 09:55:59 2014 +1100
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d4896fb8766f8b7ac37ba421fbfbffb0f56ee8d4
元コミット内容
cmd/cc, cmd/5c, cmd/6c, cmd/8c: introduce linkarchinit and add amd64p32 support
Replaces CL 70000043.
Introduce linkarchinit() from cmd/ld.
For cmd/6c, switch to the amd64p32 linker model if we are building under nacl/amd64p32.
LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/72010043
変更の背景
このコミットの主な背景は、Go言語がGoogle Native Client (NaCl) プラットフォームをサポートする取り組みの一環として、amd64p32
という特定のアーキテクチャに対応する必要があったことです。
Goコンパイラは、異なるターゲットアーキテクチャ(例: amd64
, 386
)やオペレーティングシステム(例: linux
, windows
, nacl
)向けにコードを生成します。それぞれの組み合わせには、特定のリンカモデルやデータ構造のサイズ(ポインタのサイズなど)が関連付けられています。
nacl/amd64p32
は、64ビットの命令セットを使用しながらも、ポインタやint
/uint
型が32ビットであるという特殊なモデルです。これは、64ビットのレジスタや演算能力を活用しつつ、メモリフットプリントを削減したい場合に有効でした。このコミット以前は、Goコンパイラがnacl/amd64p32
環境でビルドされる際に、適切なリンカモデルを動的に選択するメカニズムが不足していました。
linkarchinit
関数の導入は、コンパイラの初期化段階で現在のターゲットアーキテクチャ(GOARCH
環境変数で指定される)をチェックし、必要に応じてamd64p32
リンカモデルに切り替えるための汎用的な方法を提供します。これにより、Goコンパイラがnacl/amd64p32
環境で正しく動作し、効率的なコードを生成できるようになります。
なお、Go言語におけるNaClサポートは、Go 1.14以降で廃止されています。これは、NaCl自体の利用が減少したことや、WebAssemblyなどの新しい技術が登場したことによるものです。しかし、このコミットは当時のGo言語のクロスコンパイル戦略と、特定のニッチな環境への対応を示す重要な歴史的変更点と言えます。
前提知識の解説
このコミットを理解するためには、以下の概念について知っておく必要があります。
-
Goコンパイラのツールチェーン (
cmd/cc
,cmd/5c
,cmd/6c
,cmd/8c
):- Go言語の初期のコンパイラは、Plan 9 Cコンパイラをベースにしていました。
cmd/cc
はC言語のフロントエンドで、GoのコンパイラがCコードを処理する際に使用されました。cmd/5c
はARMアーキテクチャ(GOARCH=arm
)向けのCコンパイラです。cmd/6c
はAMD64アーキテクチャ(GOARCH=amd64
)向けのCコンパイラです。cmd/8c
は386アーキテクチャ(GOARCH=386
)向けのCコンパイラです。- これらのツールは、Goのソースコードをアセンブリに変換する過程で重要な役割を果たしていました。
-
Google Native Client (NaCl):
- Googleが開発したサンドボックス技術で、ウェブブラウザ内でコンパイルされたC/C++コードを安全かつ高速に実行することを目的としていました。
- ウェブアプリケーションがネイティブコードを実行できるようにすることで、パフォーマンスと機能の向上を目指しました。
- Go言語は、かつてNaClプラットフォームへの実験的なサポートを提供していました。
-
amd64p32
アーキテクチャ:amd64p32
は、NaCl環境でGoがサポートしていた特定のアーキテクチャの一つです。amd64
は64ビットのx86命令セットを指します。p32
は「32ビットポインタ」を意味します。つまり、64ビットの命令セットを使用するものの、アドレス空間は4GBに制限され、ポインタやint
/uint
型は32ビットサイズになります。- このモデルは、64ビットのレジスタと演算能力の恩恵を受けつつ、ポインタサイズが小さくなることでメモリ使用量を削減できるという利点がありました。
-
LinkArch
構造体:- Goコンパイラの内部で、特定のアーキテクチャのリンカに関する情報(例: ポインタサイズ、アラインメント要件など)をカプセル化するために使用される構造体です。
linkamd64
は標準のAMD64アーキテクチャのリンカ設定を、linkamd64p32
はamd64p32
アーキテクチャのリンカ設定をそれぞれ表します。
-
getgoarch()
関数:- Goのビルドシステムが設定する
GOARCH
環境変数の値を取得する関数です。これにより、現在のターゲットアーキテクチャをプログラム的に判別できます。
- Goのビルドシステムが設定する
技術的詳細
このコミットの技術的な核心は、Goコンパイラの初期化プロセスにlinkarchinit()
という新しい関数を導入し、これを通じてnacl/amd64p32
という特殊なリンカモデルを動的に選択できるようにした点にあります。
以前のGoコンパイラでは、thelinkarch
というグローバル変数が、コンパイルターゲットのアーキテクチャに応じたLinkArch
構造体へのポインタとして静的に初期化されていました(例: src/cmd/6c/txt.c
ではlinkamd64
、src/cmd/8c/txt.c
ではlink386
)。しかし、amd64p32
のような、同じamd64
命令セットを使用しながらもポインタサイズが異なるような特殊なケースに対応するためには、より柔軟なメカニズムが必要でした。
linkarchinit()
関数は、コンパイラのmain
関数内でcinit()
(コンパイラの初期化処理)の前に呼び出されるように設計されています。この関数は、getgoarch()
を呼び出して現在のGOARCH
環境変数の値を取得し、それが"amd64p32"
であるかどうかをチェックします。もし"amd64p32"
であれば、thelinkarch
グローバル変数を&linkamd64p32
に設定し直します。これにより、以降のコンパイルおよびリンク処理でamd64p32
の特性(特に32ビットポインタ)が正しく考慮されるようになります。
また、src/cmd/cc/lex.c
のmain
関数内では、amd64p32
の場合にewidth[TIND]
(ポインタの幅)を4バイトに設定する既存のロジックが、getgoarch()
の戻り値ではなく、より汎用的なp
変数(getgoarch()
の結果を格納)を使用するように変更されています。これは、コードの一貫性を保ち、linkarchinit()
が設定するthelinkarch
と連携して、ポインタサイズに関する設定が正しく行われるようにするためです。
src/cmd/8c/txt.c
(386コンパイラ)では、linkarchinit()
が導入されていますが、その実装は空です。これは、amd64p32
が386アーキテクチャとは直接関係ないため、386コンパイラでは特別なリンカモデルの切り替えが不要であることを示しています。しかし、将来的な拡張性やコードの統一性のために、関数自体は定義されています。
この変更により、Goコンパイラは、ビルド環境のGOARCH
設定に基づいて、適切なリンカモデルを動的に選択できるようになり、nacl/amd64p32
のような特殊なターゲット環境への対応が強化されました。
コアとなるコードの変更箇所
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
index 61b333c1cb..f308aff08c 100644
--- a/src/cmd/6c/txt.c
+++ b/src/cmd/6c/txt.c
@@ -30,11 +30,18 @@
#include "gc.h"
-LinkArch *thelinkarch = &linkamd64;
-
int thechar = '6';
char *thestring = "amd64";
+LinkArch *thelinkarch = &linkamd64;
+
+void
+linkarchinit(void)
+{
+ if(strcmp(getgoarch(), "amd64p32") == 0)
+ thelinkarch = &linkamd64p32;
+}
+
void
ginit(void)
{
diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c
index 8a38955459..1b6c2e6d96 100644
--- a/src/cmd/8c/txt.c
+++ b/src/cmd/8c/txt.c
@@ -30,11 +30,17 @@
#include "gc.h"
-LinkArch *thelinkarch = &link386;
-
int thechar = '8';
char *thestring = "386";
+LinkArch *thelinkarch = &link386;
+
+void
+linkarchinit(void)
+{
+}
+
void
ginit(void)
{
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
index 726364ce94..c8aac12530 100644
--- a/src/cmd/cc/cc.h
+++ b/src/cmd/cc/cc.h
@@ -795,6 +795,7 @@ int32 exreg(Type*);
int32 align(int32, Type*, int, int32*);
int32 maxround(int32, int32);
int hasdotdotdot(void);
+void linkarchinit(void);
extern schar ewidth[];
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
index f6025d2807..a8ece212f0 100644
--- a/src/cmd/cc/lex.c
+++ b/src/cmd/cc/lex.c
@@ -124,7 +124,7 @@ main(int argc, char *argv[])
p = getgoarch();
if(strncmp(p, thestring, strlen(thestring)) != 0)
sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
- if(strcmp(getgoarch(), "amd64p32") == 0) // must be before cinit
+ if(strcmp(p, "amd64p32") == 0) // must be before cinit
ewidth[TIND] = 4;
nacl = strcmp(getgoos(), "nacl") == 0;
@@ -133,6 +133,7 @@ main(int argc, char *argv[])
quotefmtinstall(); // before cinit, which overrides %Q
+ linkarchinit();
ctxt = linknew(thelinkarch);\n
ctxt->diag = yyerror;\n
ctxt->bso = &bstdout;\n
コアとなるコードの解説
このコミットでは、主に以下のファイルが変更されています。
-
src/cmd/6c/txt.c
:LinkArch *thelinkarch = &linkamd64;
の宣言が、linkarchinit
関数の定義の前に移動されました。これは、linkarchinit
がthelinkarch
を変更できるようにするためです。linkarchinit()
関数が新しく追加されました。この関数は、getgoarch()
で現在のターゲットアーキテクチャを取得し、それが"amd64p32"
である場合に、グローバル変数thelinkarch
を&linkamd64p32
に設定します。これにより、amd64p32
環境でのコンパイル時に適切なリンカモデルが選択されるようになります。
-
src/cmd/8c/txt.c
:src/cmd/6c/txt.c
と同様に、LinkArch *thelinkarch = &link386;
の宣言が移動されました。linkarchinit()
関数が追加されましたが、その実装は空です。これは、amd64p32
が386アーキテクチャとは直接関係ないため、386コンパイラでは特別なリンカモデルの切り替えが不要であることを示しています。しかし、関数シグネチャを統一し、将来的な拡張性を考慮して定義されています。
-
src/cmd/cc/cc.h
:linkarchinit()
関数のプロトタイプ宣言void linkarchinit(void);
が追加されました。これにより、他のコンパイラソースファイルからこの関数を呼び出すことができるようになります。
-
src/cmd/cc/lex.c
:main
関数内で、ewidth[TIND] = 4;
を設定する条件がstrcmp(getgoarch(), "amd64p32") == 0
からstrcmp(p, "amd64p32") == 0
に変更されました。ここでp
はgetgoarch()
の戻り値を格納するローカル変数です。これは機能的な変更ではなく、コードの一貫性を高めるためのリファクタリングです。- 最も重要な変更は、
linkarchinit();
の呼び出しがmain
関数内に追加されたことです。この呼び出しは、ctxt = linknew(thelinkarch);
(リンカコンテキストの初期化)の直前に行われます。これにより、リンカコンテキストが作成される前にthelinkarch
が正しく設定され、amd64p32
環境でのポインタサイズなどの特性が適切に反映されることが保証されます。
これらの変更により、Goコンパイラは、nacl/amd64p32
のような特殊なターゲットアーキテクチャに対して、より正確で効率的なコードを生成できるようになりました。
関連リンク
- Go CL 72010043: https://golang.org/cl/72010043
参考にした情報源リンク
- go.dev: Go and NaCl context: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHSvO5uFXKWwTwSUkMKo2_WpCuXADs7FhaybdbPkOr4VUS8wSJaOOHOjRwFxXmmDLmYatyzj6tPNf5s8-jnXnEUSUJd5wTQjy8lZ8fFvIuR4QeLOaiFOQBPaxYgn74i-s6ik8i7jcsI1CJxNa4p
- stackoverflow.com: amd64p32 explanation: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQG8MbgHWeHxdDJHPdyWsf4YYtR0fYR_WW7NOUWCrBNrwUU0vioB8awH8sPqLoWZzYhPRPXP80py-JWqXqcKjemKasWBO_sJY4wYOwGDmgfRmudZDho0SDasvY3gI_f3XHELaQXB7kGrpuRTw3BJ_f1LIvLr2DZbHhBSqBcMQeRr5kcInKBu1LlpQvbMowqBF4Q4AU0gbAlxIJbA340TVqyaP0ExKIpFhrLyTWw=
- github.com: NaCl support dropped from Go: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGnwUMEVjqNLvMs5KkeOhL49cVlWQ2W2o4H0FczFvxfQLYz67Bff-8HnNFclrORZomcQi_t5-d40ZJslIvg48gHzGfIFXDV8BMNnZwNpXjdAyotM02q26IZjA6V9C7RlPIfPtmNTvyQ7LXWAdDWzybaFD3ayW7GMNV-vmfXig==
- google.com: amd64p32 benefits: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFkmXi6xDr8M34Ku1G_unXgwvJAzRtrugipJkRr6y5FiZq14Lk5wDq5J_LZsbO6bWqKKuS5qwC6YPKChvFSw1oo9fQ3iL0KGscCfQju0AyeI8s1766keuetyZBK2VGUnYfPyGJ9waIdG214d_Wsiw==
- utoronto.ca: amd64 definition: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEaFgj_vmYT5jQhZHUpqTzAM1fnqYXT30VQXqEx6FD3Hwr9RVZp4NFfROSjKaZ4x8TdvbylTDRAUKAJKRz0Y4pUc_QxFJd4XuDGuz1XmeMAfb4pcZSRqC1y9jtX5-xRMtwuLXhBotOfKuJIqPkVUX1zNGZL6i2yofK2-OIPja9ZKTI7zKHmAUH5
- github.com: golang.org/x/crypto/nacl: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFFho415v4SNhsnNJcmCdyat7XgknljoCCFfAaSz3JBmwG5coIVc51Tlq0ZZilsm9aKTDmFhhvq-ENqzJzLSi2StRV5uPl9oW_3WQC5BmMPzDsFam_ulLMqd2bVtg==
- go.dev: golang.org/x/crypto/nacl documentation: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHn1nSoUf2HXWyO7E4iAiQ5-vbBhWnOHki0MeQMk1drEHQhpvUKP0maAjSM2OjGh1DsQPV0IwEvxO69hhxK1FnV7CwrWQ03tYKWf0bTdg3a9NCmHCVN_nUnncw7SmEnVxtwlJXx9Q==
- reddit.com: golang.org/x/crypto/nacl vs Go runtime NaCl: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFB7CHPvQ9kS8kiU57oO2GXpS6f6YPo6l9DH87JP2AAqSokkiGxspXJHPldcJwJ-4GC_q7VuWE798aGku8X00VgA0ax5qcddpFKF3uEFxQszGucbsLnFiVUW4_405dfdZLvuqhWJJsMJljqHF59aSFYnyOZvvjUXu6ssVnuq9JBsqq_05xTcsCBymyRn2eqmwgO7l5L0DT1CfI=