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

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

このコミットは、Go言語のランタイムにおけるcgo(C言語との連携機能)がNetBSD上で正しくビルドされるようにするための修正です。具体的には、NetBSD環境で必要となるenvironおよび__prognameというシンボルをGoランタイムが明示的に提供するように、src/pkg/runtime/cgo/netbsd.cという新しいファイルを追加しています。これは、FreeBSDの既存の実装をNetBSD向けにコピーし、適応させたものです。

コミット

  • コミットハッシュ: b4402a49b6c9a87f27c2140beacf46ef95738455
  • Author: Benny Siegert bsiegert@gmail.com
  • Date: Sun Jul 29 18:51:06 2012 -0400
  • Subject: runtime/cgo: fix netbsd build

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

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

元コミット内容

commit b4402a49b6c9a87f27c2140beacf46ef95738455
Author: Benny Siegert <bsiegert@gmail.com>
Date:   Sun Jul 29 18:51:06 2012 -0400

    runtime/cgo: fix netbsd build
    
    Copy over freebsd.c to netbsd.c.
    
    Fixes #3823.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/6398045
--
 src/pkg/runtime/cgo/netbsd.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/pkg/runtime/cgo/netbsd.c b/src/pkg/runtime/cgo/netbsd.c
new file mode 100644
index 0000000000..b6403f686c
--- /dev/null
+++ b/src/pkg/runtime/cgo/netbsd.c
@@ -0,0 +1,13 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Supply environ and __progname, because we don't
+// link against the standard NetBSD crt0.o and the
+// libc dynamic library needs them.
+
+char *environ[1];
+char *__progname;
+
+#pragma dynexport environ environ
+#pragma dynexport __progname __progname

変更の背景

このコミットは、Go言語のプログラムがNetBSDオペレーティングシステム上でC言語のコード(cgo経由)と連携する際に発生していたビルドの問題を解決するために導入されました。

一般的なC言語のプログラムは、crt0.o(C runtime start-up object file)と呼ばれるオブジェクトファイルにリンクされます。このcrt0.oは、プログラムのmain関数が呼び出される前に、環境変数(environ)やプログラム名(__progname)などのグローバル変数を初期化する役割を担っています。

Go言語のランタイムは、その独自の起動プロセスとメモリ管理メカニズムを持っているため、標準的なC言語のcrt0.oにリンクしない場合があります。特に、Goのランタイムが直接OSのシステムコールを呼び出してプログラムを起動するような場合、crt0.oが提供するはずのenviron__prognameといったシンボルが利用できなくなり、結果としてlibc(C標準ライブラリ)がこれらのシンボルを必要とする際に問題が発生します。

NetBSD環境では、libcが動的ライブラリとしてリンクされる際に、これらのシンボルを期待していました。Goのランタイムがcrt0.oを介さずに起動すると、これらのシンボルが未定義となり、ビルドエラーや実行時エラーを引き起こす可能性がありました。このコミットは、この問題を解決するために、Goランタイム自身がこれらのシンボルを明示的に定義し、エクスポートすることで、libcの要件を満たすようにしています。

コミットメッセージにある「Fixes #3823」は、この問題がGoのIssueトラッカーで報告されていたことを示しています。

前提知識の解説

cgo

cgoは、Go言語のプログラムからC言語の関数を呼び出したり、C言語のデータ型を扱ったりするためのGoの機能です。これにより、既存のCライブラリをGoプログラムから利用したり、パフォーマンスが重要な部分をCで記述したりすることが可能になります。cgoを使用すると、GoコンパイラはCコードをコンパイルし、Goコードとリンクするための特別な処理を行います。

Goランタイム (runtime)

Go言語のランタイムは、Goプログラムの実行を管理するシステムです。これには、ガベージコレクション、ゴルーチンのスケジューリング、チャネルの操作、メモリ管理、システムコールへのインターフェースなどが含まれます。Goプログラムは、OS上で直接実行されるのではなく、このランタイムの上で動作します。

NetBSD

NetBSDは、オープンソースのUNIXライクなオペレーティングシステムであり、BSD系OSの一つです。移植性が非常に高く、多くの異なるハードウェアアーキテクチャで動作することで知られています。

environ

environは、C言語のプログラムにおいて、環境変数を格納するグローバル変数です。これは通常、char **environとして宣言され、NULLで終端される文字列ポインタの配列として、KEY=VALUE形式の環境変数文字列へのポインタを保持します。getenv()などの関数は、このenviron配列を検索して環境変数の値を取得します。

__progname

__prognameは、プログラムの実行ファイル名を格納するグローバル変数です。多くのUNIX系システムでは、main関数の第一引数であるargv[0]から初期化されます。デバッグやログ出力などでプログラム名が必要な場合に使用されます。

crt0.o

crt0.o(C runtime zero object file)は、C言語のプログラムが実行を開始する際に最初にロードされるオブジェクトファイルです。これは、プログラムのエントリポイント(通常は_startシンボル)を含み、main関数が呼び出される前に、スタックのセットアップ、環境変数の初期化(environの設定)、コマンドライン引数の解析(argc, argvの設定)、標準I/Oストリームの初期化など、基本的なランタイム環境のセットアップを行います。

libc (C標準ライブラリ)

libcは、C言語の標準ライブラリであり、ファイルI/O、文字列操作、メモリ管理、数学関数、プロセス制御など、基本的なシステム機能を提供する関数の集合です。多くのCプログラムは、これらの関数を利用するためにlibcにリンクされます。動的リンクの場合、プログラムの実行時にlibcの共有ライブラリがロードされます。

#pragma dynexport

#pragma dynexportは、特定のシンボル(変数や関数)を動的リンカが利用できるようにエクスポートするためのコンパイラ固有のディレクティブです。これは、共有ライブラリ(ダイナミックリンクライブラリ)から特定のシンボルを外部に公開する際に使用されます。このコミットの文脈では、Goランタイムが定義したenviron__prognameを、libcなどの外部ライブラリが動的に参照できるようにするために使用されています。

技術的詳細

Go言語のランタイムは、OSの起動メカニズムと密接に連携して動作します。通常のCプログラムがcrt0.oを介して起動し、main関数に制御が渡されるのに対し、Goプログラムは独自のruntimeパッケージがプログラムのエントリポイントとなり、OSから直接制御を受け取ることがあります。この場合、crt0.oが通常行う環境のセットアップ(environ__prognameの初期化など)がスキップされる可能性があります。

NetBSDのlibcは、動的リンクされた際に、これらのグローバルシンボル(environ__progname)が利用可能であることを期待します。もしGoランタイムがこれらのシンボルを定義せず、かつcrt0.oもリンクされない場合、libcは未定義のシンボルを参照しようとしてエラーとなります。

このコミットの解決策は、Goランタイムの一部として、NetBSD固有のCファイル(netbsd.c)を追加することです。このファイル内で、environ__prognameを明示的に宣言し、#pragma dynexportディレクティブを使用して、これらのシンボルが動的リンカによって外部に公開されるようにします。これにより、libcがこれらのシンボルを必要とする際に、Goランタイムが提供する定義を参照できるようになり、ビルドおよび実行時の問題を回避します。

「Copy over freebsd.c to netbsd.c」という記述は、FreeBSD環境でも同様の問題が存在し、既に解決策が実装されていたことを示唆しています。NetBSDとFreeBSDはどちらもBSD系のOSであり、システム起動やlibcの挙動に類似点があるため、FreeBSDの解決策をNetBSDに適用することができたと考えられます。

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

diff --git a/src/pkg/runtime/cgo/netbsd.c b/src/pkg/runtime/cgo/netbsd.c
new file mode 100644
index 0000000000..b6403f686c
--- /dev/null
+++ b/src/pkg/runtime/cgo/netbsd.c
@@ -0,0 +1,13 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Supply environ and __progname, because we don't
+// link against the standard NetBSD crt0.o and the
+// libc dynamic library needs them.
+
+char *environ[1];
+char *__progname;
+
+#pragma dynexport environ environ
+#pragma dynexport __progname __progname

コアとなるコードの解説

追加されたsrc/pkg/runtime/cgo/netbsd.cファイルの内容は以下の通りです。

  1. 著作権表示:

    // Copyright 2010 The Go Authors.  All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    

    Goプロジェクトの標準的な著作権表示です。

  2. コメントによる目的説明:

    // Supply environ and __progname, because we don't
    // link against the standard NetBSD crt0.o and the
    // libc dynamic library needs them.
    

    このコードの目的を明確に説明しています。Goランタイムが標準のNetBSD crt0.oにリンクしないため、libc動的ライブラリが必要とするenviron__prognameを提供する必要があることを述べています。

  3. environの宣言:

    char *environ[1];
    

    environグローバル変数を宣言しています。これはcharポインタの配列として定義されており、環境変数文字列へのポインタを保持します。[1]というサイズは、少なくとも1つの要素(通常はNULL終端のため)を保持できることを示していますが、実際の環境変数のリストはGoランタイムの内部で管理され、必要に応じてこのポインタが更新されるか、あるいはlibcがこのシンボルを単に存在することだけを期待している可能性があります。

  4. __prognameの宣言:

    char *__progname;
    

    __prognameグローバル変数を宣言しています。これはプログラム名文字列へのポインタを保持します。

  5. #pragma dynexportディレクティブ:

    #pragma dynexport environ environ
    #pragma dynexport __progname __progname
    

    この2行がこの修正の核心です。#pragma dynexportは、コンパイラに対して、指定されたシンボル(ここではenviron__progname)を動的リンカが外部から参照できるようにエクスポートするよう指示します。これにより、Goランタイムがビルドされた際に、これらのシンボルが共有ライブラリの外部インターフェースとして利用可能になり、libcなどの他の動的リンクされたライブラリがこれらを正しく解決できるようになります。

このファイルは、GoランタイムがNetBSD上で動作する際の、C言語とのインターフェース層の一部として機能し、OS固有のリンキング要件を満たすための重要な役割を果たしています。

関連リンク

参考にした情報源リンク

  • コミットメッセージと変更されたコード
  • C言語のcrt0.oenviron__prognameに関する一般的な知識
  • Go言語のcgoおよびランタイムに関する一般的な知識
  • BSD系OSのシステムプログラミングに関する一般的な知識