[インデックス 17937] ファイルの概要
このコミットは、Go言語のリンカの一部である src/liblink/obj8.c
ファイルに対する変更です。このファイルは、Goのツールチェーンにおいて、386アーキテクチャ(Intel 80386互換プロセッサ)向けのオブジェクトコード生成とリンク処理に関連する部分を扱っています。特に、Plan 9オペレーティングシステム上での外部レジスタアクセスに関する問題を修正しています。
コミット
commit 52ee63f544a1dc5ef4b69a4638c99cbdfae34b42
Author: Anthony Martin <ality@pbrane.org>
Date: Mon Dec 9 18:48:44 2013 -0500
liblink: fix extern register accesses on Plan 9 (386)
R=golang-dev, 0intro, rsc
CC=golang-dev
https://golang.org/cl/39680044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/52ee63f544a1dc5ef4b69a4638c99cbdfae34b42
元コミット内容
liblink: fix extern register accesses on Plan 9 (386)
R=golang-dev, 0intro, rsc
CC=golang-dev
https://golang.org/cl/39680044
変更の背景
このコミットの背景には、Go言語のリンカ(liblink
)がPlan 9オペレーティングシステム上で386アーキテクチャをターゲットとする際に発生していた、外部(extern)レジスタアクセスに関するバグが存在していました。
Goのツールチェーンは、その設計思想においてPlan 9オペレーティングシステムの影響を強く受けています。特に、Goのアセンブリ言語はPlan 9のアセンブラに似た構文とセマンティクスを持っています。このような環境下で、特定のレジスタ(D_AX
からD_DI
など)への外部アクセスが正しく処理されない問題が発生していました。
元のコードには、この問題に対処しようとしたと思われるTODO
コメント付きのブロックが存在しましたが、それがコメントアウトされており、機能していませんでした。このコミットは、そのコメントアウトされたコードを修正し、有効化することで、Plan 9 (386) 環境での外部レジスタアクセスを正しく処理できるようにすることを目的としています。具体的には、_tos
シンボルへの参照を適切に解決することで、レジスタへの間接アクセスが正しく行われるように修正しています。
前提知識の解説
Go言語のリンカ (liblink
)
liblink
はGo言語のビルドツールチェーンにおけるリンカの役割を担っています。Goのコンパイラは、直接機械語を生成するのではなく、Goアセンブリ言語に似た中間表現(「semi-abstract instruction set」と呼ばれることもあります)を生成します。liblink
はこの中間表現を受け取り、最終的な実行可能バイナリを生成する際に、実際の機械語命令への変換(命令選択)や、シンボルの解決、ライブラリのリンクなどを行います。
Plan 9
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Go言語の設計者の一部はPlan 9の開発にも携わっており、Goのツールチェーン、特にアセンブリ言語の設計にはPlan 9の思想が色濃く反映されています。Plan 9のアセンブラは、一般的なx86アセンブラとは異なる独自の構文とレジスタの命名規則を持っています。
386アーキテクチャ
Intel 80386は、1985年にリリースされた32ビットのx86プロセッサです。このアーキテクチャは、現代のx86-64アーキテクチャの基礎を築きました。Go言語のツールチェーンは、32ビットおよび64ビットのx86アーキテクチャをサポートしており、このコミットは特に32ビット版(386)に焦点を当てています。
Goアセンブリにおけるレジスタとアドレッシングモード
Goのアセンブリ言語は、Plan 9アセンブラの影響を受けており、一般的なIntel構文とは異なる表記を使用します。
D_INDIR
: これは「間接アドレッシングモード」を示します。オペランドが直接データではなく、データが格納されているメモリのアドレスを指定することを意味します。D_GS
: x86アーキテクチャにおけるセグメントレジスタの一つであるGS
レジスタを指します。セグメントレジスタは、メモリセグメントのベースアドレスを保持するために使用されます。D_AX
,D_DI
: これらはx86アーキテクチャの汎用レジスタを指します。AX
(Accumulator Register): 演算結果を格納するためによく使われます。32ビット環境ではEAX
に対応します。DI
(Destination Index Register): 文字列操作やメモリ操作で、目的地のポインタとしてよく使われます。32ビット環境ではEDI
に対応します。 Goの内部表現では、これらのレジスタがD_AX
やD_DI
のように表現されることがあります。
ctxt->plan9tos
ctxt
はリンカのコンテキスト構造体(Link
構造体)を指します。ctxt->plan9tos
は、このコンテキスト構造体内のフィールドであり、Plan 9固有の_tos
(Top Of Stack)シンボルへの参照を保持するために使用されます。Plan 9環境では、スタックのトップを指す特定のシンボルが存在し、これへのアクセスが正しく行われる必要があります。
技術的詳細
このコミットが修正している問題は、Plan 9 (386) 環境において、外部レジスタへのアクセスが正しく行われないというものです。Goのリンカは、アセンブリコード内のレジスタアクセスを処理する際に、特定の変換や最適化を行います。特に、D_INDIR+D_GS
のような間接アドレッシングモードと、D_AX
からD_DI
までの汎用レジスタへのアクセスが組み合わされた場合に問題が発生していました。
元のコードには、このケースを処理するためのロジックがコメントアウトされた状態で存在していました。このロジックは、p->from.type == D_INDIR+D_GS
(GS
セグメントレジスタを介した間接アクセス)かつp->to.type >= D_AX && p->to.type <= D_DI
(汎用レジスタへの書き込み)という条件を満たす場合に適用されるべきものでした。
問題の核心は、この処理がplan9_tos
というグローバル変数に依存していた点です。しかし、このplan9_tos
が適切に初期化されていないか、あるいはコンテキスト固有の_tos
シンボルへの参照が正しく取得されていないために、レジスタアクセスが失敗していました。
このコミットでは、コメントアウトされていたコードを有効化し、plan9_tos
グローバル変数への直接的な依存を排除しています。代わりに、リンカのコンテキスト(ctxt
)から_tos
シンボルを動的にルックアップし、その結果をctxt->plan9tos
に格納して使用するように変更しています。これにより、_tos
シンボルへの参照が常に現在のリンクコンテキストに適切に解決され、Plan 9 (386) 環境での外部レジスタアクセスが正しく行われるようになります。
具体的には、appendp(ctxt, p)
で新しいプログラム命令(Prog
)を作成し、元の命令のfrom
オペランドを新しい命令のfrom
にコピーします。そして、新しい命令のfrom.type
をD_INDIR + p->to.type
に設定することで、レジスタへの間接アクセスを表現します。元の命令p
はAMOVL
(32ビット移動命令)に変換され、p->from.type
はD_EXTERN
(外部シンボル)に、p->from.sym
はctxt->plan9tos
に設定されます。これにより、_tos
シンボルを介したレジスタへの間接的なデータ移動が正しく行われるようになります。
コアとなるコードの変更箇所
diff --git a/src/liblink/obj8.c b/src/liblink/obj8.c
index e744abe55e..e22a1b912f 100644
--- a/src/liblink/obj8.c
+++ b/src/liblink/obj8.c
@@ -271,10 +271,11 @@ progedit(Link *ctxt, Prog *p)
}
}
}
- /* TODO
if(ctxt->headtype == Hplan9) {
if(p->from.type == D_INDIR+D_GS
&& p->to.type >= D_AX && p->to.type <= D_DI) {
+ if(ctxt->plan9tos == nil)
+ ctxt->plan9tos = linklookup(ctxt, "_tos", 0);
q = appendp(ctxt, p);
q->from = p->from;
q->from.type = D_INDIR + p->to.type;
@@ -282,11 +283,10 @@ progedit(Link *ctxt, Prog *p)
q->as = p->as;
p->as = AMOVL;
p->from.type = D_EXTERN;
- p->from.sym = plan9_tos;
+ p->from.sym = ctxt->plan9tos;
p->from.offset = 0;
}
}\n- */
}\n
static Prog*
コアとなるコードの解説
このコミットのコアとなる変更は、src/liblink/obj8.c
ファイルのprogedit
関数内にあります。
-
コメントアウトの解除: 元のコードでは、Plan 9 (386) 環境での特定のレジスタアクセスを処理するためのロジックが、
/* TODO ... */
というコメントブロックによって完全にコメントアウトされていました。このコミットでは、このコメントブロックが解除され、内部のロジックが有効化されています。 -
ctxt->plan9tos
の初期化:+ if(ctxt->plan9tos == nil) + ctxt->plan9tos = linklookup(ctxt, "_tos", 0);
これが最も重要な変更点です。以前のコメントアウトされたコードでは、
plan9_tos
というグローバル変数(またはそれに類するもの)が使われていたと推測されます。しかし、この修正では、リンカのコンテキストctxt
に属するplan9tos
フィールドを使用するように変更されています。if(ctxt->plan9tos == nil)
というチェックは、_tos
シンボルへの参照がまだ解決されていない場合にのみ、linklookup
関数を呼び出してシンボルをルックアップし、ctxt->plan9tos
に格納することを意味します。linklookup(ctxt, "_tos", 0)
は、リンカのコンテキスト内で_tos
という名前のシンボルを探し、そのシンボルへのポインタを返します。これにより、_tos
シンボルへの参照が動的に、かつコンテキストに依存して解決されるようになります。 -
p->from.sym
の変更:- p->from.sym = plan9_tos; + p->from.sym = ctxt->plan9tos;
この行は、上記の
ctxt->plan9tos
の初期化と密接に関連しています。元のコード(コメントアウトされていた部分)では、p->from.sym
がplan9_tos
というシンボルに直接設定されていました。しかし、この修正により、p->from.sym
は、現在のリンカコンテキストで適切にルックアップされた_tos
シンボルへの参照であるctxt->plan9tos
に設定されるようになりました。これにより、外部レジスタアクセスが_tos
シンボルを介して正しく行われるようになります。
この変更により、Plan 9 (386) 環境におけるGoプログラムのリンキング時に、GS
セグメントレジスタを介した間接的なレジスタアクセスが正しく処理され、実行時の問題が解消されることが期待されます。
関連リンク
このコミットは、GoのIssueトラッカーやデザインドキュメントに直接関連する特定のリンクは見つかりませんでした。しかし、Goのリンカとアセンブリに関する一般的な情報は以下のリンクで参照できます。
- Go Assembly Language: https://go.dev/doc/asm
- Go Toolchain: https://go.dev/doc/go1.2 (Go 1.2のリリースノートなど、当時のツールチェーンに関する情報)
参考にした情報源リンク
- Go Assembly Language: https://go.dev/doc/asm
- Go Toolchain: https://go.dev/doc/go1.2
- x86 Registers: https://en.wikipedia.org/wiki/X86_registers
- Plan 9 from Bell Labs: https://9p.io/plan9/
- Goのリンカに関する情報 (Web検索結果より):
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEFyvjAjvpsgE7V8ny-VDIwlCYosvVHTDl_8rlxXRnPMWROci6aYRtFSlCS9ychqK3gKHgrByAVBwbvyMAFtK_iym4uFfQsbZhnOYFzQ5cH0M49JRPQ8y20jZ0yIz3u
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHdSP3CGKyxj-XZKrUCLj3XjcbDVtHo2RyqoO6g7_j4tZaMfDKuvovWE5kWI_NdFgig3PyG-DGZNmnXy_Z8IQXayl5aWYNp88vtr1LlUxX3YSM=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGgehrN1v5Y__xQApUG-adK8qjwaiwCyRrW5mjuFDTsmt5AQcebkg73g0PE4hrWfQYHOcnadki0nA-xPo9oNFzQEyIM17RtWFsjwOUQb3aB7XGR0n02nvLkSIiXICpsOkZpzLaxADA=