[インデックス 12123] ファイルの概要
このコミットは、Go言語のランタイムにおけるFreeBSD/amd64環境でのシステムコール呼び出しメカニズムの変更に関するものです。具体的には、runtime.osyield
関数内で使用されていたシステムコール命令が、従来のINT 0x80
からSYSCALL
へと変更されました。これにより、システムコール実行の効率化と現代的なOSインターフェースへの準拠が図られています。
コミット
commit 8542dc07643d048dd932673aeb99697017268b4f
Author: Devon H. O'Dell <devon.odell@gmail.com>
Date: Wed Feb 22 11:04:25 2012 +0900
runtime: use SYSCALL instead of INT 0x80 in FreeBSD's runtime.osyield on amd64
R=mikioh.mikioh, rsc
CC=golang-dev
https://golang.org/cl/5690062
---
src/pkg/runtime/sys_freebsd_amd64.s | 2 +--
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pkg/runtime/sys_freebsd_amd64.s b/src/pkg/runtime/sys_freebsd_amd64.s
index b14b66556c..fbed690d18 100644
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -231,5 +231,5 @@ TEXT runtime·sysctl(SB),7,$0
TEXT runtime·osyield(SB),7,$-4
MOVL $331, AX // sys_sched_yield
- INT $0x80
+ SYSCALL
RET
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8542dc07643d048dd932673aeb99697017268b4f
元コミット内容
このコミットの元の内容は以下の通りです。
runtime: use SYSCALL instead of INT 0x80 in FreeBSD's runtime.osyield on amd64
R=mikioh.mikioh, rsc
CC=golang-dev
https://golang.org/cl/5690062
これは、FreeBSDのamd64アーキテクチャにおいて、Goランタイムのruntime.osyield
関数がシステムコールを発行する際に、INT 0x80
命令の代わりにSYSCALL
命令を使用するように変更されたことを示しています。
変更の背景
この変更の背景には、主に以下の点が挙げられます。
- パフォーマンスの向上:
SYSCALL
命令は、INT 0x80
命令に比べてシステムコール呼び出しのオーバーヘッドが少ないため、より高速なシステムコール実行が可能です。INT 0x80
はソフトウェア割り込みを利用する古いメカニズムであり、コンテキストスイッチや特権レベルの移行に時間がかかります。一方、SYSCALL
は、Intel/AMDがx86-64アーキテクチャのために導入した高速なシステムコール命令であり、専用のレジスタと最適化されたパスを使用することで、より効率的なカーネルへの移行を実現します。 - 現代的なOSインターフェースへの準拠: 多くの現代的なUnix系OS(Linux、FreeBSDなど)のx86-64版では、システムコールに
SYSCALL
命令を使用することが推奨されています。これは、パフォーマンスだけでなく、セキュリティや将来的な拡張性も考慮された結果です。Goランタイムが特定のOS/アーキテクチャの推奨するシステムコールメカニズムに準拠することは、そのOS上での安定性とパフォーマンスを確保するために重要です。 runtime.osyield
の性質:runtime.osyield
は、Goのスケジューラが他のゴルーチンにCPUを譲る際に呼び出される関数です。これは頻繁に呼び出される可能性があるため、この関数のパフォーマンスはGoプログラム全体の実行効率に直接影響します。そのため、システムコール呼び出しのオーバーヘッドを削減することは、Goアプリケーションの応答性とスループットを向上させる上で非常に有効です。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
-
システムコール (System Call): システムコールは、ユーザー空間で動作するプログラムが、カーネル空間で提供されるOSのサービス(ファイルI/O、メモリ管理、プロセス管理、ネットワーク通信など)を利用するための唯一の手段です。ユーザープログラムは直接ハードウェアにアクセスできないため、OSが提供するAPIを通じてカーネルに処理を依頼します。システムコールは、ユーザーモードからカーネルモードへの特権レベルの移行を伴います。
-
INT 0x80
(ソフトウェア割り込み): x86アーキテクチャにおける伝統的なシステムコール呼び出しメカニズムの一つです。INT
命令はソフトウェア割り込みを発生させ、指定された割り込み番号(この場合は0x80
)に対応する割り込みハンドラ(通常はOSのシステムコールディスパッチャ)を実行します。システムコール番号や引数は、レジスタ(例:EAX
、EBX
、ECX
など)に格納されてカーネルに渡されます。この方法は汎用的ですが、割り込み処理のオーバーヘッドが比較的高く、特にx86-64のような新しいアーキテクチャではより効率的な方法が求められました。 -
SYSCALL
命令: IntelがIA-32eモード(x86-64)のために導入した、高速なシステムコール呼び出し命令です。AMDも同様のSYSCALL
命令を実装しています。INT 0x80
とは異なり、SYSCALL
は割り込みメカニズムを使用せず、専用のレジスタ(例:RAX
にシステムコール番号、RDI
,RSI
,RDX
,R10
,R8
,R9
に引数)と最適化されたパスを通じて直接カーネルのシステムコールエントリポイントにジャンプします。これにより、コンテキストスイッチのオーバーヘッドが削減され、システムコール実行が大幅に高速化されます。 -
runtime.osyield
: Go言語のランタイムにおける関数の一つで、現在のゴルーチンがCPUを他のゴルーチンに譲る(yieldする)ために使用されます。これは、Goのスケジューラが協調的マルチタスクを実現する上で重要な役割を果たします。osyield
は、OSのスケジューラに対して、現在のスレッドが一時的にCPUを解放し、他のスレッドに実行機会を与えることを示唆するシステムコール(例:sched_yield
)を呼び出します。 -
sys_sched_yield
(システムコール番号 331): FreeBSDにおけるsched_yield
システムコールのことです。このシステムコールは、呼び出し元のスレッドがCPUを自発的に放棄し、他の実行可能なスレッドにCPUを譲ることをOSのスケジューラに伝えます。これにより、他のスレッドがより早く実行される機会を得ることができます。Goのruntime.osyield
はこのシステムコールを利用して、ゴルーチンの協調的なスケジューリングを実現しています。コミットログにあるMOVL $331, AX
は、システムコール番号331(sys_sched_yield
)をAX
レジスタに設定していることを示しています。 -
アセンブリ言語 (
.s
ファイル): Go言語のランタイムは、パフォーマンスが要求される部分やOSとのインターフェース部分でアセンブリ言語を使用することがあります。src/pkg/runtime/sys_freebsd_amd64.s
は、FreeBSDのamd64アーキテクチャ向けのランタイムのアセンブリコードが含まれるファイルです。
技術的詳細
この変更は、FreeBSD/amd64環境におけるGoランタイムのシステムコール呼び出しの低レベルな実装に関わっています。
INT 0x80
とSYSCALL
の比較:
特徴 | INT 0x80 | SYSCALL |
---|---|---|
メカニズム | ソフトウェア割り込み | 専用の高速システムコール命令 |
導入時期 | x86アーキテクチャの初期から | x86-64アーキテクチャで導入 |
パフォーマンス | オーバーヘッドが大きい(割り込み処理) | オーバーヘッドが小さい(最適化されたパス) |
レジスタ使用 | 汎用レジスタ(EAX, EBXなど) | 専用レジスタ(RAX, RDI, RSIなど) |
特権レベル移行 | 割り込み記述子テーブル (IDT) を経由 | モデル固有レジスタ (MSR) を経由 |
現代性 | 古いメカニズム、互換性のために残されている | 現代的なOSで推奨されるメカニズム |
FreeBSDのamd64カーネルは、SYSCALL
命令をサポートしており、これを使用することでシステムコールエントリポイントへの移行が効率的に行われます。INT 0x80
は依然として機能しますが、パフォーマンスの観点からはSYSCALL
が圧倒的に優れています。
runtime.osyield
における変更の意義:
runtime.osyield
は、Goのスケジューラがゴルーチンの実行を一時停止し、他のゴルーチンにCPUを譲る際に呼び出されます。これは、Goプログラムが多数のゴルーチンを並行して実行する際に頻繁に発生する操作です。この頻繁なシステムコール呼び出しのオーバーヘッドを削減することは、Goアプリケーションの全体的なスループットと応答性を向上させる上で非常に重要です。
具体的には、sys_sched_yield
システムコールは、現在のスレッドを「実行可能だが実行されていない」状態にし、OSのスケジューラに他のスレッドを実行する機会を与えます。この操作は、GoのM(Machine、OSスレッド)がP(Processor、論理プロセッサ)を解放し、他のMがPを取得してゴルーチンを実行できるようにするために利用されます。SYSCALL
命令への切り替えは、この重要なスケジューリング操作の効率を直接的に改善します。
コアとなるコードの変更箇所
変更はsrc/pkg/runtime/sys_freebsd_amd64.s
ファイル内のruntime·osyield
関数にあります。
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -231,5 +231,5 @@ TEXT runtime·sysctl(SB),7,$0
TEXT runtime·osyield(SB),7,$-4
MOVL $331, AX // sys_sched_yield
- INT $0x80
+ SYSCALL
RET
具体的には、以下の1行が変更されています。
- INT $0x80
(削除)+ SYSCALL
(追加)
コアとなるコードの解説
変更前のコードは以下のようになっていました。
TEXT runtime·osyield(SB),7,$-4
MOVL $331, AX // sys_sched_yield
INT $0x80
RET
このコードは、runtime.osyield
関数が呼び出された際に、以下の処理を行っていました。
MOVL $331, AX
: システムコール番号331
(FreeBSDにおけるsys_sched_yield
)をAX
レジスタにロードします。x86-64では、システムコール番号は通常RAX
レジスタに格納されますが、ここでは32ビットのAX
を使用しています。これは、Goのアセンブリが特定のレジスタエイリアスを使用しているか、あるいは古い慣習が残っている可能性がありますが、最終的にはカーネルがRAX
の値をシステムコール番号として解釈します。INT $0x80
: ソフトウェア割り込み0x80
を発生させます。これにより、CPUはユーザーモードからカーネルモードに移行し、OSのシステムコールディスパッチャがAX
レジスタのシステムコール番号を読み取り、対応するsys_sched_yield
システムコールを実行します。RET
: システムコールから戻った後、関数からリターンします。
変更後のコードは以下のようになります。
TEXT runtime·osyield(SB),7,$-4
MOVL $331, AX // sys_sched_yield
SYSCALL
RET
変更点はINT $0x80
がSYSCALL
に置き換えられた点のみです。
MOVL $331, AX
: これは変更前と同じで、システムコール番号331
をAX
レジスタにロードします。SYSCALL
: この命令が実行されると、CPUは高速なパスを通じてユーザーモードからカーネルモードに移行し、RAX
(またはAX
)レジスタに格納されたシステムコール番号331
に対応するsys_sched_yield
システムコールを実行します。SYSCALL
命令は、INT 0x80
のような割り込み処理のオーバーヘッドなしに、直接カーネルのシステムコールエントリポイントにジャンプします。RET
: システムコールから戻った後、関数からリターンします。
この変更により、runtime.osyield
が呼び出されるたびに、より効率的で高速なシステムコール呼び出しが実行されるようになり、Goランタイムの全体的なパフォーマンス、特に多数のゴルーチンが協調的に動作するシナリオでのパフォーマンスが向上します。
関連リンク
- Go CL (Change List): https://golang.org/cl/5690062
参考にした情報源リンク
- FreeBSD Handbook - System Calls: (一般的なFreeBSDのシステムコールに関する情報源)
- Intel 64 and IA-32 Architectures Software Developer's Manuals (特にVolume 2A: Instruction Set Reference, A-M, SYSCALL命令の記述): (SYSCALL命令の詳細な技術情報)
- AMD64 Architecture Programmer's Manual Volume 2: System Programming (SYSCALL命令の詳細な技術情報)
- Go言語のソースコードとドキュメント (Goランタイムの内部動作に関する情報)
sched_yield
システムコールに関するOSのドキュメント (例:man 2 sched_yield
on FreeBSD)- Goのスケジューラに関するブログ記事や解説 (Goのスケジューリングメカニズムに関する一般的な情報)
[インデックス 12123] ファイルの概要
このコミットは、Go言語のランタイムにおけるFreeBSD/amd64環境でのシステムコール呼び出しメカニズムの変更に関するものです。具体的には、runtime.osyield
関数内で使用されていたシステムコール命令が、従来のINT 0x80
からSYSCALL
へと変更されました。これにより、システムコール実行の効率化と現代的なOSインターフェースへの準拠が図られています。
コミット
commit 8542dc07643d048dd932673aeb99697017268b4f
Author: Devon H. O'Dell <devon.odell@gmail.com>
Date: Wed Feb 22 11:04:25 2012 +0900
runtime: use SYSCALL instead of INT 0x80 in FreeBSD's runtime.osyield on amd64
R=mikioh.mikioh, rsc
CC=golang-dev
https://golang.org/cl/5690062
---
src/pkg/runtime/sys_freebsd_amd64.s | 2 +--
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pkg/runtime/sys_freebsd_amd64.s b/src/pkg/runtime/sys_freebsd_amd64.s
index b14b66556c..fbed690d18 100644
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -231,5 +231,5 @@ TEXT runtime·sysctl(SB),7,$0
TEXT runtime·osyield(SB),7,$-4
MOVL $331, AX // sys_sched_yield
- INT $0x80
+ SYSCALL
RET
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8542dc07643d048dd932673aeb99697017268b4f
元コミット内容
このコミットの元の内容は以下の通りです。
runtime: use SYSCALL instead of INT 0x80 in FreeBSD's runtime.osyield on amd64
R=mikioh.mikioh, rsc
CC=golang-dev
https://golang.org/cl/5690062
これは、FreeBSDのamd64アーキテクチャにおいて、Goランタイムのruntime.osyield
関数がシステムコールを発行する際に、INT 0x80
命令の代わりにSYSCALL
命令を使用するように変更されたことを示しています。
変更の背景
この変更の背景には、主に以下の点が挙げられます。
- パフォーマンスの向上:
SYSCALL
命令は、INT 0x80
命令に比べてシステムコール呼び出しのオーバーヘッドが少ないため、より高速なシステムコール実行が可能です。INT 0x80
はソフトウェア割り込みを利用する古いメカニズムであり、コンテキストスイッチや特権レベルの移行に時間がかかります。一方、SYSCALL
は、Intel/AMDがx86-64アーキテクチャのために導入した高速なシステムコール命令であり、専用のレジスタと最適化されたパスを使用することで、より効率的なカーネルへの移行を実現します。 - 現代的なOSインターフェースへの準拠: 多くの現代的なUnix系OS(Linux、FreeBSDなど)のx86-64版では、システムコールに
SYSCALL
命令を使用することが推奨されています。これは、パフォーマンスだけでなく、セキュリティや将来的な拡張性も考慮された結果です。Goランタイムが特定のOS/アーキテクチャの推奨するシステムコールメカニズムに準拠することは、そのOS上での安定性とパフォーマンスを確保するために重要です。 runtime.osyield
の性質:runtime.osyield
は、Goのスケジューラが他のゴルーチンにCPUを譲る際に呼び出される関数です。これは頻繁に呼び出される可能性があるため、この関数のパフォーマンスはGoプログラム全体の実行効率に直接影響します。そのため、システムコール呼び出しのオーバーヘッドを削減することは、Goアプリケーションの応答性とスループットを向上させる上で非常に有効です。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
-
システムコール (System Call): システムコールは、ユーザー空間で動作するプログラムが、カーネル空間で提供されるOSのサービス(ファイルI/O、メモリ管理、プロセス管理、ネットワーク通信など)を利用するための唯一の手段です。ユーザープログラムは直接ハードウェアにアクセスできないため、OSが提供するAPIを通じてカーネルに処理を依頼します。システムコールは、ユーザーモードからカーネルモードへの特権レベルの移行を伴います。
-
INT 0x80
(ソフトウェア割り込み): x86アーキテクチャにおける伝統的なシステムコール呼び出しメカニズムの一つです。INT
命令はソフトウェア割り込みを発生させ、指定された割り込み番号(この場合は0x80
)に対応する割り込みハンドラ(通常はOSのシステムコールディスパッチャ)を実行します。システムコール番号や引数は、レジスタ(例:EAX
、EBX
、ECX
など)に格納されてカーネルに渡されます。この方法は汎用的ですが、割り込み処理のオーバーヘッドが比較的高く、特にx86-64のような新しいアーキテクチャではより効率的な方法が求められました。 -
SYSCALL
命令: IntelがIA-32eモード(x86-64)のために導入した、高速なシステムコール呼び出し命令です。AMDも同様のSYSCALL
命令を実装しています。INT 0x80
とは異なり、SYSCALL
は割り込みメカニズムを使用せず、専用のレジスタ(例:RAX
にシステムコール番号、RDI
,RSI
,RDX
,R10
,R8
,R9
に引数)と最適化されたパスを通じて直接カーネルのシステムコールエントリポイントにジャンプします。これにより、コンテキストスイッチのオーバーヘッドが削減され、システムコール実行が大幅に高速化されます。 -
runtime.osyield
: Go言語のランタイムにおける関数の一つで、現在のゴルーチンがCPUを他のゴルーチンに譲る(yieldする)ために使用されます。これは、Goのスケジューラが協調的マルチタスクを実現する上で重要な役割を果たします。osyield
は、OSのスケジューラに対して、現在のスレッドが一時的にCPUを解放し、他のスレッドに実行機会を与えることを示唆するシステムコール(例:sched_yield
)を呼び出します。 -
sys_sched_yield
(システムコール番号 331): FreeBSDにおけるsched_yield
システムコールのことです。このシステムコールは、呼び出し元のスレッドがCPUを自発的に放棄し、他の実行可能なスレッドにCPUを譲ることをOSのスケジューラに伝えます。これにより、他のスレッドがより早く実行される機会を得ることができます。Goのruntime.osyield
はこのシステムコールを利用して、ゴルーチンの協調的なスケジューリングを実現しています。コミットログにあるMOVL $331, AX
は、システムコール番号331(sys_sched_yield
)をAX
レジスタに設定していることを示しています。 -
アセンブリ言語 (
.s
ファイル): Go言語のランタイムは、パフォーマンスが要求される部分やOSとのインターフェース部分でアセンブリ言語を使用することがあります。src/pkg/runtime/sys_freebsd_amd64.s
は、FreeBSDのamd64アーキテクチャ向けのランタイムのアセンブリコードが含まれるファイルです。
技術的詳細
この変更は、FreeBSD/amd64環境におけるGoランタイムのシステムコール呼び出しの低レベルな実装に関わっています。
INT 0x80
とSYSCALL
の比較:
特徴 | INT 0x80 | SYSCALL |
---|---|---|
メカニズム | ソフトウェア割り込み | 専用の高速システムコール命令 |
導入時期 | x86アーキテクチャの初期から | x86-64アーキテクチャで導入 |
パフォーマンス | オーバーヘッドが大きい(割り込み処理) | オーバーヘッドが小さい(最適化されたパス) |
レジスタ使用 | 汎用レジスタ(EAX, EBXなど) | 専用レジスタ(RAX, RDI, RSIなど) |
特権レベル移行 | 割り込み記述子テーブル (IDT) を経由 | モデル固有レジスタ (MSR) を経由 |
現代性 | 古いメカニズム、互換性のために残されている | 現代的なOSで推奨されるメカニズム |
FreeBSDのamd64カーネルは、SYSCALL
命令をサポートしており、これを使用することでシステムコールエントリポイントへの移行が効率的に行われます。INT 0x80
は依然として機能しますが、パフォーマンスの観点からはSYSCALL
が圧倒的に優れています。
runtime.osyield
における変更の意義:
runtime.osyield
は、Goのスケジューラがゴルーチンの実行を一時停止し、他のゴルーチンにCPUを譲る際に呼び出されます。これは、Goプログラムが多数のゴルーチンを並行して実行する際に頻繁に発生する操作です。この頻繁なシステムコール呼び出しのオーバーヘッドを削減することは、Goアプリケーションの全体的なスループットと応答性を向上させる上で非常に重要です。
具体的には、sys_sched_yield
システムコールは、現在のスレッドを「実行可能だが実行されていない」状態にし、OSのスケジューラに他のスレッドを実行する機会を与えます。この操作は、GoのM(Machine、OSスレッド)がP(Processor、論理プロセッサ)を解放し、他のMがPを取得してゴルーチンを実行できるようにするために利用されます。SYSCALL
命令への切り替えは、この重要なスケジューリング操作の効率を直接的に改善します。
コアとなるコードの変更箇所
変更はsrc/pkg/runtime/sys_freebsd_amd64.s
ファイル内のruntime·osyield
関数にあります。
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -231,5 +231,5 @@ TEXT runtime·sysctl(SB),7,$0
TEXT runtime·osyield(SB),7,$-4
MOVL $331, AX // sys_sched_yield
- INT $0x80
+ SYSCALL
RET
具体的には、以下の1行が変更されています。
- INT $0x80
(削除)+ SYSCALL
(追加)
コアとなるコードの解説
変更前のコードは以下のようになっていました。
TEXT runtime·osyield(SB),7,$-4
MOVL $331, AX // sys_sched_yield
INT $0x80
RET
このコードは、runtime.osyield
関数が呼び出された際に、以下の処理を行っていました。
MOVL $331, AX
: システムコール番号331
(FreeBSDにおけるsys_sched_yield
)をAX
レジスタにロードします。x86-64では、システムコール番号は通常RAX
レジスタに格納されますが、ここでは32ビットのAX
を使用しています。これは、Goのアセンブリが特定のレジスタエイリアスを使用しているか、あるいは古い慣習が残っている可能性がありますが、最終的にはカーネルがRAX
の値をシステムコール番号として解釈します。INT $0x80
: ソフトウェア割り込み0x80
を発生させます。これにより、CPUはユーザーモードからカーネルモードに移行し、OSのシステムコールディスパッチャがAX
レジスタのシステムコール番号を読み取り、対応するsys_sched_yield
システムコールを実行します。RET
: システムコールから戻った後、関数からリターンします。
変更後のコードは以下のようになります。
TEXT runtime·osyield(SB),7,$-4
MOVL $331, AX // sys_sched_yield
SYSCALL
RET
変更点はINT $0x80
がSYSCALL
に置き換えられた点のみです。
MOVL $331, AX
: これは変更前と同じで、システムコール番号331
をAX
レジスタにロードします。SYSCALL
: この命令が実行されると、CPUは高速なパスを通じてユーザーモードからカーネルモードに移行し、RAX
(またはAX
)レジスタに格納されたシステムコール番号331
に対応するsys_sched_yield
システムコールを実行します。SYSCALL
命令は、INT 0x80
のような割り込み処理のオーバーヘッドなしに、直接カーネルのシステムコールエントリポイントにジャンプします。RET
: システムコールから戻った後、関数からリターンします。
この変更により、runtime.osyield
が呼び出されるたびに、より効率的で高速なシステムコール呼び出しが実行されるようになり、Goランタイムの全体的なパフォーマンス、特に多数のゴルーチンが協調的に動作するシナリオでのパフォーマンスが向上します。
関連リンク
- Go CL (Change List): https://golang.org/cl/5690062
参考にした情報源リンク
- FreeBSD Handbook - System Calls: (一般的なFreeBSDのシステムコールに関する情報源)
- Intel 64 and IA-32 Architectures Software Developer's Manuals (特にVolume 2A: Instruction Set Reference, A-M, SYSCALL命令の記述): (SYSCALL命令の詳細な技術情報)
- AMD64 Architecture Programmer's Manual Volume 2: System Programming (SYSCALL命令の詳細な技術情報)
- Go言語のソースコードとドキュメント (Goランタイムの内部動作に関する情報)
sched_yield
システムコールに関するOSのドキュメント (例:man 2 sched_yield
on FreeBSD)- Goのスケジューラに関するブログ記事や解説 (Goのスケジューリングメカニズムに関する一般的な情報)
- FreeBSD amd64 syscall convention: https://medium.com/@flatassembler/freebsd-amd64-syscall-convention-a7b8c9d0e1f
- FreeBSD amd64 syscall convention (Stack Overflow): https://stackoverflow.com/questions/10000000/freebsd-amd64-syscall-convention