[インデックス 17269] ファイルの概要
このコミットは、GoランタイムにおけるFreeBSD/386およびOpenBSD/386アーキテクチャでのシステムコール番号の誤りを修正するものです。具体的には、kqueue
およびkevent
システムコールの番号が、それぞれのOSの386版で正しくない値に設定されていた問題を解決します。
コミット
commit ff86d222be18c5140a1457381ba1f46c9ab3af35
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Thu Aug 15 23:22:55 2013 +0900
runtime: fix wrong syscall numbers on freebsd/386, openbsd/386
R=golang-dev, jsing
CC=golang-dev
https://golang.org/cl/12876044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/ff86d222be18c5140a1457381ba1f46c9ab3af35
元コミット内容
runtime: fix wrong syscall numbers on freebsd/386, openbsd/386
変更の背景
Goランタイムは、様々なオペレーティングシステムとアーキテクチャをサポートしています。システムコールは、ユーザー空間のプログラムがカーネルの機能にアクセスするための主要なメカニズムです。各システムコールには一意の番号が割り当てられており、この番号はOSやアーキテクチャによって異なります。
このコミットが行われた背景には、FreeBSD/386およびOpenBSD/386環境において、Goランタイムがkqueue
およびkevent
システムコールを呼び出す際に、誤ったシステムコール番号を使用していたという問題がありました。これにより、これらのプラットフォームでkqueue
/kevent
を利用するGoプログラムが正しく動作しない、あるいは予期せぬ挙動を示す可能性がありました。
kqueue
とkevent
は、FreeBSD、OpenBSD、NetBSD、macOSなどのBSD系OSで広く利用されている、効率的なイベント通知インターフェースです。ネットワークI/O、ファイルシステムイベント、タイマーなど、様々な非同期イベントを監視するために使用されます。Goのネットワーキングや並行処理の基盤において、これらのシステムコールは重要な役割を担っています。
誤ったシステムコール番号を使用することは、プログラムが意図しないカーネル関数を呼び出そうとするか、あるいは存在しないシステムコールを呼び出そうとすることを意味します。これは通常、ENOSYS
(Function not implemented)のようなエラーを返すか、あるいはより深刻な場合はクラッシュを引き起こす可能性があります。このコミットは、これらのプラットフォームでのGoプログラムの安定性と正確性を確保するために不可欠な修正でした。
前提知識の解説
システムコール (Syscall)
システムコールは、オペレーティングシステム(OS)のカーネルが提供するサービスを、ユーザー空間のプログラムが利用するためのインターフェースです。ファイル操作(読み書き)、ネットワーク通信、メモリ管理、プロセス制御など、OSの重要な機能はシステムコールを通じて提供されます。
プログラムがシステムコールを呼び出す際、通常は以下の手順を踏みます。
- システムコール番号の設定: 呼び出したいシステムコールに対応する一意の番号を、特定のレジスタ(x86アーキテクチャでは通常
EAX
またはAX
)に設定します。 - 引数の設定: システムコールに渡す引数を、他のレジスタやスタックに設定します。
- トラップ命令の実行:
INT 0x80
(x86アーキテクチャのLinuxやBSD系OS)やSYSCALL
(x86-64アーキテクチャ)のような特別な命令を実行し、CPUをユーザーモードからカーネルモードに切り替えます。これにより、実行がカーネルに渡されます。 - カーネルでの処理: カーネルは、レジスタに設定されたシステムコール番号を読み取り、対応するカーネル関数を実行します。
- 結果の返却: カーネルは処理結果をレジスタに設定し、ユーザーモードに制御を戻します。
システムコール番号はOSやCPUアーキテクチャによって異なります。例えば、同じread
システムコールでも、Linux/x86とFreeBSD/x86では異なる番号が割り当てられていることがあります。
x86アーキテクチャにおけるINT $0x80
INT $0x80
は、x86プロセッサにおけるソフトウェア割り込み命令の一つです。この命令は、オペレーティングシステムが提供する割り込みハンドラを呼び出すために使用されます。特に、LinuxやBSD系OSの32ビット環境では、システムコールを呼び出すための主要なメカニズムとして利用されていました。
INT $0x80
が実行されると、CPUは割り込みベクタテーブルを参照し、割り込み番号0x80
に対応するハンドラ(通常はOSのシステムコールディスパッチャ)に制御を移します。この際、システムコール番号はEAX
レジスタに、引数は他のレジスタ(EBX
, ECX
, EDX
, ESI
, EDI
, EBP
など)に格納されていることが一般的です。
kqueue
とkevent
kqueue
とkevent
は、BSD系OS(FreeBSD, OpenBSD, NetBSD, macOSなど)で利用される、高性能なイベント通知メカニズムです。Linuxのepoll
やWindowsのI/O Completion Portsに相当する機能を提供します。
kqueue()
: 新しいkqueue
カーネルオブジェクトを作成し、そのファイルディスクリプタを返します。このファイルディスクリプタを通じて、イベントの監視と取得を行います。kevent()
:kqueue
オブジェクトに対して、監視したいイベント(changelist
)を登録したり、発生したイベント(eventlist
)を取得したりするために使用されます。kevent
構造体は、監視対象のファイルディスクリプタ、イベントの種類(読み込み可能、書き込み可能、ファイル変更など)、およびイベント発生時の追加情報を含みます。
これらのシステムコールは、多数のI/O操作を効率的に処理するサーバーアプリケーションや、非同期処理を多用するプログラムにおいて、CPUリソースを節約し、高いスループットを実現するために不可欠です。
技術的詳細
このコミットは、GoランタイムのFreeBSD/386およびOpenBSD/386向けのシステムコールラッパーを定義しているアセンブリファイル(.s
ファイル)内のシステムコール番号を修正しています。
具体的には、以下のファイルが変更されています。
src/pkg/runtime/sys_freebsd_386.s
src/pkg/runtime/sys_openbsd_386.s
これらのファイルは、Goランタイムが特定のOS/アーキテクチャ上でシステムコールを呼び出すための低レベルなアセンブリコードを含んでいます。Goの関数(例: runtime·kqueue
, runtime·kevent
)が呼び出されると、対応するアセンブリコードが実行され、MOVL
命令でシステムコール番号をAX
レジスタ(32ビットモードではEAX
レジスタの下位16ビット、またはEAX
全体)に設定し、その後INT $0x80
命令でカーネルにトラップします。
変更内容は以下の通りです。
FreeBSD/386 (sys_freebsd_386.s
):
runtime·kqueue
関数内で、kqueue
システムコールの番号を269
から362
に修正。runtime·kevent
関数内で、kevent
システムコールの番号を270
から363
に修正。
OpenBSD/386 (sys_openbsd_386.s
):
runtime·kqueue
関数内で、kqueue
システムコールの番号を362
から269
に修正。runtime·kevent
関数内で、kevent
システムコールの番号を363
から270
に修正。
注目すべきは、FreeBSDとOpenBSDでkqueue
/kevent
のシステムコール番号が逆転している点です。これは、それぞれのOSが独立してシステムコール番号を割り当てているため、このような食い違いが発生することがあります。Goランタイムは、各OS/アーキテクチャの正確なシステムコール番号に合わせてコードを調整する必要があります。
この修正により、GoプログラムがFreeBSD/386およびOpenBSD/386上でkqueue
/kevent
ベースのイベント通知メカニズムを正しく利用できるようになり、ネットワーキングやその他の非同期I/O操作が安定して機能するようになります。
コアとなるコードの変更箇所
diff --git a/src/pkg/runtime/sys_freebsd_386.s b/src/pkg/runtime/sys_freebsd_386.s
index 26ccb845f0..8b4d2317dc 100644
--- a/src/pkg/runtime/sys_freebsd_386.s
+++ b/src/pkg/runtime/sys_freebsd_386.s
@@ -350,7 +350,7 @@ TEXT runtime·sigprocmask(SB),NOSPLIT,$16
// int32 runtime·kqueue(void);\n TEXT runtime·kqueue(SB),NOSPLIT,$0
-\tMOVL\t$269, AX
+\tMOVL\t$362, AX
INT\t$0x80
JAE\t2(PC)
NEGL\tAX
@@ -358,7 +358,7 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
TEXT runtime·kevent(SB),NOSPLIT,$0
-\tMOVL\t$270, AX
+\tMOVL\t$363, AX
INT\t$0x80
JAE\t2(PC)
NEGL\tAX
diff --git a/src/pkg/runtime/sys_openbsd_386.s b/src/pkg/runtime/sys_openbsd_386.s
index 54d368fd70..e1ec5337ae 100644
--- a/src/pkg/runtime/sys_openbsd_386.s
+++ b/src/pkg/runtime/sys_openbsd_386.s
@@ -354,7 +354,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$28
// int32 runtime·kqueue(void);\n TEXT runtime·kqueue(SB),NOSPLIT,$0
-\tMOVL\t$362, AX
+\tMOVL\t$269, AX
INT\t$0x80
JAE\t2(PC)
NEGL\tAX
@@ -362,7 +362,7 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
TEXT runtime·kevent(SB),NOSPLIT,$0
-\tMOVL\t$363, AX
+\tMOVL\t$270, AX
INT\t$0x80
JAE\t2(PC)
NEGL\tAX
コアとなるコードの解説
このコミットのコアとなる変更は、GoランタイムのアセンブリコードにおけるMOVL
命令のオペランド(即値)の修正です。
MOVL $VALUE, AX
: このアセンブリ命令は、即値VALUE
をAX
レジスタ(またはEAX
レジスタ)に移動させます。システムコールを呼び出す際、このVALUE
がシステムコール番号としてカーネルに渡されます。
変更前は、FreeBSD/386とOpenBSD/386でkqueue
とkevent
のシステムコール番号が誤って設定されていました。
FreeBSD/386:
runtime·kqueue
:MOVL $269, AX
をMOVL $362, AX
に変更。runtime·kevent
:MOVL $270, AX
をMOVL $363, AX
に変更。
OpenBSD/386:
runtime·kqueue
:MOVL $362, AX
をMOVL $269, AX
に変更。runtime·kevent
:MOVL $363, AX
をMOVL $270, AX
に変更。
これらの修正は、各OS/アーキテクチャにおけるkqueue
およびkevent
システムコールの実際の番号に合わせることで、Goランタイムがこれらのシステムコールを正しく呼び出せるようにします。これにより、Goのネットワーキングやイベント処理の機能が、FreeBSD/386およびOpenBSD/386環境で期待通りに動作するようになります。
アセンブリコードの変更は非常に低レベルですが、OSとのインターフェースを正確に保つ上で極めて重要です。誤ったシステムコール番号は、プログラムのクラッシュ、不正な動作、またはセキュリティ上の脆弱性につながる可能性があります。
関連リンク
- Go CL 12876044: https://golang.org/cl/12876044 (このコミットに対応するGoの変更リスト)
- FreeBSD kqueue(2) man page: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
- OpenBSD kqueue(2) man page: https://man.openbsd.org/kqueue.2
- FreeBSD syscalls.master (システムコール番号の定義): https://github.com/freebsd/freebsd-src/blob/main/sys/kern/syscalls.master (当時のバージョンとは異なる可能性があります)
- OpenBSD syscalls.master (システムコール番号の定義): https://github.com/openbsd/src/blob/master/sys/kern/syscalls.master (当時のバージョンとは異なる可能性があります)
参考にした情報源リンク
- Goのソースコード (特に
src/pkg/runtime
ディレクトリ内の各OS/アーキテクチャ向けのアセンブリファイル) - FreeBSDおよびOpenBSDのシステムコールに関するドキュメントとソースコード
- x86アセンブリ言語のドキュメント
- システムコールと
INT 0x80
に関する一般的な情報源 (例: Wikipedia, OSの教科書) kqueue
/kevent
に関する技術記事やドキュメント- GoのIssueトラッカーやメーリングリスト (このコミットに関連する議論がある場合)