[インデックス 15674] ファイルの概要
このコミットは、Go言語のリンカ (src/cmd/ld/go.c
) と、OpenBSD向けのCgoランタイム (src/pkg/runtime/cgo/gcc_openbsd_386.c
, src/pkg/runtime/cgo/gcc_openbsd_amd64.c
)、そしてテストスクリプト (src/run.bash
) に変更を加えています。主な目的は、GoとCの相互運用機能であるCgoにおいて、あるシンボルがcgo_export
とcgo_import
の両方として扱われる場合に発生する問題を解決することです。
コミット
cmd/ld, runtime/cgo: allow a symbol to be both cgo_export and cgo_import.
Fixes #4878.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7420052
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/960d7082ee9b8fda91444167b3c253d5cf5e115d
元コミット内容
commit 960d7082ee9b8fda91444167b3c253d5cf5e115d
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Mon Mar 11 14:24:51 2013 +0800
cmd/ld, runtime/cgo: allow a symbol to be both cgo_export and cgo_import.
Fixes #4878.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7420052
---
src/cmd/ld/go.c | 11 ++++++++---\n src/pkg/runtime/cgo/gcc_openbsd_386.c | 6 +++---\n src/pkg/runtime/cgo/gcc_openbsd_amd64.c | 6 +++---\n src/run.bash | 1 -\n 4 files changed, 14 insertions(+), 10 deletions(-)\n
変更の背景
このコミットは、Go言語のIssue 4878「cmd/ld: symbol is both imported and exported: _cgo_thread_start」を修正するために行われました。この問題は、特にOpenBSD環境において、Cgoを使用する際に特定のシンボル(例: _cgo_thread_start
)がGoリンカによって「インポートとエクスポートの両方」として誤って検出され、エラーとなることが原因でした。
通常、シンボルは外部からインポートされるか(cgo_import
)、外部にエクスポートされるか(cgo_export
)のいずれか一方であるべきです。しかし、OpenBSDのCgoランタイムの特定の設計や、リンカのシンボル解決ロジックの不備により、この二重の定義が検出され、リンカがエラーを発生させていました。これにより、OpenBSD上でのCgoプログラムのビルドが妨げられていました。
この問題は、GoのランタイムがCのコードを呼び出し、CのコードがGoのコードをコールバックするような複雑なCgoのシナリオで顕在化しやすかったと考えられます。リンカは、シンボルが外部ライブラリからインポートされるべきか、それともGoプログラム自身が提供するべきかについて明確な判断ができず、矛盾として扱っていました。
前提知識の解説
Go言語のCgo
Cgoは、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりするためのGoの機能です。これにより、既存のCライブラリをGoから利用したり、パフォーマンスが重要な部分をCで記述したりすることが可能になります。
Cgoを使用する際、Goのビルドプロセスは以下のようになります。
- Goのソースコード内の
import "C"
ブロックを解析し、Cのコードを抽出します。 - Cのコンパイラ(通常はGCC)を使用して、抽出されたCのコードをコンパイルします。
- GoのコンパイラはGoのコードをコンパイルします。
- Goリンカ(
cmd/ld
)は、コンパイルされたGoのオブジェクトファイルとCのオブジェクトファイルをリンクし、最終的な実行可能ファイルを生成します。この際、GoとCの間でやり取りされるシンボル(関数や変数)の解決が行われます。
cgo_export
とcgo_import
Cgoにおいて、GoとCの間でシンボルをやり取りするために、特別なディレクティブが使用されます。
cgo_export
: Goの関数や変数をCのコードから呼び出せるように、外部にエクスポートする際に使用されます。Goのコードで//export MyGoFunction
のように記述すると、MyGoFunction
というGoの関数がCから呼び出し可能なシンボルとしてエクスポートされます。cgo_import
: Cの関数や変数をGoのコードから呼び出せるように、外部からインポートする際に使用されます。Goのコードでimport "C"
ブロック内にCの関数宣言を記述すると、その関数は外部のCライブラリからインポートされるシンボルとして扱われます。
リンカは、これらのcgo_export
およびcgo_import
の情報を基に、GoとCのオブジェクトファイル間でシンボルを正しく解決します。
Goリンカ (cmd/ld
)
cmd/ld
はGo言語のリンカであり、コンパイルされたGoのオブジェクトファイルと、Cgoによって生成されたCのオブジェクトファイル、およびその他のライブラリを結合して実行可能ファイルを生成する役割を担っています。リンカは、プログラム内のすべてのシンボル参照を解決し、それぞれのシンボルがどこで定義されているかを特定します。
Thread Local Storage (TLS)
Thread Local Storage (TLS) は、各スレッドが独自のデータコピーを持つことを可能にするメカニズムです。これにより、グローバル変数のようにアクセスできるが、実際にはスレッドごとに独立した値を持つ変数を定義できます。Cgoのコンテキストでは、GoランタイムとCランタイムがスレッド固有の情報を管理するためにTLSを使用することがあります。OpenBSDのような特定のOSでは、TLSのサポートが他のOSと異なる場合があり、それがCgoランタイムの複雑さや問題の原因となることがあります。
技術的詳細
このコミットの技術的詳細は、主にGoリンカのシンボル解決ロジックと、OpenBSDにおけるCgoランタイムの特殊性に起因します。
リンカのシンボル解決の競合
Goリンカは、loadcgo
関数内でCgo関連のシンボルを処理します。以前のリンカのロジックでは、あるシンボルが既にdynimplib
(動的インポートライブラリ)を持つ、つまり外部からインポートされるシンボルとしてマークされているにもかかわらず、cgo_export
としても定義されようとすると、これをエラーとして扱っていました。
if(s->dynimplib != nil) {
fprintf(2, "%s: symbol is both imported and exported: %s\\n", argv0, local);
nerrors++;
}
このロジックは、一般的なケースではシンボル定義の矛盾を検出するのに役立ちますが、OpenBSDのCgoランタイムの特定のシナリオでは問題を引き起こしました。OpenBSDのCgoランタイムは、GoランタイムがCのコードを呼び出し、そのCのコードがGoのランタイムの一部(例えば、スレッドの初期化に関連する関数)をコールバックするような、より複雑な相互作用を必要とすることがあります。この際、特定のシンボル(例: _cgo_thread_start
)が、Go側からCにエクスポートされると同時に、C側からGoにインポートされるかのようにリンカに認識されてしまうことがありました。これは、シンボルが実際に二重に定義されているわけではなく、リンカの視点から見た「インポート」と「エクスポート」の解釈が、OpenBSDのCgoの特殊なフローと合致しなかったためです。
修正アプローチ:「エクスポートがインポートを上書きする」
このコミットの主要な修正は、リンカのloadcgo
関数において、シンボルが既にインポートされているとマークされていても、それがcgo_export
として定義されようとする場合に、既存のインポート情報をクリアし、エクスポートを優先させるというロジックを追加したことです。
// export overrides import, for openbsd/cgo.
// see issue 4878.
if(s->dynimplib != nil) {
s->dynimplib = nil;
s->extname = nil;
s->dynimpvers = nil;
s->type = 0;
}
この変更により、リンカは「このシンボルは外部からインポートされるものだが、Go自身がエクスポートするものとしても定義されている。この場合はGoのエクスポートを優先しよう」と判断するようになります。これにより、OpenBSDのCgoランタイムが内部的に必要とするシンボルが、リンカによって矛盾として扱われることなく、正しく解決されるようになりました。
OpenBSD Cgoランタイムの変更
src/pkg/runtime/cgo/gcc_openbsd_386.c
および src/pkg/runtime/cgo/gcc_openbsd_amd64.c
の変更は、tcb_fixup
関数内のコメントの修正です。以前のコメントでは、メインスレッドのTCB (Thread Control Block) は静的割り当てであるため解放すべきではないとされていましたが、新しいコメントでは、oldtcb
を解放すると二重解放の問題を引き起こす可能性があり、newtcb
がメモリリークを引き起こす可能性があると指摘しています。そして、OpenBSDがPT_TLS(POSIX Thread Local Storage)を適切にサポートするようになったら、この問題を解決すべきだと述べています。
この変更は、直接的にcgo_export
とcgo_import
の競合を解決するものではありませんが、OpenBSDのCgoランタイムにおけるスレッドローカルストレージの管理に関する既存の課題を明確にしています。これは、Issue 4878の根本原因の一部、またはその修正によって顕在化した別の問題に関連している可能性があります。リンカの変更がシンボル解決の矛盾を解消したことで、ランタイムレベルでのメモリ管理の課題がより明確になったのかもしれません。
テストスクリプトの変更
src/run.bash
の変更は、OpenBSD環境でmisc/cgo/test
のテストがスキップされていた行を削除しています。これは、Issue 4878が修正されたため、OpenBSD上でもCgoのテストが正常に実行できるようになったことを示しています。これにより、OpenBSD環境でのCgoの安定性が向上したことが確認できます。
コアとなるコードの変更箇所
src/cmd/ld/go.c
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -499,11 +499,16 @@ loadcgo(char *file, char *pkg, char *p, int n)
remote = local;
local = expandpkg(local, pkg);
s = lookup(local, 0);
+
+ // export overrides import, for openbsd/cgo.
+ // see issue 4878.
if(s->dynimplib != nil) {
- fprintf(2, "%s: symbol is both imported and exported: %s\\n", argv0, local);
- nerrors++;
+ s->dynimplib = nil;
+ s->extname = nil;
+ s->dynimpvers = nil;
+ s->type = 0;
}
-
+
if(s->cgoexport == 0) {
if(strcmp(f[0], "cgo_export_static") == 0)
s->cgoexport |= CgoExportStatic;
src/pkg/runtime/cgo/gcc_openbsd_386.c
および src/pkg/runtime/cgo/gcc_openbsd_amd64.c
--- a/src/pkg/runtime/cgo/gcc_openbsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_openbsd_386.c
@@ -48,9 +48,9 @@ tcb_fixup(int mainthread)
bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE);
__set_tcb(newtcb + TLS_SIZE);
- // The main thread TCB is a static allocation - do not try to free it.
- if(!mainthread)
- free(oldtcb);
+ // NOTE(jsing, minux): we can't free oldtcb without causing double-free
+ // problem. so newtcb will be memory leaks. Get rid of this when OpenBSD
+ // has proper support for PT_TLS.
}
static void *
(gcc_openbsd_amd64.c
も同様の変更)
src/run.bash
--- a/src/run.bash
+++ b/src/run.bash
@@ -74,7 +74,6 @@ go run $GOROOT/test/run.go - .
) || exit $?\n
[ "$CGO_ENABLED" != 1 ] ||
-[ "$GOHOSTOS" == openbsd ] || # issue 4878
(xcd ../misc/cgo/test
go test
case "$GOHOSTOS-$GOARCH" in
コアとなるコードの解説
src/cmd/ld/go.c
の変更
この変更は、Goリンカのloadcgo
関数内で行われています。loadcgo
は、Cgoによって生成されたシンボル情報を処理する部分です。
変更前のコードでは、s->dynimplib != nil
(シンボルs
が動的インポートライブラリを持つ、つまり外部からインポートされるシンボルとしてマークされている)の場合に、そのシンボルが既にエクスポートされていると判断されると、エラーとして処理し、リンカを停止させていました。
変更後のコードでは、s->dynimplib != nil
の場合でも、エラーを発生させる代わりに、シンボルs
のインポート関連の情報をクリアしています。具体的には、s->dynimplib
、s->extname
、s->dynimpvers
、s->type
をリセットしています。
このロジックは、コメントにあるように「export overrides import, for openbsd/cgo.」(OpenBSD/Cgoの場合、エクスポートがインポートを上書きする)という原則に基づいています。これにより、OpenBSDのCgoランタイムが内部的に必要とするシンボルが、リンカによって「インポートとエクスポートの競合」として誤って検出されることなく、Goプログラムがそのシンボルをエクスポートする定義を優先して処理できるようになりました。結果として、リンカのエラーが回避され、OpenBSD上でのCgoプログラムのビルドが可能になります。
src/pkg/runtime/cgo/gcc_openbsd_386.c
および src/pkg/runtime/cgo/gcc_openbsd_amd64.c
の変更
これらのファイルは、OpenBSDアーキテクチャ(386とAMD64)向けのCgoランタイムの一部です。tcb_fixup
関数は、スレッドのTCB(Thread Control Block)の修正に関連するものです。
変更はコードのロジック自体ではなく、コメントの修正です。以前のコメントは、メインスレッドのTCBは静的割り当てであるため解放すべきではないと述べていました。しかし、新しいコメントでは、oldtcb
を解放すると二重解放の問題が発生する可能性があり、その結果newtcb
がメモリリークを引き起こす可能性があると指摘しています。そして、OpenBSDがPT_TLS(POSIX Thread Local Storage)を適切にサポートするようになったら、この問題に対処すべきだと明記しています。
このコメントの変更は、OpenBSDのCgoランタイムにおけるスレッドローカルストレージの管理が複雑であり、メモリリークや二重解放のリスクを伴うことを開発者に注意喚起するものです。これは、Issue 4878の直接的な修正ではありませんが、OpenBSD環境でのCgoの安定性に関連する情報を提供しています。リンカの変更によってビルドが可能になったことで、ランタイムレベルでのこれらの課題がより明確になった可能性があります。
src/run.bash
の変更
このシェルスクリプトは、Goのテストを実行するためのものです。変更前は、[ "$GOHOSTOS" == openbsd ] || # issue 4878
という行があり、これはGOHOSTOS
がopenbsd
の場合に、misc/cgo/test
ディレクトリ内のgo test
の実行をスキップするという意味でした。
この行が削除されたことで、OpenBSD環境でもmisc/cgo/test
のテストが実行されるようになりました。これは、Issue 4878が修正され、OpenBSD上でのCgoのビルドと実行に関する問題が解決されたため、テストをスキップする必要がなくなったことを示しています。これにより、OpenBSD環境でのCgoの機能がGoのCI/CDパイプラインで継続的にテストされるようになり、将来的な回帰を防ぐのに役立ちます。
関連リンク
- Go Issue 4878: cmd/ld: symbol is both imported and exported: _cgo_thread_start
- Go Change List 7420052: cmd/ld, runtime/cgo: allow a symbol to be both cgo_export and cgo_import.
参考にした情報源リンク
- Go言語のCgoに関する公式ドキュメントや関連するGoのソースコード
- Go Issue 4878の議論スレッド
- Goのリンカ(
cmd/ld
)の一般的な動作に関する情報 - Thread Local Storage (TLS) に関する一般的な情報# [インデックス 15674] ファイルの概要
このコミットは、Go言語のリンカ (src/cmd/ld/go.c
) と、OpenBSD向けのCgoランタイム (src/pkg/runtime/cgo/gcc_openbsd_386.c
, src/pkg/runtime/cgo/gcc_openbsd_amd64.c
)、そしてテストスクリプト (src/run.bash
) に変更を加えています。主な目的は、GoとCの相互運用機能であるCgoにおいて、あるシンボルがcgo_export
とcgo_import
の両方として扱われる場合に発生する問題を解決することです。
コミット
cmd/ld, runtime/cgo: allow a symbol to be both cgo_export and cgo_import.
Fixes #4878.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7420052
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/960d7082ee9b8fda91444167b3c253d5cf5e115d
元コミット内容
commit 960d7082ee9b8fda91444167b3c253d5cf5e115d
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Mon Mar 11 14:24:51 2013 +0800
cmd/ld, runtime/cgo: allow a symbol to be both cgo_export and cgo_import.
Fixes #4878.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7420052
---
src/cmd/ld/go.c | 11 ++++++++---\n src/pkg/runtime/cgo/gcc_openbsd_386.c | 6 +++---\n src/pkg/runtime/cgo/gcc_openbsd_amd64.c | 6 +++---\n src/run.bash | 1 -\n 4 files changed, 14 insertions(+), 10 deletions(-)\n
変更の背景
このコミットは、Go言語のIssue 4878「cmd/ld: symbol is both imported and exported: _cgo_thread_start」を修正するために行われました。この問題は、特にOpenBSD環境において、Cgoを使用する際に特定のシンボル(例: _cgo_thread_start
)がGoリンカによって「インポートとエクスポートの両方」として誤って検出され、エラーとなることが原因でした。
通常、シンボルは外部からインポートされるか(cgo_import
)、外部にエクスポートされるか(cgo_export
)のいずれか一方であるべきです。しかし、OpenBSDのCgoランタイムの特定の設計や、リンカのシンボル解決ロジックの不備により、この二重の定義が検出され、リンカがエラーを発生させていました。これにより、OpenBSD上でのCgoプログラムのビルドが妨げられていました。
この問題は、GoのランタイムがCのコードを呼び出し、CのコードがGoのコードをコールバックするような複雑なCgoのシナリオで顕在化しやすかったと考えられます。リンカは、シンボルが外部ライブラリからインポートされるべきか、それともGoプログラム自身が提供するべきかについて明確な判断ができず、矛盾として扱っていました。
前提知識の解説
Go言語のCgo
Cgoは、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりするためのGoの機能です。これにより、既存のCライブラリをGoから利用したり、パフォーマンスが重要な部分をCで記述したりすることが可能になります。
Cgoを使用する際、Goのビルドプロセスは以下のようになります。
- Goのソースコード内の
import "C"
ブロックを解析し、Cのコードを抽出します。 - Cのコンパイラ(通常はGCC)を使用して、抽出されたCのコードをコンパイルします。
- GoのコンパイラはGoのコードをコンパイルします。
- Goリンカ(
cmd/ld
)は、コンパイルされたGoのオブジェクトファイルとCのオブジェクトファイルをリンクし、最終的な実行可能ファイルを生成します。この際、GoとCの間でやり取りされるシンボル(関数や変数)の解決が行われます。
cgo_export
とcgo_import
Cgoにおいて、GoとCの間でシンボルをやり取りするために、特別なディレクティブが使用されます。
cgo_export
: Goの関数や変数をCのコードから呼び出せるように、外部にエクスポートする際に使用されます。Goのコードで//export MyGoFunction
のように記述すると、MyGoFunction
というGoの関数がCから呼び出し可能なシンボルとしてエクスポートされます。cgo_import
: Cの関数や変数をGoのコードから呼び出せるように、外部からインポートする際に使用されます。Goのコードでimport "C"
ブロック内にCの関数宣言を記述すると、その関数は外部のCライブラリからインポートされるシンボルとして扱われます。
リンカは、これらのcgo_export
およびcgo_import
の情報を基に、GoとCのオブジェクトファイル間でシンボルを正しく解決します。
Goリンカ (cmd/ld
)
cmd/ld
はGo言語のリンカであり、コンパイルされたGoのオブジェクトファイルと、Cgoによって生成されたCのオブジェクトファイル、およびその他のライブラリを結合して実行可能ファイルを生成する役割を担っています。リンカは、プログラム内のすべてのシンボル参照を解決し、それぞれのシンボルがどこで定義されているかを特定します。
Thread Local Storage (TLS)
Thread Local Storage (TLS) は、各スレッドが独自のデータコピーを持つことを可能にするメカニズムです。これにより、グローバル変数のようにアクセスできるが、実際にはスレッドごとに独立した値を持つ変数を定義できます。Cgoのコンテキストでは、GoランタイムとCランタイムがスレッド固有の情報を管理するためにTLSを使用することがあります。OpenBSDのような特定のOSでは、TLSのサポートが他のOSと異なる場合があり、それがCgoランタイムの複雑さや問題の原因となることがあります。
技術的詳細
このコミットの技術的詳細は、主にGoリンカのシンボル解決ロジックと、OpenBSDにおけるCgoランタイムの特殊性に起因します。
リンカのシンボル解決の競合
Goリンカは、loadcgo
関数内でCgo関連のシンボルを処理します。以前のリンカのロジックでは、あるシンボルが既にdynimplib
(動的インポートライブラリ)を持つ、つまり外部からインポートされるシンボルとしてマークされているにもかかわらず、cgo_export
としても定義されようとすると、これをエラーとして扱っていました。
if(s->dynimplib != nil) {
fprintf(2, "%s: symbol is both imported and exported: %s\\n", argv0, local);
nerrors++;
}
このロジックは、一般的なケースではシンボル定義の矛盾を検出するのに役立ちますが、OpenBSDのCgoランタイムの特定のシナリオでは問題を引き起こしました。OpenBSDのCgoランタイムは、GoランタイムがCのコードを呼び出し、そのCのコードがGoのランタイムの一部(例えば、スレッドの初期化に関連する関数)をコールバックするような、より複雑な相互作用を必要とすることがあります。この際、特定のシンボル(例: _cgo_thread_start
)が、Go側からCにエクスポートされると同時に、C側からGoにインポートされるかのようにリンカに認識されてしまうことがありました。これは、シンボルが実際に二重に定義されているわけではなく、リンカの視点から見た「インポート」と「エクスポート」の解釈が、OpenBSDのCgoの特殊なフローと合致しなかったためです。
修正アプローチ:「エクスポートがインポートを上書きする」
このコミットの主要な修正は、リンカのloadcgo
関数において、シンボルが既にインポートされているとマークされていても、それがcgo_export
として定義されようとする場合に、既存のインポート情報をクリアし、エクスポートを優先させるというロジックを追加したことです。
// export overrides import, for openbsd/cgo.
// see issue 4878.
if(s->dynimplib != nil) {
s->dynimplib = nil;
s->extname = nil;
s->dynimpvers = nil;
s->type = 0;
}
この変更により、リンカは「このシンボルは外部からインポートされるものだが、Go自身がエクスポートするものとしても定義されている。この場合はGoのエクスポートを優先しよう」と判断するようになります。これにより、OpenBSDのCgoランタイムが内部的に必要とするシンボルが、リンカによって矛盾として扱われることなく、正しく解決されるようになりました。
OpenBSD Cgoランタイムの変更
src/pkg/runtime/cgo/gcc_openbsd_386.c
および src/pkg/runtime/cgo/gcc_openbsd_amd64.c
の変更は、tcb_fixup
関数内のコメントの修正です。以前のコメントでは、メインスレッドのTCB (Thread Control Block) は静的割り当てであるため解放すべきではないとされていましたが、新しいコメントでは、oldtcb
を解放すると二重解放の問題を引き起こす可能性があり、newtcb
がメモリリークを引き起こす可能性があると指摘しています。そして、OpenBSDがPT_TLS(POSIX Thread Local Storage)を適切にサポートするようになったら、この問題を解決すべきだと述べています。
この変更は、直接的にcgo_export
とcgo_import
の競合を解決するものではありませんが、OpenBSDのCgoランタイムにおけるスレッドローカルストレージの管理に関する既存の課題を明確にしています。これは、Issue 4878の根本原因の一部、またはその修正によって顕在化した別の問題に関連している可能性があります。リンカの変更がシンボル解決の矛盾を解消したことで、ランタイムレベルでのメモリ管理の課題がより明確になったのかもしれません。
テストスクリプトの変更
src/run.bash
の変更は、OpenBSD環境でmisc/cgo/test
のテストがスキップされていた行を削除しています。これは、Issue 4878が修正されたため、OpenBSD上でもCgoのテストが正常に実行できるようになったことを示しています。これにより、OpenBSD環境でのCgoの安定性が向上したことが確認できます。
コアとなるコードの変更箇所
src/cmd/ld/go.c
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -499,11 +499,16 @@ loadcgo(char *file, char *pkg, char *p, int n)
remote = local;
local = expandpkg(local, pkg);
s = lookup(local, 0);
+
+ // export overrides import, for openbsd/cgo.
+ // see issue 4878.
if(s->dynimplib != nil) {
- fprintf(2, "%s: symbol is both imported and exported: %s\\n", argv0, local);
- nerrors++;
+ s->dynimplib = nil;
+ s->extname = nil;
+ s->dynimpvers = nil;
+ s->type = 0;
}
-
+
if(s->cgoexport == 0) {
if(strcmp(f[0], "cgo_export_static") == 0)
s->cgoexport |= CgoExportStatic;
src/pkg/runtime/cgo/gcc_openbsd_386.c
および src/pkg/runtime/cgo/gcc_openbsd_amd64.c
--- a/src/pkg/runtime/cgo/gcc_openbsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_openbsd_386.c
@@ -48,9 +48,9 @@ tcb_fixup(int mainthread)
bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE);
__set_tcb(newtcb + TLS_SIZE);
- // The main thread TCB is a static allocation - do not try to free it.
- if(!mainthread)
- free(oldtcb);
+ // NOTE(jsing, minux): we can't free oldtcb without causing double-free
+ // problem. so newtcb will be memory leaks. Get rid of this when OpenBSD
+ // has proper support for PT_TLS.
}
static void *
(gcc_openbsd_amd64.c
も同様の変更)
src/run.bash
--- a/src/run.bash
+++ b/src/run.bash
@@ -74,7 +74,6 @@ go run $GOROOT/test/run.go - .
) || exit $?\n
[ "$CGO_ENABLED" != 1 ] ||
-[ "$GOHOSTOS" == openbsd ] || # issue 4878
(xcd ../misc/cgo/test
go test
case "$GOHOSTOS-$GOARCH" in
コアとなるコードの解説
src/cmd/ld/go.c
の変更
この変更は、Goリンカのloadcgo
関数内で行われています。loadcgo
は、Cgoによって生成されたシンボル情報を処理する部分です。
変更前のコードでは、s->dynimplib != nil
(シンボルs
が動的インポートライブラリを持つ、つまり外部からインポートされるシンボルとしてマークされている)の場合に、そのシンボルが既にエクスポートされていると判断されると、エラーとして処理し、リンカを停止させていました。
変更後のコードでは、s->dynimplib != nil
の場合でも、エラーを発生させる代わりに、シンボルs
のインポート関連の情報をクリアしています。具体的には、s->dynimplib
、s->extname
、s->dynimpvers
、s->type
をリセットしています。
このロジックは、コメントにあるように「export overrides import, for openbsd/cgo.」(OpenBSD/Cgoの場合、エクスポートがインポートを上書きする)という原則に基づいています。これにより、OpenBSDのCgoランタイムが内部的に必要とするシンボルが、リンカによって「インポートとエクスポートの競合」として誤って検出されることなく、Goプログラムがそのシンボルをエクスポートする定義を優先して処理できるようになりました。結果として、リンカのエラーが回避され、OpenBSD上でのCgoプログラムのビルドが可能になります。
src/pkg/runtime/cgo/gcc_openbsd_386.c
および src/pkg/runtime/cgo/gcc_openbsd_amd64.c
の変更
これらのファイルは、OpenBSDアーキテクチャ(386とAMD64)向けのCgoランタイムの一部です。tcb_fixup
関数は、スレッドのTCB(Thread Control Block)の修正に関連するものです。
変更はコードのロジック自体ではなく、コメントの修正です。以前のコメントは、メインスレッドのTCBは静的割り当てであるため解放すべきではないと述べていました。しかし、新しいコメントでは、oldtcb
を解放すると二重解放の問題が発生する可能性があり、その結果newtcb
がメモリリークを引き起こす可能性があると指摘しています。そして、OpenBSDがPT_TLS(POSIX Thread Local Storage)を適切にサポートするようになったら、この問題に対処すべきだと明記しています。
このコメントの変更は、OpenBSDのCgoランタイムにおけるスレッドローカルストレージの管理が複雑であり、メモリリークや二重解放のリスクを伴うことを開発者に注意喚起するものです。これは、Issue 4878の直接的な修正ではありませんが、OpenBSD環境でのCgoの安定性に関連する情報を提供しています。リンカの変更によってビルドが可能になったことで、ランタイムレベルでのこれらの課題がより明確になった可能性があります。
src/run.bash
の変更
このシェルスクリプトは、Goのテストを実行するためのものです。変更前は、[ "$GOHOSTOS" == openbsd ] || # issue 4878
という行があり、これはGOHOSTOS
がopenbsd
の場合に、misc/cgo/test
ディレクトリ内のgo test
の実行をスキップするという意味でした。
この行が削除されたことで、OpenBSD環境でもmisc/cgo/test
のテストが実行されるようになりました。これは、Issue 4878が修正され、OpenBSD上でのCgoのビルドと実行に関する問題が解決されたため、テストをスキップする必要がなくなったことを示しています。これにより、OpenBSD環境でのCgoの機能がGoのCI/CDパイプラインで継続的にテストされるようになり、将来的な回帰を防ぐのに役立ちます。
関連リンク
- Go Issue 4878: cmd/ld: symbol is both imported and exported: _cgo_thread_start
- Go Change List 7420052: cmd/ld, runtime/cgo: allow a symbol to be both cgo_export and cgo_import.
参考にした情報源リンク
- Go言語のCgoに関する公式ドキュメントや関連するGoのソースコード
- Go Issue 4878の議論スレッド
- Goのリンカ(
cmd/ld
)の一般的な動作に関する情報 - Thread Local Storage (TLS) に関する一般的な情報