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

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

このコミットは、Goコンパイラの一部であるcmd/6a(amd64アーキテクチャ用アセンブラ)に、nacl/amd64p32ターゲットのサポートを追加するものです。具体的には、nacl/amd64p32環境でビルドする際に、amd64p32リンカモデルを使用するように変更を加えています。

コミット

commit e509bbc943e817317e4db04b48f2895bec712c2f
Author: Dave Cheney <dave@cheney.net>
Date:   Fri Mar 7 16:02:25 2014 +1100

    cmd/6a: add support for nacl/amd64p32
    
    Replaces CL 70000043.
    
    Switch to the amd64p32 linker model if we are building under nacl/amd64p32.
    
    No need to introduce linkarchinit() as 6a contains its own main() function.
    
    LGTM=rsc
    R=rsc, minux.ma
    CC=golang-codereviews
    https://golang.org/cl/72020043

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

https://github.com/golang/go/commit/e509bbc943e817317e4db04b48f2895bec712c2f

元コミット内容

cmd/6a: nacl/amd64p32のサポートを追加。

CL 70000043を置き換える。

nacl/amd64p32でビルドしている場合、amd64p32リンカモデルに切り替える。

6aは独自のmain()関数を含んでいるため、linkarchinit()を導入する必要はない。

変更の背景

このコミットは、GoコンパイラがGoogle Native Client (NaCl) 環境のamd64p32アーキテクチャを正しくサポートするために行われました。以前の変更(CL 70000043)を置き換え、より適切な方法でnacl/amd64p32のリンカモデルを適用しています。

nacl/amd64p32は、64ビットのAMD64命令セットを使用しながら、32ビットのポインタと32ビットのint/uint型を持つ特殊なメモリモデルを特徴としていました。Goコンパイラがこの特定の環境向けにバイナリを生成するためには、リンカがこのメモリモデルを認識し、それに合わせて動作する必要がありました。このコミットは、cmd/6a(Goのamd64アセンブラ/リンカの一部)が、GOARCH=amd64p32の場合に適切なリンカ設定を適用するように修正することで、この要件を満たしています。

前提知識の解説

  • cmd/6a: Goツールチェーンの一部で、AMD64アーキテクチャ向けのアセンブラおよびリンカのフロントエンドです。Goのソースコードがコンパイルされると、最終的な実行可能ファイルを生成するためにこのツールが使用されます。
  • nacl/amd64p32: Google Native Client (NaCl) は、ウェブブラウザ内でネイティブコードを安全に実行するためのサンドボックス技術です。nacl/amd64p32は、NaClがサポートしていた特定のアーキテクチャターゲットの一つで、64ビットの命令セットを持ちながら、32ビットのポインタサイズを持つという特徴がありました。これは、メモリ効率とアドレス空間のバランスを取るための設計でした。
  • amd64p32 linker model: amd64p32アーキテクチャに特化したリンカの動作モデルです。通常の64ビットシステムとは異なり、ポインタが32ビット幅であるため、リンカはアドレス解決やシンボル配置においてこの制約を考慮する必要があります。
  • linknew: Goのリンカ内部で使用される関数で、新しいリンカコンテキスト(LinkCtxt)を初期化します。この関数は、ターゲットアーキテクチャに応じたリンカ設定(LinkArch)を受け取ります。
  • LinkArch: リンカが特定のアーキテクチャ(例: amd64, arm, amd64p32など)で動作するために必要な情報(レジスタセット、命令セット、ポインタサイズなど)をカプセル化した構造体です。
  • GOARCH: Goの環境変数の一つで、ビルドターゲットのアーキテクチャを指定します。例えば、GOARCH=amd64は64ビットIntel/AMDアーキテクチャを、GOARCH=amd64p32amd64p32アーキテクチャを意味します。
  • main()関数: C言語やGo言語などのプログラムのエントリポイントとなる関数です。cmd/6aはそれ自体が独立した実行可能プログラムであるため、独自のmain()関数を持っています。

技術的詳細

このコミットの主要な目的は、cmd/6anacl/amd64p32環境でビルドされる際に、適切なリンカモデル(amd64p32)を使用するようにすることです。

変更前は、cmd/6amain関数内で、リンカコンテキストの初期化時に常に&linkamd64(標準のamd64リンカ設定)が使用されていました。

ctxt = linknew(&linkamd64);

このコミットでは、GOARCH環境変数の値をチェックし、それが"amd64p32"である場合に、リンカコンテキストの初期化に使用するLinkArchポインタを&linkamd64p32に切り替えるロジックが追加されました。

if(strcmp(p, "amd64p32") == 0)
    thelinkarch = &linkamd64p32;

ctxt = linknew(thelinkarch);

これにより、nacl/amd64p32向けにビルドする際に、リンカが32ビットポインタの特性を正しく処理できるようになります。また、thelinkarchというグローバル変数(LinkArch*型)が導入され、リンカの初期化時にこの変数を通じて適切なアーキテクチャ設定が渡されるようになりました。

コミットメッセージにある「No need to introduce linkarchinit() as 6a contains its own main() function.」という記述は、Goの他のツール(例えば、cmd/go)では、リンカのアーキテクチャ初期化を共通のヘルパー関数(linkarchinit()のようなもの)で行う場合がありますが、cmd/6aは独立した実行可能ファイルであり、独自のmain()関数内で直接リンカの初期化ロジックを制御できるため、そのような共通関数を導入する必要がないことを示しています。

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

--- a/src/cmd/6a/lex.c
+++ b/src/cmd/6a/lex.c
@@ -63,6 +63,8 @@ Lconv(Fmt *fp)
 	return linklinefmt(ctxt, fp);
 }
 
+LinkArch*       thelinkarch = &linkamd64;
+
 void
 main(int argc, char *argv[])
 {
@@ -72,18 +74,20 @@ main(int argc, char *argv[])
 	thechar = '6';
 	thestring = "amd64";
 
-	ctxt = linknew(&linkamd64);
-	ctxt->diag = yyerror;
-	ctxt->bso = &bstdout;
-	Binit(&bstdout, 1, OWRITE);
-	listinit6();
-	fmtinstall('L', Lconv);
-
 	// Allow GOARCH=thestring or GOARCH=thestringsuffix,
 	// but not other values.	
 	p = getgoarch();
 	if(strncmp(p, thestring, strlen(thestring)) != 0)
 		sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
+	if(strcmp(p, "amd64p32") == 0)
+		thelinkarch = &linkamd64p32;
+
+	ctxt = linknew(thelinkarch);
+	ctxt->diag = yyerror;
+	ctxt->bso = &bstdout;
+	Binit(&bstdout, 1, OWRITE);
+	listinit6();
+	fmtinstall('L', Lconv);
 
 	ensuresymb(NSYMB);
 	memset(debug, 0, sizeof(debug));

コアとなるコードの解説

  1. LinkArch* thelinkarch = &linkamd64; の追加:

    • lex.cファイルの冒頭付近に、LinkArch型へのポインタであるthelinkarchというグローバル変数が新しく宣言され、デフォルト値として標準のlinkamd64(amd64アーキテクチャのリンカ設定)で初期化されています。これは、リンカの初期化時に使用されるアーキテクチャ設定を動的に変更するための準備です。
  2. main関数内のリンカ初期化ロジックの変更:

    • 変更前は、main関数内でctxt = linknew(&linkamd64);と直接linkamd64を使用してリンカコンテキストが初期化されていました。
    • 変更後、getgoarch()関数で取得したGOARCHの値(変数pに格納)が"amd64p32"と一致するかどうかがチェックされます。
    • もし一致した場合、thelinkarchポインタは&linkamd64p32amd64p32アーキテクチャのリンカ設定)を指すように更新されます。
    • 最終的に、ctxt = linknew(thelinkarch);という行で、thelinkarchが指す先のLinkArch構造体に基づいてリンカコンテキストが初期化されます。これにより、GOARCHの値に応じて適切なリンカモデルが選択されるようになります。
    • リンカコンテキストの初期化(ctxt = linknew(...))より後の行(ctxt->diag = yyerror;など)は、ifブロックの外に移動され、GOARCHの値に関わらず共通して実行されるようになりました。これは、リンカコンテキストの初期化が完了した後に、診断関数や出力バッファの設定などを行うためです。

この変更により、GoのビルドシステムがGOARCH=amd64p32を指定してcmd/6aを呼び出した際に、amd64p32に特化したリンカの挙動が有効になり、NaCl環境向けの正しいバイナリが生成されるようになりました。

関連リンク

参考にした情報源リンク