[インデックス 1528] ファイルの概要
このコミットは、Go言語のリンカである6l
の挙動に関する重要な変更を導入しています。具体的には、アーカイブ(ライブラリ)からinit
関数だけのためにオブジェクトをリンクしないように修正することで、Goライブラリの振る舞いをC言語のライブラリにより近づけることを目的としています。これにより、リンカの効率性が向上し、不要なコードのリンクが避けられます。
コミット
commit a3c4faf83f1849198b5431aa050793124a2fc91d
Author: Russ Cox <rsc@golang.org>
Date: Tue Jan 20 15:36:43 2009 -0800
6l: do not link in objects from an archive just for init functions.
(makes go libraries behave more like c libraries.)
R=r
DELTA=85 (67 added, 12 deleted, 6 changed)
OCL=23133
CL=23139
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a3c4faf83f1849198b5431aa050793124a2fc91d
元コミット内容
6l
: init
関数だけのためにアーカイブからオブジェクトをリンクしないようにする。(Goライブラリの振る舞いをCライブラリにより近づける。)
変更の背景
この変更の背景には、Go言語のリンカ6l
が、ライブラリ(アーカイブファイル、.a
)に含まれるinit
関数を処理する方法に関する課題がありました。従来の挙動では、たとえそのライブラリ内の他の関数が参照されていなくても、init
関数が存在するだけで、リンカがライブラリ全体、または関連するオブジェクトファイルをリンクしてしまう可能性がありました。これは、最終的なバイナリサイズを不必要に大きくし、リンク時間を増加させる原因となります。
C言語のリンカでは、通常、ライブラリからシンボルを解決する際に、実際に参照されているシンボルを含むオブジェクトファイルのみをリンクします。init
関数のような特殊な関数であっても、それが明示的に参照されていない限り、その関数を含むオブジェクトファイル全体がリンクされることはありません。このコミットは、Goのリンカも同様の「必要なものだけをリンクする」という原則に従うように修正し、GoライブラリがCライブラリと同様の効率的なリンク挙動を示すようにすることを目的としています。
特に、Goのinit
関数はパッケージの初期化に用いられ、プログラムの起動時に自動的に実行されます。しかし、その存在がリンカに不要な依存関係を強制することは、モジュール性やバイナリサイズ最適化の観点から望ましくありませんでした。この変更により、init
関数が「オプションの関数」として扱われ、その関数を含むオブジェクトファイルが、他のシンボルによって参照されない限り、リンクの対象から外れるようになります。
前提知識の解説
1. Go言語のinit
関数
Go言語には、各パッケージが持つことができる特別な関数init
があります。
func init()
というシグネチャを持ち、引数も戻り値もありません。- 各パッケージは複数の
init
関数を持つことができます。 init
関数は、パッケージがインポートされた際に、main
関数が実行される前に自動的に実行されます。- 主に、パッケージレベルの変数の初期化、外部リソースへの接続、設定の読み込みなど、プログラムの実行開始前に一度だけ行われるべき処理に使用されます。
init
関数の実行順序は、インポートの依存関係に基づいて決定されます。
2. 6l
リンカ
6l
は、Go言語のツールチェインの一部であるリンカです。Goのソースコードはコンパイラ(例: 6g
for x86-64)によってオブジェクトファイルにコンパイルされ、その後6l
によって実行可能ファイルにリンクされます。
6l
は、Goプログラムに必要なすべてのオブジェクトファイル(コンパイルされたGoコード、標準ライブラリ、サードパーティライブラリなど)を結合し、実行可能なバイナリを生成します。- リンカの主な役割は、シンボル解決(未解決の参照を定義に結びつけること)と、最終的な実行可能ファイルのレイアウトを決定することです。
3. アーカイブファイル(.a
)とライブラリのリンク
- アーカイブファイル(
.a
): 複数のオブジェクトファイル(.o
)を一つにまとめたファイルです。Unix系のシステムでは静的ライブラリとしてよく使われます。リンカは、アーカイブファイルの中から、プログラムが参照しているシンボルを定義しているオブジェクトファイルだけを抽出してリンクします。 - 静的リンク: プログラムのコンパイル時に、必要なライブラリのコードが実行可能ファイルに直接組み込まれる方式です。これにより、実行可能ファイルは自己完結型となり、実行時に外部ライブラリを必要としません。
- シンボル解決: リンカが、プログラム内で使用されている関数や変数の名前(シンボル)を、それらが定義されている実際のメモリ上のアドレスに結びつけるプロセスです。
4. C言語のリンカの挙動
C言語のリンカ(例: ld
)は、静的ライブラリ(.a
)をリンクする際に、非常に効率的な「必要なものだけをリンクする」戦略を採用しています。
- プログラムがライブラリ内の特定の関数や変数を使用している場合のみ、その関数や変数を含むオブジェクトファイルがアーカイブから抽出され、最終的な実行可能ファイルにリンクされます。
- ライブラリ内の他のオブジェクトファイルや、参照されていない関数は、バイナリサイズを肥大化させないためにリンクされません。
技術的詳細
このコミットは、6l
リンカがinit
関数を特別に扱うためのメカニズムを導入しています。
-
isinitfunc
関数の導入:src/cmd/6l/go.c
にisinitfunc(Sym *s)
関数が追加されました。- この関数は、シンボル名にGoの内部的な
init
関数のマーカー(·Init·
または·init·
)が含まれているかどうかをチェックします。Goのコンパイラは、init
関数に対してこのような特殊なシンボル名を生成します。 - これにより、リンカは特定のシンボルが
init
関数であるかどうかを識別できるようになります。
-
SOPT
シンボルタイプの導入:src/cmd/6l/l.h
に新しいシンボルタイプSOPT
が追加されました。SOPT
は「Optional Symbol(オプションのシンボル)」を意味し、init
関数など、アーカイブから明示的に参照されなくてもリンクされるべきではない関数に割り当てられます。src/cmd/6l/obj.c
のシンボル処理ロジックが変更され、isinitfunc
が真を返すシンボルに対してSOPT
タイプが設定されるようになりました。これにより、リンカはこれらの関数を「オプション」としてマークし、特別な処理を適用します。
-
ignoreoptfuncs
関数の導入と利用:src/cmd/6l/go.c
にignoreoptfuncs()
関数が追加されました。- この関数は、リンカが生成したプログラム命令(
Prog
)を走査し、SOPT
タイプのシンボルへの呼び出し(ACALL
命令)を見つけます。 - もし
SOPT
シンボルへの呼び出しが見つかった場合、その呼び出し命令をANOP
(No Operation)命令に変換し、from
とto
のアドレス指定を無効にします。これは、SOPT
としてマークされた関数が最終的にリンクされなかった場合に、その関数への呼び出しが実行時に問題を引き起こさないようにするための措置です。 src/cmd/6l/obj.c
のmain
関数内で、definetypestrings()
やdefinetypesigs()
の前にignoreoptfuncs()
が呼び出されるようになりました。これにより、リンク処理の早い段階でオプション関数の呼び出しが処理されます。
-
newtext
関数の導入とコードの整理:src/cmd/6l/pass.c
にnewtext(Prog *p, Sym *s)
関数が追加されました。- この関数は、テキストセクション(コード)に新しいプログラム命令を追加するロジックをカプセル化します。
- 以前は
src/cmd/6l/obj.c
のATEXT
ケース内に直接記述されていた、シンボルタイプの設定、プログラムカウンタの更新、命令リストへの追加などの処理がnewtext
関数にまとめられました。これにより、コードの重複が減り、可読性と保守性が向上しました。 ATEXT
命令の処理において、シンボルがSTEXT
(通常のテキストシンボル)またはSXREF
(外部参照シンボル)であるかどうかのチェックに加えて、SOPT
であるかどうかのチェックも追加されました。これにより、SOPT
としてマークされたinit
関数が、再定義として誤って扱われることを防ぎます。
これらの変更により、6l
リンカはinit
関数を「オプション」として認識し、その関数が他のコードから明示的に参照されていない限り、その関数を含むオブジェクトファイルをアーカイブからリンクしないように動作します。これにより、Goの静的ライブラリのリンク挙動がC言語のそれにより近くなり、最終的なバイナリサイズが最適化されます。
コアとなるコードの変更箇所
src/cmd/6l/go.c
isinitfunc
関数の追加: シンボル名がinit
関数パターンに一致するかを判定。ignoreoptfuncs
関数の追加:SOPT
タイプのシンボルへの呼び出しをANOP
に変換。
src/cmd/6l/l.h
Sym
構造体にtext
フィールド(Prog*
型)を追加。enum
にSOPT
シンボルタイプを追加。ignoreoptfuncs
、deadcode
、newtext
、isinitfunc
関数のプロトタイプ宣言を追加。
src/cmd/6l/obj.c
main
関数内でignoreoptfuncs()
を呼び出すように変更。ANAME
処理において、isinitfunc(s)
が真の場合にシンボルタイプをSOPT
に設定するロジックを追加。ATEXT
処理において、シンボルがSOPT
タイプでないことを再定義チェックの条件に追加。ATEXT
処理のコード生成部分をnewtext(p, s)
呼び出しに置き換え。
src/cmd/6l/pass.c
newtext
関数の追加: テキストセクションに新しいプログラム命令を追加する共通ロジックをカプセル化。patch
関数内のdiag
メッセージをより詳細にするために、p->to.sym->name
を追加。
コアとなるコードの解説
isinitfunc
(src/cmd/6l/go.c)
int
isinitfunc(Sym *s)
{
char *p;
p = utfrune(s->name, 0xb7); // 0xb7 = '·'
if(p == nil)
return 0;
if(memcmp(p, "·Init·", 8) == 0 || memcmp(p, "·init·", 8) == 0)
return 1;
return 0;
}
この関数は、Goのinit
関数がコンパイラによって生成される際に付与される特殊なシンボル名(·Init·
または·init·
)を検出します。0xb7
はUTF-8で·
(中点)を表します。シンボル名にこの中点が含まれ、その後にInit·
またはinit·
が続く場合、そのシンボルはinit
関数であると判断されます。
ignoreoptfuncs
(src/cmd/6l/go.c)
void
ignoreoptfuncs(void)
{
Prog *p;
// nop out calls to optional functions
// that were not pulled in from libraries.
for(p=firstp; p != P; p=p->link) {
if(p->to.sym != S && p->to.sym->type == SOPT) {
if(p->as != ACALL)
diag("bad use of optional function: %P", p);
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
}
}
}
この関数は、リンカが生成した命令列(Prog
リスト)を走査します。もし命令のターゲットシンボル(p->to.sym
)がSOPT
タイプ(オプションの関数、つまりinit
関数)であり、かつその命令が関数呼び出し(ACALL
)である場合、その呼び出し命令をANOP
(何もしない命令)に変換します。これにより、もしinit
関数が最終的にリンクされなかったとしても、その関数への呼び出しが実行時にクラッシュを引き起こすことを防ぎます。
SOPT
シンボルタイプの割り当て (src/cmd/6l/obj.c)
if((v == D_EXTERN || v == D_STATIC) && s->type == 0) {
s->type = SXREF;
if(isinitfunc(s))
s->type = SOPT; // optional function; don't pull in an object file just for s.
}
オブジェクトファイルを読み込む際、外部参照(D_EXTERN
)または静的(D_STATIC
)シンボルで、まだタイプが設定されていないもの(s->type == 0
)に対して、まずSXREF
(外部参照)タイプを設定します。その上で、もしそのシンボルがisinitfunc
によってinit
関数であると識別された場合、そのタイプをSOPT
に上書きします。これにより、リンカは後続の処理でこのシンボルを「オプション」として特別に扱うようになります。
newtext
(src/cmd/6l/pass.c)
Prog*
newtext(Prog *p, Sym *s)
{
if(p == P) {
p = prg();
p->as = ATEXT;
p->from.sym = s;
}
s->type = STEXT;
s->text = p;
s->value = pc;
lastp->link = p;
lastp = p;
p->pc = pc++;
if(textp == P)
textp = p;
else
etextp->pcond = p;
etextp = p;
return p;
}
この関数は、新しいテキストセクション(コード)の命令(Prog
)を作成または初期化し、それをリンカの命令リストに追加する共通のロジックを提供します。シンボルs
のタイプをSTEXT
(テキストセクションのシンボル)に設定し、そのテキスト命令へのポインタをs->text
に格納します。また、プログラムカウンタpc
を更新し、命令をリンカの内部リストに適切に連結します。これにより、obj.c
内の重複するコードが削減され、コードの構造が改善されました。
関連リンク
- Go言語の
init
関数に関する公式ドキュメントやチュートリアル - Go言語のリンカ(
cmd/link
)のソースコード - 静的ライブラリと動的ライブラリのリンクに関する一般的な情報
参考にした情報源リンク
- Go言語の初期のリンカの挙動に関する議論(GoのメーリングリストやIssueトラッカーなど、当時の情報源)
- C言語のリンカの挙動に関する一般的な情報(例:
man ld
、リンカの仕組みに関する書籍やオンラインリソース) - Go言語のソースコード(特に
src/cmd/6l
ディレクトリ)
[インデックス 1528] ファイルの概要
このコミットは、Go言語のリンカである6l
の挙動に関する重要な変更を導入しています。具体的には、アーカイブ(ライブラリ)からinit
関数だけのためにオブジェクトをリンクしないように修正することで、Goライブラリの振る舞いをC言語のライブラリにより近づけることを目的としています。これにより、リンカの効率性が向上し、不要なコードのリンクが避けられます。
コミット
commit a3c4faf83f1849198b5431aa050793124a2fc91d
Author: Russ Cox <rsc@golang.org>
Date: Tue Jan 20 15:36:43 2009 -0800
6l: do not link in objects from an archive just for init functions.
(makes go libraries behave more like c libraries.)
R=r
DELTA=85 (67 added, 12 deleted, 6 changed)
OCL=23133
CL=23139
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a3c4faf83f1849198b5431aa050793124a2fc91d
元コミット内容
6l
: init
関数だけのためにアーカイブからオブジェクトをリンクしないようにする。(Goライブラリの振る舞いをCライブラリにより近づける。)
変更の背景
この変更の背景には、Go言語のリンカ6l
が、ライブラリ(アーカイブファイル、.a
)に含まれるinit
関数を処理する方法に関する課題がありました。従来の挙動では、たとえそのライブラリ内の他の関数が参照されていなくても、init
関数が存在するだけで、リンカがライブラリ全体、または関連するオブジェクトファイルをリンクしてしまう可能性がありました。これは、最終的なバイナリサイズを不必要に大きくし、リンク時間を増加させる原因となります。
C言語のリンカでは、通常、ライブラリからシンボルを解決する際に、実際に参照されているシンボルを含むオブジェクトファイルのみをリンクします。init
関数のような特殊な関数であっても、それが明示的に参照されていない限り、その関数を含むオブジェクトファイル全体がリンクされることはありません。このコミットは、Goのリンカも同様の「必要なものだけをリンクする」という原則に従うように修正し、GoライブラリがCライブラリと同様の効率的なリンク挙動を示すようにすることを目的としています。
特に、Goのinit
関数はパッケージの初期化に用いられ、プログラムの起動時に自動的に実行されます。しかし、その存在がリンカに不要な依存関係を強制することは、モジュール性やバイナリサイズ最適化の観点から望ましくありませんでした。この変更により、init
関数が「オプションの関数」として扱われ、その関数を含むオブジェクトファイルが、他のシンボルによって参照されない限り、リンクの対象から外れるようになります。
前提知識の解説
1. Go言語のinit
関数
Go言語には、各パッケージが持つことができる特別な関数init
があります。
func init()
というシグネチャを持ち、引数も戻り値もありません。- 各パッケージは複数の
init
関数を持つことができます。 init
関数は、パッケージがインポートされた際に、main
関数が実行される前に自動的に実行されます。- 主に、パッケージレベルの変数の初期化、外部リソースへの接続、設定の読み込みなど、プログラムの実行開始前に一度だけ行われるべき処理に使用されます。
init
関数の実行順序は、インポートの依存関係に基づいて決定されます。
2. 6l
リンカ
6l
は、Go言語のツールチェインの一部であるリンカです。Goのソースコードはコンパイラ(例: 6g
for x86-64)によってオブジェクトファイルにコンパイルされ、その後6l
によって実行可能ファイルにリンクされます。
6l
は、Goプログラムに必要なすべてのオブジェクトファイル(コンパイルされたGoコード、標準ライブラリ、サードパーティライブラリなど)を結合し、実行可能なバイナリを生成します。- リンカの主な役割は、シンボル解決(未解決の参照を定義に結びつけること)と、最終的な実行可能ファイルのレイアウトを決定することです。
3. アーカイブファイル(.a
)とライブラリのリンク
- アーカイブファイル(
.a
): 複数のオブジェクトファイル(.o
)を一つにまとめたファイルです。Unix系のシステムでは静的ライブラリとしてよく使われます。リンカは、アーカイブファイルの中から、プログラムが参照しているシンボルを定義しているオブジェクトファイルだけを抽出してリンクします。 - 静的リンク: プログラムのコンパイル時に、必要なライブラリのコードが実行可能ファイルに直接組み込まれる方式です。これにより、実行可能ファイルは自己完結型となり、実行時に外部ライブラリを必要としません。
- シンボル解決: リンカが、プログラム内で使用されている関数や変数の名前(シンボル)を、それらが定義されている実際のメモリ上のアドレスに結びつけるプロセスです。
4. C言語のリンカの挙動
C言語のリンカ(例: ld
)は、静的ライブラリ(.a
)をリンクする際に、非常に効率的な「必要なものだけをリンクする」戦略を採用しています。
- プログラムがライブラリ内の特定の関数や変数を使用している場合のみ、その関数や変数を含むオブジェクトファイルがアーカイブから抽出され、最終的な実行可能ファイルにリンクされます。
- ライブラリ内の他のオブジェクトファイルや、参照されていない関数は、バイナリサイズを肥大化させないためにリンクされません。
技術的詳細
このコミットは、6l
リンカがinit
関数を特別に扱うためのメカニズムを導入しています。
-
isinitfunc
関数の導入:src/cmd/6l/go.c
にisinitfunc(Sym *s)
関数が追加されました。- この関数は、シンボル名にGoの内部的な
init
関数のマーカー(·Init·
または·init·
)が含まれているかどうかをチェックします。Goのコンパイラは、init
関数に対してこのような特殊なシンボル名を生成します。 - これにより、リンカは特定のシンボルが
init
関数であるかどうかを識別できるようになります。
-
SOPT
シンボルタイプの導入:src/cmd/6l/l.h
に新しいシンボルタイプSOPT
が追加されました。SOPT
は「Optional Symbol(オプションのシンボル)」を意味し、init
関数など、アーカイブから明示的に参照されなくてもリンクされるべきではない関数に割り当てられます。src/cmd/6l/obj.c
のシンボル処理ロジックが変更され、isinitfunc
が真を返すシンボルに対してSOPT
タイプが設定されるようになりました。これにより、リンカはこれらの関数を「オプション」としてマークし、特別な処理を適用します。
-
ignoreoptfuncs
関数の導入と利用:src/cmd/6l/go.c
にignoreoptfuncs()
関数が追加されました。- この関数は、リンカが生成したプログラム命令(
Prog
)を走査し、SOPT
タイプのシンボルへの呼び出し(ACALL
命令)を見つけます。 - もし
SOPT
シンボルへの呼び出しが見つかった場合、その呼び出し命令をANOP
(No Operation)命令に変換し、from
とto
のアドレス指定を無効にします。これは、SOPT
としてマークされた関数が最終的にリンクされなかった場合に、その関数への呼び出しが実行時に問題を引き起こさないようにするための措置です。 src/cmd/6l/obj.c
のmain
関数内で、definetypestrings()
やdefinetypesigs()
の前にignoreoptfuncs()
が呼び出されるようになりました。これにより、リンク処理の早い段階でオプション関数の呼び出しが処理されます。
-
newtext
関数の導入とコードの整理:src/cmd/6l/pass.c
にnewtext(Prog *p, Sym *s)
関数が追加されました。- この関数は、テキストセクション(コード)に新しいプログラム命令を追加するロジックをカプセル化します。
- 以前は
src/cmd/6l/obj.c
のATEXT
ケース内に直接記述されていた、シンボルタイプの設定、プログラムカウンタの更新、命令リストへの追加などの処理がnewtext
関数にまとめられました。これにより、コードの重複が減り、可読性と保守性が向上しました。 ATEXT
命令の処理において、シンボルがSTEXT
(通常のテキストシンボル)またはSXREF
(外部参照シンボル)であるかどうかのチェックに加えて、SOPT
であるかどうかのチェックも追加されました。これにより、SOPT
としてマークされたinit
関数が、再定義として誤って扱われることを防ぎます。
これらの変更により、6l
リンカはinit
関数を「オプション」として認識し、その関数が他のコードから明示的に参照されていない限り、その関数を含むオブジェクトファイルをアーカイブからリンクしないように動作します。これにより、Goの静的ライブラリのリンク挙動がC言語のそれにより近くなり、最終的なバイナリサイズが最適化されます。
コアとなるコードの変更箇所
src/cmd/6l/go.c
isinitfunc
関数の追加: シンボル名がinit
関数パターンに一致するかを判定。ignoreoptfuncs
関数の追加:SOPT
タイプのシンボルへの呼び出しをANOP
に変換。
src/cmd/6l/l.h
Sym
構造体にtext
フィールド(Prog*
型)を追加。enum
にSOPT
シンボルタイプを追加。ignoreoptfuncs
、deadcode
、newtext
、isinitfunc
関数のプロトタイプ宣言を追加。
src/cmd/6l/obj.c
main
関数内でignoreoptfuncs()
を呼び出すように変更。ANAME
処理において、isinitfunc(s)
が真の場合にシンボルタイプをSOPT
に設定するロジックを追加。ATEXT
処理において、シンボルがSOPT
タイプでないことを再定義チェックの条件に追加。ATEXT
処理のコード生成部分をnewtext(p, s)
呼び出しに置き換え。
src/cmd/6l/pass.c
newtext
関数の追加: テキストセクションに新しいプログラム命令を追加する共通ロジックをカプセル化。patch
関数内のdiag
メッセージをより詳細にするために、p->to.sym->name
を追加。
コアとなるコードの解説
isinitfunc
(src/cmd/6l/go.c)
int
isinitfunc(Sym *s)
{
char *p;
p = utfrune(s->name, 0xb7); // 0xb7 = '·'
if(p == nil)
return 0;
if(memcmp(p, "·Init·", 8) == 0 || memcmp(p, "·init·", 8) == 0)
return 1;
return 0;
}
この関数は、Goのinit
関数がコンパイラによって生成される際に付与される特殊なシンボル名(·Init·
または·init·
)を検出します。0xb7
はUTF-8で·
(中点)を表します。シンボル名にこの中点が含まれ、その後にInit·
またはinit·
が続く場合、そのシンボルはinit
関数であると判断されます。
ignoreoptfuncs
(src/cmd/6l/go.c)
void
ignoreoptfuncs(void)
{
Prog *p;
// nop out calls to optional functions
// that were not pulled in from libraries.
for(p=firstp; p != P; p=p->link) {
if(p->to.sym != S && p->to.sym->type == SOPT) {
if(p->as != ACALL)
diag("bad use of optional function: %P", p);
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
}
}
}
この関数は、リンカが生成した命令列(Prog
リスト)を走査します。もし命令のターゲットシンボル(p->to.sym
)がSOPT
タイプ(オプションの関数、つまりinit
関数)であり、かつその命令が関数呼び出し(ACALL
)である場合、その呼び出し命令をANOP
(何もしない命令)に変換します。これにより、もしinit
関数が最終的にリンクされなかったとしても、その関数への呼び出しが実行時にクラッシュを引き起こすことを防ぎます。
SOPT
シンボルタイプの割り当て (src/cmd/6l/obj.c)
if((v == D_EXTERN || v == D_STATIC) && s->type == 0) {
s->type = SXREF;
if(isinitfunc(s))
s->type = SOPT; // optional function; don't pull in an object file just for s.
}
オブジェクトファイルを読み込む際、外部参照(D_EXTERN
)または静的(D_STATIC
)シンボルで、まだタイプが設定されていないもの(s->type == 0
)に対して、まずSXREF
(外部参照)タイプを設定します。その上で、もしそのシンボルがisinitfunc
によってinit
関数であると識別された場合、そのタイプをSOPT
に上書きします。これにより、リンカは後続の処理でこのシンボルを「オプション」として特別に扱うようになります。
newtext
(src/cmd/6l/pass.c)
Prog*
newtext(Prog *p, Sym *s)
{
if(p == P) {
p = prg();
p->as = ATEXT;
p->from.sym = s;
}
s->type = STEXT;
s->text = p;
s->value = pc;
lastp->link = p;
lastp = p;
p->pc = pc++;
if(textp == P)
textp = p;
else
etextp->pcond = p;
etextp = p;
return p;
}
この関数は、新しいテキストセクション(コード)の命令(Prog
)を作成または初期化し、それをリンカの命令リストに追加する共通のロジックを提供します。シンボルs
のタイプをSTEXT
(テキストセクションのシンボル)に設定し、そのテキスト命令へのポインタをs->text
に格納します。また、プログラムカウンタpc
を更新し、命令をリンカの内部リストに適切に連結します。これにより、obj.c
内の重複するコードが削減され、コードの構造が改善されました。
関連リンク
- Go言語の
init
関数に関する公式ドキュメントやチュートリアル - Go言語のリンカ(
cmd/link
)のソースコード - 静的ライブラリと動的ライブラリのリンクに関する一般的な情報
参考にした情報源リンク
- Go言語の初期のリンカの挙動に関する議論(GoのメーリングリストやIssueトラッカーなど、当時の情報源)
- C言語のリンカの挙動に関する一般的な情報(例:
man ld
、リンカの仕組みに関する書籍やオンラインリソース) - Go言語のソースコード(特に
src/cmd/6l
ディレクトリ) - Web search results for "Go language init function behavior linker" (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGF5s_llFIEBGh_tgOYB0UfzSd5w-BietxoO4MmaBPT7sfnhoy1juWi3GW1sbvGbO-UHYLVVxY6thUB0DUeD6F6IOgr-vE8H5QA_UddDqi2E5ALpqkpGSYocPDG00W-7VNnZj1yUB3JE07C2aknQ1Rg_kNz2p8ooWCfJqAaNYCZodzQYjYbCeO3s_DnySOYHcV_eZF8jw2VbVSoK6IDn_C_pGRqCP5b)
- medium.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEZ8ypfj7x23_3jYIKDpQ-2zAkfPxFCrVCC1BRx0334OqO-hlB6qODRFBGZsQw78X_-a6IQ_APcvNBpnd9PDaCqk3_wG0jZpQsM3fkqzXLndjcMY9V-javjHEQsLYIkFcwpEGvtyarVr-gTz6Vh2o6DX_Q7d5cB7v3jf__-tkvGmzKTb8WGg__BQLLtvPZLmxNwCN9Qvcdzll33-no3hTc=)
- tutorialedge.net (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFOqhV3poGBvLJS3uTUM15ZvyAFOs2o2BXAX7Rdq4bWlKUlyj6584s1Uq8B9Fk-tbF2z6UGFfGSGKudTGNQDcz2pWxLheE6JSLgb7KI55moztV3u-ccspUgEKlsKgguwHwt7q7k0oQMVcoChNstQ9IQ)
- digitalocean.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQE7v2sDXfiMlCuce-Mi-cV1EmTE-RxyYTjzI_yXMPuAJdCF1g5H00I9zmQB4UjQt5m2R_3H-MWZDgs05qdvzOSTxFYNdUg6CoBz4QbzeEfooyGkSx27ejJufCK2cLqu-_e-qx43qgqch4QOtl4zWsrQ40GcjwS2FAzsmWq8rLVTe2oO8WY=)
- github.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHE7OhcM0We6qUMY5ia4zeYOW5gxNwTLVjwjIET_7bBy8ekdc_951NfGWMhihCGRIEYq9RMRV6Z_bmkugMiGNGVkYthEovrnTzJs6qLr99Ungx_UVemXrlssC2Bm-QJxFDfmhFS)