[インデックス 14141] ファイルの概要
このコミットは、Go言語のランタイムがFreeBSDオペレーティングシステム上でARMアーキテクチャをサポートするための変更を導入するものです。具体的には、FreeBSD/ARM環境に特化したシステム定義、起動ルーチン、シグナルハンドリング、およびシステムコールラッパーが追加されています。
コミット
commit 366268aa7951b81d55c4c8e69383758556917577
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Fri Oct 12 23:19:39 2012 +0800
runtime: FreeBSD/ARM support
R=rsc
CC=golang-dev
https://golang.org/cl/6625071
---
src/pkg/runtime/defs_freebsd_arm.h | 183 ++++++++++++++++++++++++
src/pkg/runtime/rt0_freebsd_arm.s | 8 ++
src/pkg/runtime/signal_freebsd_arm.c | 156 +++++++++++++++++++++
src/pkg/runtime/sys_freebsd_arm.s | 262 +++++++++++++++++++++++++++++++++++
4 files changed, 609 insertions(+)
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/366268aa7951b81d55c4c8e69383758556917577
元コミット内容
このコミットは、GoランタイムにFreeBSD/ARMのサポートを追加します。これには、FreeBSD/ARM固有のシステム定義、ランタイムの初期化コード、シグナル処理、およびシステムコールインターフェースの実装が含まれます。
変更の背景
Go言語は、その設計思想として、様々なプラットフォーム(OSとアーキテクチャの組み合わせ)での動作をサポートすることを目指しています。このコミットが作成された2012年当時、Goは既にLinuxやWindows、macOSなどの主要なOSと、x86/x64アーキテクチャをサポートしていましたが、組み込みシステムや特定のサーバー環境で利用されるARMアーキテクチャとFreeBSDの組み合わせに対するサポートは限定的でした。
FreeBSDは、堅牢性と高性能で知られるUNIX系OSであり、ARMアーキテクチャは低消費電力と高いコストパフォーマンスから、モバイルデバイス、組み込みシステム、そして近年ではデータセンターのサーバーなど、幅広い分野で採用が拡大していました。Go言語がこれらの環境で動作できるようにすることは、Goの適用範囲を広げ、より多くの開発者がGoを利用できるようにするために不可欠でした。
このコミットは、GoランタイムがFreeBSD/ARM環境で正しく動作するために必要な、低レベルのOSおよびハードウェアとのインタラクション層を実装することを目的としています。これにより、GoプログラムがFreeBSD/ARM上でコンパイルされ、実行できるようになります。
前提知識の解説
このコミットの変更内容を理解するためには、以下の技術的な概念についての知識が役立ちます。
- Goランタイム (Go Runtime): Goプログラムは、OSが提供する機能(システムコール、メモリ管理、スレッド管理など)を直接利用するのではなく、Goランタイムと呼ばれる独自の実行環境を介してこれらの機能にアクセスします。ランタイムは、ガベージコレクション、ゴルーチン(軽量スレッド)のスケジューリング、チャネル通信、メモリ割り当てなど、Go言語の並行処理モデルとメモリ管理を支える重要な役割を担っています。各OS/アーキテクチャの組み合わせに対して、ランタイムはそれぞれのプラットフォームの特性に合わせて実装されます。
- FreeBSD: UNIX系オペレーティングシステムの一つで、高性能、安定性、セキュリティに優れています。カーネルとユーザーランドが一体となって開発されており、システムコールインターフェースを通じてアプリケーションにサービスを提供します。
- ARMアーキテクチャ (Advanced RISC Machine): RISC(Reduced Instruction Set Computer)ベースのプロセッサアーキテクチャです。低消費電力と高い性能効率が特徴で、スマートフォン、タブレット、組み込みシステム、IoTデバイス、そして近年ではサーバーやデスクトップPCにも広く採用されています。ARMプロセッサは、レジスタセット、命令セット、メモリモデルなどがx86とは異なります。
- システムコール (System Call): アプリケーションがOSのカーネル機能(ファイルI/O、メモリ管理、プロセス管理、ネットワーク通信など)にアクセスするためのインターフェースです。アプリケーションは直接カーネルにアクセスすることはできず、システムコールを通じて間接的に要求を伝えます。各OSは独自のシステムコールセットと呼び出し規約を持っています。ARMアーキテクチャでは、通常、
SWI
(Software Interrupt) 命令やSVC
(Supervisor Call) 命令を使用してシステムコールをトリガーします。 - シグナルハンドリング (Signal Handling): OSがプロセスに対して非同期イベント(エラー、外部からの割り込みなど)を通知するメカニズムです。例えば、プログラムの不正なメモリアクセス(SIGSEGV)、割り込み(SIGINT)、タイマーイベント(SIGALRM)などがあります。プログラムはシグナルを受信した際に、事前に登録されたシグナルハンドラ関数を実行することで、これらのイベントに対応できます。
- メモリ管理 (Memory Management): プログラムがメモリを効率的に利用するための仕組みです。
mmap
(memory map) は、ファイルや匿名メモリ領域をプロセスの仮想アドレス空間にマッピングするシステムコールで、メモリ割り当てやファイルI/Oに利用されます。munmap
はマッピングを解除します。 - スレッド管理 (Thread Management): プロセス内で複数の実行パスを管理する仕組みです。Goランタイムは、OSスレッドの上にゴルーチンを多重化して実行します。
thr_new
やthr_start
は、FreeBSDにおけるスレッド作成に関連するシステムコールやランタイム関数です。 - アセンブリ言語 (Assembly Language): 特定のCPUアーキテクチャの命令セットに直接対応する低レベルのプログラミング言語です。Goランタイムの低レベルな部分(起動ルーチン、システムコールラッパー、コンテキストスイッチなど)は、パフォーマンスやOSとの密接な連携のためにアセンブリ言語で記述されることがあります。
godefs
ツール: Goのソースコード内でC言語の構造体や定数をGoの型定義に変換するために使用されるツールです。これにより、C言語で定義されたOSの構造体や定数をGoプログラムから安全に利用できるようになります。
技術的詳細
このコミットは、GoランタイムがFreeBSD/ARM上で動作するために必要な、以下の主要なコンポーネントを追加・変更しています。
-
src/pkg/runtime/defs_freebsd_arm.h
:- このファイルは、
godefs
ツールによって生成されたヘッダファイルであり、FreeBSD/ARM環境におけるシステムコールに関連する定数(PROT_NONE
,MAP_ANON
,SA_SIGINFO
など)や、OSが使用する主要なデータ構造(Rtprio
,ThrParam
,Sigaltstack
,Sigset
,Siginfo
,Mcontext
,Ucontext
,Timespec
,Timeval
,Itimerval
など)のGo言語での定義を含んでいます。 Mcontext
構造体は、シグナルハンドラが呼び出された時点のCPUレジスタの状態(R0-R15, CPSRなど)を保持しており、シグナル発生時のプログラムの状態を分析するために重要です。Ucontext
構造体は、シグナルマスク、マシンコンテキスト(Mcontext
)、代替スタック情報など、シグナルハンドラが実行されるコンテキスト全体をカプセル化します。- これらの定義は、GoランタイムがFreeBSDカーネルと正しくインタラクトし、システムコールやシグナル処理を行う上で不可欠です。
- このファイルは、
-
src/pkg/runtime/rt0_freebsd_arm.s
:- このファイルは、GoプログラムのFreeBSD/ARM上でのエントリポイントとなる低レベルのアセンブリコードを含んでいます。
_rt0_arm_freebsd
というシンボルは、プログラムが起動した際に最初に実行されるコードであり、Goランタイムの初期化ルーチンである_rt0_arm
にジャンプします。- これは、GoプログラムがOSによってロードされた後、Goランタイムが制御を引き継ぎ、Goの実行環境をセットアップするための最初のステップです。
-
src/pkg/runtime/signal_freebsd_arm.c
:- このファイルは、FreeBSD/ARM環境におけるGoランタイムのシグナルハンドリングロジックをC言語で実装しています。
runtime·dumpregs
関数は、Mcontext
構造体からCPUレジスタの値を抽出し、デバッグ目的で出力します。これは、クラッシュやパニック発生時にレジスタの状態を把握するために非常に有用です。runtime·sighandler
関数は、Goランタイムの主要なシグナルハンドラです。OSからシグナルを受信すると、この関数が呼び出され、シグナルの種類(SIGPROF
、SIGSEGV
など)に応じて適切な処理(プロファイリング、パニックの開始、シグナルの転送など)を行います。特に、SIGPROF
(プロファイリングシグナル)や、SIGSEGV
(セグメンテーション違反)のような致命的なシグナルに対するGoランタイムのパニック処理が実装されています。runtime·signalstack
は、代替シグナルスタックを設定するための関数です。これにより、通常のスタックが破損した場合でも、シグナルハンドラが安全に実行できるようになります。runtime·setsig
は、特定のシグナルに対するハンドラを設定するための関数です。SA_SIGINFO
フラグは、シグナルハンドラに追加のコンテキスト情報(Siginfo
、Ucontext
)を渡すことを指定します。SA_ONSTACK
は、代替シグナルスタックを使用することを指定します。runtime·cputicks
は、CPUのティック数を返す関数で、プロファイリングや乱数生成のシードとして利用されます。FreeBSD/ARMでは、runtime·nanotime()
(gettimeofday
システムコールに基づく)が使用されています。
-
src/pkg/runtime/sys_freebsd_arm.s
:- このファイルは、FreeBSD/ARM環境におけるGoランタイムのシステムコールラッパーをアセンブリ言語で実装しています。
- Goランタイムは、OSのシステムコールを直接呼び出すのではなく、このファイルで定義されたラッパー関数を介して呼び出します。これにより、Goの呼び出し規約とOSのシステムコール呼び出し規約の間の変換が行われます。
- 各
TEXT runtime·<syscall_name>(SB)
ブロックは、特定のシステムコール(例:runtime·sys_umtx_op
,runtime·thr_new
,runtime·exit
,runtime·write
,runtime·mmap
,runtime·munmap
,runtime·sigaction
,runtime·nanotime
,runtime·sigprocmask
など)に対応しています。 SWI
命令(Software Interrupt)は、ARMアーキテクチャでシステムコールをトリガーするために使用されます。SWI
命令のオペランドは、呼び出すシステムコールの番号を示します(例:$454
はumtx_op
、$1
はexit
、$4
はwrite
など)。- レジスタ(R0-R7)は、システムコールへの引数を渡すために使用され、戻り値もレジスタを介して返されます。スタックも引数渡しに使用されることがあります。
runtime·sigtramp
は、OSのシグナルディスパッチャからGoランタイムのシグナルハンドラ(runtime·sighandler
)への橋渡しをするアセンブリルーチンです。これは、シグナル発生時のCPUコンテキストを保存し、Goランタイムのコンテキスト(g
とm
ポインタ)を適切に設定してから、C言語で記述されたruntime·sighandler
を呼び出します。runtime·cas
およびruntime·casp
は、アトミックな比較交換(Compare-And-Swap)操作を実装しています。これは、並行処理におけるロックフリーなデータ構造や同期プリミティブを実装するために不可欠な低レベル操作です。
コアとなるコードの変更箇所
このコミットで追加された主要なファイルは以下の4つです。
src/pkg/runtime/defs_freebsd_arm.h
: FreeBSD/ARM固有の定数と構造体定義。src/pkg/runtime/rt0_freebsd_arm.s
: FreeBSD/ARM用のランタイム初期化アセンブリコード。src/pkg/runtime/signal_freebsd_arm.c
: FreeBSD/ARM用のシグナルハンドリングCコード。src/pkg/runtime/sys_freebsd_arm.s
: FreeBSD/ARM用のシステムコールラッパーアセンブリコード。
これらのファイルはすべて新規追加されており、GoランタイムがFreeBSD/ARM環境で動作するために必要な、OSおよびアーキテクチャ固有の低レベルなインタラクション層を構成しています。
コアとなるコードの解説
src/pkg/runtime/defs_freebsd_arm.h
このファイルは、GoランタイムがFreeBSD/ARMカーネルと連携するために必要な、C言語のシステムヘッダから抽出された定数と構造体のGo言語表現を提供します。
- 定数:
PROT_READ
,MAP_ANON
,SA_SIGINFO
などのメモリ保護フラグ、メモリマッピングフラグ、シグナルアクションフラグ、および様々なシグナル番号(SIGHUP
,SIGINT
,SIGSEGV
など)が定義されています。これらは、mmap
やsigaction
などのシステムコールを呼び出す際に引数として使用されます。 - 構造体:
Siginfo
: シグナルに関する詳細情報(シグナル番号、エラーコード、発生アドレスなど)を保持します。Mcontext
: シグナル発生時のCPUレジスタの状態(R0-R15, CPSRなど)を保持します。これは、スタックトレースの生成やデバッグに不可欠です。Ucontext
: シグナルハンドラが実行される際の完全なコンテキスト(シグナルマスク、マシンコンテキスト、スタック情報など)をカプセル化します。Timespec
,Timeval
,Itimerval
: 時間関連のシステムコールで使用される構造体です。FreeBSD/ARMでは、tv_sec
がint64
である点が注目されます。
これらの定義は、GoランタイムがFreeBSDカーネルのAPIを正しく呼び出し、その応答を解釈するために必要です。
src/pkg/runtime/rt0_freebsd_arm.s
これは、GoプログラムがFreeBSD/ARM上で起動する際のエントリポイントとなる非常に短いアセンブリファイルです。
TEXT _rt0_arm_freebsd(SB),7,$-4
B _rt0_arm(SB)
_rt0_arm_freebsd(SB)
: FreeBSD/ARM環境におけるGoプログラムの開始点となるシンボルです。B _rt0_arm(SB)
: この命令は、Goランタイムの共通ARM初期化ルーチンである_rt0_arm
に無条件ジャンプします。 このファイルは、OSがプログラムをロードした直後にGoランタイムが制御を獲得し、Goの実行環境をセットアップするための最初のステップを提供します。
src/pkg/runtime/signal_freebsd_arm.c
このCファイルは、FreeBSD/ARM環境でのGoランタイムのシグナル処理ロジックを実装しています。
runtime·dumpregs(Mcontext *r)
:Mcontext
構造体からARMレジスタの値を抽出し、runtime·printf
で出力します。これは、プログラムがクラッシュした際に、CPUの状態をデバッグログに出力するために使用されます。runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
:- Goランタイムの主要なシグナルハンドラです。OSからシグナルが配送されると、この関数が呼び出されます。
SIGPROF
(プロファイリングシグナル)の場合、runtime·sigprof
を呼び出してプロファイリングデータを収集します。SigPanic
フラグが設定されたシグナル(例:SIGSEGV
,SIGBUS
)の場合、Goのパニックメカニズムをトリガーします。gp->sig
,gp->sigcode0
,gp->sigcode1
,gp->sigpc
にシグナル情報を設定し、runtime·sigpanic
関数を呼び出すようにレジスタ(特にr15
- プログラムカウンタ)を操作します。これにより、Goのパニック処理が開始され、スタックトレースが生成されます。SigNotify
フラグが設定されたシグナルやSI_USER
(ユーザーが生成したシグナル)の場合、runtime·sigsend
を呼び出してGoのシグナル通知チャネルにシグナルを送信します。SigKill
フラグが設定されたシグナル(例:SIGKILL
)の場合、runtime·exit(2)
を呼び出してプログラムを終了します。SigThrow
フラグが設定されたシグナル(デフォルトの動作)の場合、runtime·startpanic()
を呼び出し、シグナル情報とスタックトレースを出力してプログラムを終了します。
runtime·signalstack(byte *p, int32 n)
:sigaltstack
システムコールを呼び出して、代替シグナルスタックを設定します。これにより、通常のスタックが破損した場合でも、シグナルハンドラが安全に実行できる保証を提供します。runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
:sigaction
システムコールを呼び出して、特定のシグナルi
に対するハンドラ関数fn
を設定します。SA_SIGINFO
とSA_ONSTACK
フラグを設定し、必要に応じてSA_RESTART
フラグも設定します。runtime·sighandler
がハンドラとして設定される場合、実際にはアセンブリのruntime·sigtramp
が登録されます。runtime·cputicks()
: CPUのティック数を返す関数で、runtime·nanotime()
(gettimeofday
システムコールに基づく)の値を返します。
src/pkg/runtime/sys_freebsd_arm.s
このアセンブリファイルは、GoランタイムがFreeBSD/ARMカーネルのシステムコールを呼び出すためのラッパー関数を定義しています。
- システムコール呼び出し規約:
- ARMアーキテクチャでは、通常、システムコール番号はレジスタ
R7
に設定されます(ただし、FreeBSDではSWI
命令のオペランドとして直接指定されることが多い)。 - 引数は
R0
、R1
、R2
、R3
などのレジスタに渡されます。引数がこれら4つのレジスタに収まらない場合、残りの引数はスタックにプッシュされます。 - システムコールは
SWI
(Software Interrupt)命令を使用してトリガーされます。SWI
命令のオペランドは、呼び出すシステムコールの番号です(例:SWI $454
はumtx_op
システムコール)。 - システムコールの戻り値は
R0
レジスタに格納されます。エラーが発生した場合、R0
にはエラーコードが設定され、C
フラグ(キャリーフラグ)がセットされます。
- ARMアーキテクチャでは、通常、システムコール番号はレジスタ
- 主要なシステムコールラッパー:
runtime·sys_umtx_op
: ユーザーランドミューテックス操作(umtx_op
システムコール)のラッパー。runtime·thr_new
: 新しいスレッドを作成する(thr_new
システムコール)のラッパー。runtime·thr_start
: 新しく作成されたスレッドの開始ルーチン。Goのmstart
関数を呼び出して、Goスケジューラにスレッドを登録します。runtime·exit
,runtime·exit1
: プログラムを終了する(exit
,exit1
システムコール)のラッパー。runtime·write
: ファイルディスクリプタにデータを書き込む(write
システムコール)のラッパー。runtime·getrlimit
: リソース制限を取得する(getrlimit
システムコール)のラッパー。runtime·setitimer
: タイマーを設定する(setitimer
システムコール)のラッパー。time·now
,runtime·nanotime
: 現在時刻を取得する(gettimeofday
システムコール)のラッパー。nanotime
は秒とマイクロ秒からナノ秒を計算します。runtime·sigaction
: シグナルハンドラを設定する(sigaction
システムコール)のラッパー。runtime·sigtramp
: OSからシグナルハンドラが呼び出された際に、Goランタイムのコンテキスト(g
とm
ポインタ)を適切に設定し、C言語で記述されたruntime·sighandler
を呼び出すためのアセンブリルーチン。runtime·mmap
,runtime·munmap
: メモリマッピングを行う/解除する(mmap
,munmap
システムコール)のラッパー。runtime·sigaltstack
: 代替シグナルスタックを設定する(sigaltstack
システムコール)のラッパー。runtime·usleep
: 指定された時間だけスリープする(nanosleep
システムコール)のラッパー。runtime·sysctl
: カーネルパラメータを取得/設定する(sysctl
システムコール)のラッパー。runtime·osyield
: CPUを他のスレッドに譲る(sched_yield
システムコール)のラッパー。runtime·sigprocmask
: シグナルマスクを変更する(sigprocmask
システムコール)のラッパー。runtime·cacheflush
: キャッシュをフラッシュする(sysarch
システムコール)のラッパー。runtime·casp
,runtime·cas
: アトミックな比較交換(Compare-And-Swap)操作を実装。これは、ARMv6以降のプロセッサで利用可能なアトミック命令(例:LDREX
,STREX
)を利用して実装されます。
これらのアセンブリラッパーは、GoランタイムがFreeBSD/ARMカーネルの機能に効率的かつ安全にアクセスするための基盤を提供します。
関連リンク
- Go言語公式ドキュメント: https://golang.org/doc/
- FreeBSDプロジェクト: https://www.freebsd.org/
- ARMアーキテクチャ: https://developer.arm.com/
- Goのランタイムに関するブログ記事やドキュメント(一般的な情報源)
参考にした情報源リンク
- Goのソースコード(特に
src/runtime
ディレクトリ) - FreeBSDのシステムコールに関するドキュメント(
man
ページなど) - ARMアーキテクチャのリファレンスマニュアル
- Goのランタイムに関する技術ブログや論文(一般的な情報源)