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

[インデックス 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プログラムが正しく動作しない、あるいは予期せぬ挙動を示す可能性がありました。

kqueuekeventは、FreeBSD、OpenBSD、NetBSD、macOSなどのBSD系OSで広く利用されている、効率的なイベント通知インターフェースです。ネットワークI/O、ファイルシステムイベント、タイマーなど、様々な非同期イベントを監視するために使用されます。Goのネットワーキングや並行処理の基盤において、これらのシステムコールは重要な役割を担っています。

誤ったシステムコール番号を使用することは、プログラムが意図しないカーネル関数を呼び出そうとするか、あるいは存在しないシステムコールを呼び出そうとすることを意味します。これは通常、ENOSYS(Function not implemented)のようなエラーを返すか、あるいはより深刻な場合はクラッシュを引き起こす可能性があります。このコミットは、これらのプラットフォームでのGoプログラムの安定性と正確性を確保するために不可欠な修正でした。

前提知識の解説

システムコール (Syscall)

システムコールは、オペレーティングシステム(OS)のカーネルが提供するサービスを、ユーザー空間のプログラムが利用するためのインターフェースです。ファイル操作(読み書き)、ネットワーク通信、メモリ管理、プロセス制御など、OSの重要な機能はシステムコールを通じて提供されます。

プログラムがシステムコールを呼び出す際、通常は以下の手順を踏みます。

  1. システムコール番号の設定: 呼び出したいシステムコールに対応する一意の番号を、特定のレジスタ(x86アーキテクチャでは通常EAXまたはAX)に設定します。
  2. 引数の設定: システムコールに渡す引数を、他のレジスタやスタックに設定します。
  3. トラップ命令の実行: INT 0x80(x86アーキテクチャのLinuxやBSD系OS)やSYSCALL(x86-64アーキテクチャ)のような特別な命令を実行し、CPUをユーザーモードからカーネルモードに切り替えます。これにより、実行がカーネルに渡されます。
  4. カーネルでの処理: カーネルは、レジスタに設定されたシステムコール番号を読み取り、対応するカーネル関数を実行します。
  5. 結果の返却: カーネルは処理結果をレジスタに設定し、ユーザーモードに制御を戻します。

システムコール番号は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など)に格納されていることが一般的です。

kqueuekevent

kqueuekeventは、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: このアセンブリ命令は、即値VALUEAXレジスタ(またはEAXレジスタ)に移動させます。システムコールを呼び出す際、このVALUEがシステムコール番号としてカーネルに渡されます。

変更前は、FreeBSD/386とOpenBSD/386でkqueuekeventのシステムコール番号が誤って設定されていました。

FreeBSD/386:

  • runtime·kqueue: MOVL $269, AXMOVL $362, AX に変更。
  • runtime·kevent: MOVL $270, AXMOVL $363, AX に変更。

OpenBSD/386:

  • runtime·kqueue: MOVL $362, AXMOVL $269, AX に変更。
  • runtime·kevent: MOVL $363, AXMOVL $270, AX に変更。

これらの修正は、各OS/アーキテクチャにおけるkqueueおよびkeventシステムコールの実際の番号に合わせることで、Goランタイムがこれらのシステムコールを正しく呼び出せるようにします。これにより、Goのネットワーキングやイベント処理の機能が、FreeBSD/386およびOpenBSD/386環境で期待通りに動作するようになります。

アセンブリコードの変更は非常に低レベルですが、OSとのインターフェースを正確に保つ上で極めて重要です。誤ったシステムコール番号は、プログラムのクラッシュ、不正な動作、またはセキュリティ上の脆弱性につながる可能性があります。

関連リンク

参考にした情報源リンク

  • Goのソースコード (特にsrc/pkg/runtimeディレクトリ内の各OS/アーキテクチャ向けのアセンブリファイル)
  • FreeBSDおよびOpenBSDのシステムコールに関するドキュメントとソースコード
  • x86アセンブリ言語のドキュメント
  • システムコールとINT 0x80に関する一般的な情報源 (例: Wikipedia, OSの教科書)
  • kqueue/keventに関する技術記事やドキュメント
  • GoのIssueトラッカーやメーリングリスト (このコミットに関連する議論がある場合)