[インデックス 17704] ファイルの概要
このコミットは、Go言語のFreeBSD/ARM環境におけるシステムコール呼び出し規約をEABI(Embedded Application Binary Interface)に合わせるための変更です。これにより、FreeBSD/ARM上でのGoプログラムの動作の安定性と正確性が向上します。
コミット
commit 649a2a9be550abdacdaf45a7ad778d4f0b1f299a
Author: Dave Cheney <dave@cheney.net>
Date: Thu Sep 26 21:35:49 2013 +1000
runtime, syscall: update freebsd/arm calling convention to match EABI
Fixes #6451.
There is still some breakages unrelated to the syscall change.
[root@beaglebone ~/go/src]# /root/go/pkg/tool/freebsd_arm/go_bootstrap version
go version devel freebsd/arm
a std@beaglebone ~/go/src]# /root/go/pkg/tool/freebsd_arm/go_bootstrap install -
fatal error: mark - finalizer inconsistency
runtime stack:
runtime.throw(0x3e80ac)
/root/go/src/pkg/runtime/panic.c:464 +0x5c
addfinroots(0x2)
/root/go/src/pkg/runtime/mgc0.c:1501 +0x74
runtime.walkfintab(0x6c200)
/root/go/src/pkg/runtime/mfinal.c:216 +0xa0
addroots()
/root/go/src/pkg/runtime/mgc0.c:1561 +0x188
gc(0x50632f78)
/root/go/src/pkg/runtime/mgc0.c:2098 +0x19c
mgc(0x306170a0)
/root/go/src/pkg/runtime/mgc0.c:2049 +0x30
runtime.mcall(0x3e97b0)
/root/go/src/pkg/runtime/asm_arm.s:165 +0x3c
goroutine 1 [garbage collection]:
runtime.gc(0x0)
/root/go/src/pkg/runtime/mgc0.c:2020 +0x1a0 fp=0x50632f80
runtime.mallocgc(0x680, 0x1b1971, 0x1)
/root/go/src/pkg/runtime/malloc.goc:143 +0x210 fp=0x50632fbc
----- stack segment boundary -----
cnew(0x1b1970, 0x640, 0x1)
/root/go/src/pkg/runtime/malloc.goc:718 +0xc4 fp=0x50626110
runtime.cnewarray(0x1b1970, 0x640)
/root/go/src/pkg/runtime/malloc.goc:731 +0x3c fp=0x50626120
makeslice1(0x1ac6d0, 0x500, 0x640, 0x50626190)
/root/go/src/pkg/runtime/slice.c:57 +0x50 fp=0x5062612c
growslice1(0x1ac6d0, 0x30714a00, 0x500, 0x500, 0x501, ...)
/root/go/src/pkg/runtime/slice.c:113 +0x8c fp=0x50626144
runtime.growslice(0x1ac6d0, 0x30714a00, 0x500, 0x500, 0x1, ...)
/root/go/src/pkg/runtime/slice.c:80 +0x19c fp=0x50626174
go/build.(*importReader).readByte(0x3070d1b0, 0xb384e)
/root/go/src/pkg/go/build/read.go:43 +0xbc fp=0x506261b4
go/build.(*importReader).peekByte(0x3070d1b0, 0x3070d101, 0x3070d180)
/root/go/src/pkg/go/build/read.go:89 +0x210 fp=0x506261d0
go/build.readComments(0x203e2560, 0x306f79a8, 0x306f79a8, 0x203e2560, 0x306f79a8, ...)
/root/go/src/pkg/go/build/read.go:194 +0x84 fp=0x506261f4
go/build.(*Context).matchFile(0x3e9730, 0x306209c0, 0x13, 0x306c42b4, 0x5, ...)
/root/go/src/pkg/go/build/build.go:812 +0x74c fp=0x5062629c
go/build.(*Context).Import(0x3e9730, 0x1f95c8, 0x1, 0x30620960, 0x13, ...)
/root/go/src/pkg/go/build/build.go:580 +0xd64 fp=0x506268dc
go/build.(*Context).ImportDir(0x3e9730, 0x30620960, 0x13, 0x0, 0x24d901, ...)
/root/go/src/pkg/go/build/build.go:397 +0x5c fp=0x50626904
main.func·021(0x30620960, 0x13, 0x203e2200, 0x30680330, 0x0, ...)
/root/go/src/cmd/go/main.go:521 +0x2cc fp=0x5062696c
path/filepath.walk(0x30620960, 0x13, 0x203e2200, 0x30680330, 0x50626ae8, ...)
/root/go/src/pkg/path/filepath/path.go:341 +0x5c fp=0x506269d8
path/filepath.walk(0x3067e720, 0x11, 0x203e2200, 0x30680210, 0x50626ae8, ...)
/root/go/src/pkg/path/filepath/path.go:359 +0x308 fp=0x50626a44
path/filepath.Walk(0x3067e720, 0x11, 0x50626ae8, 0x1f9728, 0x1)
/root/go/src/pkg/path/filepath/path.go:380 +0xb4 fp=0x50626a68
main.matchPackages(0xbfffedea, 0x3, 0x1b1190, 0x3067e600, 0x10)
/root/go/src/cmd/go/main.go:530 +0x2c0 fp=0x50626b1c
main.allPackages(0xbfffedea, 0x3, 0x1fadc8, 0x3, 0x1)
/root/go/src/cmd/go/main.go:474 +0x34 fp=0x50626b70
main.importPathsNoDotExpansion(0x30620018, 0x1, 0x1, 0x0, 0xffffffff, ...)
/root/go/src/cmd/go/main.go:305 +0x2f8 fp=0x50626c04
main.importPaths(0x30620018, 0x1, 0x1, 0x3, 0x0, ...)
/root/go/src/cmd/go/main.go:315 +0x44 fp=0x50626c88
main.packagesAndErrors(0x30620018, 0x1, 0x1, 0x50626d60, 0x90f44, ...)
/root/go/src/cmd/go/pkg.go:798 +0x1bc fp=0x50626d1c
main.packagesForBuild(0x30620018, 0x1, 0x1, 0x53490, 0x0, ...)
/root/go/src/cmd/go/pkg.go:818 +0x44 fp=0x50626dac
main.runInstall(0x3e46e0, 0x30620018, 0x1, 0x1)
/root/go/src/cmd/go/build.go:311 +0x48 fp=0x50626e60
main.main()
/root/go/src/cmd/go/main.go:161 +0x518 fp=0x50626f8c
runtime.main()
/root/go/src/pkg/runtime/proc.c:222 +0x100 fp=0x50626fc0
runtime.goexit()
/root/go/src/pkg/runtime/proc.c:1396 fp=0x50626fc0
goroutine 3 [syscall]:
os/signal.loop()
/root/go/src/pkg/os/signal/signal_unix.go:21 +0x24
created by os/signal.init·1
/root/go/src/pkg/os/signal/signal_unix.go:27 +0x48
R=minux.ma, rsc
CC=golang-dev
https://golang.org/cl/13824044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/649a2a9be550abdacdaf45a7ad778d4f0b1f299a
元コミット内容
FreeBSD/ARM環境におけるGoランタイムとシステムコールの呼び出し規約をEABIに合わせるように更新する。
これはIssue #6451を修正するものである。
システムコールの変更とは無関係な、いくつかの破損がまだ残っている。
コミットメッセージには、BeagleBone上でのgo install
実行時に発生したfatal error: mark - finalizer inconsistency
というランタイムエラーのスタックトレースが含まれている。
変更の背景
このコミットの主な背景は、Go言語がFreeBSD/ARMアーキテクチャ上で正しく動作するためのシステムコール呼び出し規約の不一致を解消することです。特に、ARMアーキテクチャにはOABI (Old Application Binary Interface) とEABI (Embedded Application Binary Interface) の2つの主要なABIが存在します。GoのランタイムがFreeBSD/ARM上でシステムコールを呼び出す際、OSが期待するEABIの規約とGoランタイムが使用していた規約との間に齟齬があったため、システムコールが正しく実行されず、結果としてプログラムのクラッシュや予期せぬ動作を引き起こしていました。
コミットメッセージに記載されているfatal error: mark - finalizer inconsistency
というエラーは、ガベージコレクション(GC)に関連する問題を示唆しています。システムコールが正しく機能しない場合、メモリ管理やリソースの解放が適切に行われず、このようなGCの不整合を引き起こす可能性があります。このコミットは、システムコール呼び出し規約をEABIに準拠させることで、これらの低レベルな問題を解決し、FreeBSD/ARM上でのGoの安定性を向上させることを目的としています。
前提知識の解説
ARMアーキテクチャとABI (Application Binary Interface)
ARM (Advanced RISC Machine) は、モバイルデバイスや組み込みシステムで広く使用されているCPUアーキテクチャです。ARMプロセッサは、その低消費電力と高性能のバランスから、スマートフォン、タブレット、IoTデバイス、さらにはサーバーまで、多岐にわたる分野で採用されています。
ABI (Application Binary Interface) は、オペレーティングシステムとアプリケーション、または異なるモジュール間でバイナリレベルでの互換性を保証するための規約のセットです。これには、以下の要素が含まれます。
- レジスタの使用規約: 関数呼び出し時にどのレジスタが引数として使用され、どのレジスタが呼び出し元によって保存されるべきか、どのレジスタが呼び出し先によって変更されてもよいか、などが定義されます。
- スタックフレームのレイアウト: 関数呼び出し時のスタックの構造(ローカル変数、引数、戻りアドレスの配置など)が定義されます。
- システムコール規約: アプリケーションがOSのサービス(システムコール)を呼び出す際の引数の渡し方、戻り値の受け取り方、システムコール番号の指定方法などが定義されます。
- データ型の表現: 整数、浮動小数点数、ポインタなどのデータ型がメモリ上でどのように表現されるか(エンディアン、アライメントなど)が定義されます。
ARMアーキテクチャには、主に以下の2つのABIが存在します。
- OABI (Old Application Binary Interface): 以前のARM Linuxディストリビューションなどで使用されていました。システムコール呼び出し規約がEABIとは異なります。
- EABI (Embedded Application Binary Interface): 現在のARMベースのシステムで広く採用されている標準的なABIです。より効率的なコード生成と、異なるツールチェーン間での互換性を提供します。特に、浮動小数点演算の扱いがOABIと異なります。
Go言語のような低レベルなランタイムを持つ言語では、OSのシステムコールを直接呼び出す必要があるため、ターゲットアーキテクチャのABIに厳密に準拠することが不可欠です。ABIの不一致は、引数が正しく渡されない、戻り値が誤って解釈される、スタックが破損するなどの問題を引き起こし、プログラムのクラッシュやセキュリティ上の脆弱性につながる可能性があります。
FreeBSDのシステムコール
FreeBSDは、UNIX系のオペレーティングシステムであり、そのシステムコールは、アプリケーションがカーネルの機能にアクセスするためのインターフェースを提供します。システムコールは、ファイル操作、プロセス管理、メモリ管理、ネットワーク通信など、OSの基本的な機能を提供します。
ARMアーキテクチャにおけるFreeBSDのシステムコールは、通常、特定のレジスタにシステムコール番号と引数を設定し、SWI
(Software Interrupt) 命令を実行することで呼び出されます。SWI
命令は、CPUをユーザーモードからカーネルモードに切り替え、指定されたシステムコールハンドラを実行します。
Goランタイムとシステムコール
Go言語のランタイムは、ガベージコレクション、スケジューラ、メモリ管理など、Goプログラムの実行をサポートする低レベルなコンポーネントの集合体です。Goプログラムがファイルを開いたり、メモリを確保したり、ネットワーク通信を行ったりする際には、GoランタイムがOSのシステムコールを呼び出します。
Goランタイムは、各アーキテクチャとOSの組み合わせ(例: freebsd/arm
)に対して、その環境のABIに合わせたシステムコール呼び出しのコードをアセンブリ言語で実装しています。これにより、GoプログラムはOSの機能を効率的かつ安全に利用できます。
技術的詳細
このコミットは、主にsrc/pkg/runtime/sys_freebsd_arm.s
とsrc/pkg/syscall/asm_freebsd_arm.s
の2つのアセンブリファイルに対する変更を含んでいます。これらのファイルは、FreeBSD/ARM環境におけるGoランタイムとsyscall
パッケージがシステムコールを呼び出す際のアセンブリコードを定義しています。
変更の核心は、システムコール番号の渡し方と引数のレジスタ割り当てをEABIに準拠させることです。
EABIにおけるシステムコール呼び出し規約 (ARM)
EABIでは、システムコールを呼び出す際、以下の規約が一般的に使用されます。
- システムコール番号:
R7
レジスタにシステムコール番号を設定します。 - 引数: 最初の4つの引数は
R0
からR3
レジスタに渡されます。それ以降の引数はスタックに積まれます。 - システムコール命令:
SWI #0
(またはSVC #0
) 命令を実行します。これは、以前のOABIでシステムコール番号を直接SWI
命令のオペランドとして指定していたのとは異なります。
変更点の内訳
-
src/pkg/runtime/sys_freebsd_arm.s
:- システムコール番号の定義: 各システムコールに対応する番号を
#define
ディレクティブで定義しています。例えば、SYS_exit
、SYS_read
、SYS_write
などです。これらの定義は、FreeBSDのシステムコール番号と一致します。 SWI
命令の変更: 以前はSWI $システムコール番号
のように直接システムコール番号をオペランドとして指定していましたが、EABIに準拠するため、MOVW $SYS_syscall_name, R7
でR7
レジスタにシステムコール番号を設定し、その後SWI $0
を実行するように変更されています。- 引数の渡し方:
mmap
などの複数の引数を取るシステムコールにおいて、引数がレジスタとスタックに正しく配置されるように調整されています。特に、64ビット引数のアライメントに関する考慮が追加されています。
- システムコール番号の定義: 各システムコールに対応する番号を
-
src/pkg/syscall/asm_freebsd_arm.s
:Syscall
、Syscall6
、Syscall9
、RawSyscall
、RawSyscall6
関数の変更: これらの関数は、Goのsyscall
パッケージから呼び出される汎用的なシステムコールラッパーです。- 以前は、システムコール番号を
R0
レジスタに設定していましたが、EABIに合わせてR7
レジスタに設定するように変更されました。 - 引数のレジスタ割り当てが変更され、最初の引数が
R0
、2番目がR1
、3番目がR2
、4番目がR3
に渡されるようになりました。 - スタックに渡される引数のオフセットも、新しいレジスタ割り当てとEABIの規約に合わせて調整されています。
- 以前は、システムコール番号を
これらの変更により、Goランタイムとsyscall
パッケージは、FreeBSD/ARM環境でEABIに準拠した方法でシステムコールを呼び出すようになり、OSとの間のバイナリ互換性が確保されます。
コアとなるコードの変更箇所
src/pkg/runtime/sys_freebsd_arm.s
--- a/src/pkg/runtime/sys_freebsd_arm.s
+++ b/src/pkg/runtime/sys_freebsd_arm.s
@@ -8,6 +8,35 @@
#include "zasm_GOOS_GOARCH.h"
#include "../../cmd/ld/textflag.h"
+
+// for EABI, as we don't support OABI
+#define SYS_BASE 0x0
+
+#define SYS_exit (SYS_BASE + 1)
+#define SYS_read (SYS_BASE + 3)
+#define SYS_write (SYS_BASE + 4)
+#define SYS_open (SYS_BASE + 5)
+#define SYS_close (SYS_BASE + 6)
+#define SYS_sigaltstack (SYS_BASE + 53)
+#define SYS_munmap (SYS_BASE + 73)
+#define SYS_madvise (SYS_BASE + 75)
+#define SYS_setitimer (SYS_BASE + 83)
+#define SYS_fcntl (SYS_BASE + 92)
+#define SYS_getrlimit (SYS_BASE + 194)
+#define SYS___sysctl (SYS_BASE + 202)
+#define SYS_nanosleep (SYS_BASE + 240)
+#define SYS_clock_gettime (SYS_BASE + 232)
+#define SYS_sched_yield (SYS_BASE + 331)
+#define SYS_sigprocmask (SYS_BASE + 340)
+#define SYS_kqueue (SYS_BASE + 362)
+#define SYS_kevent (SYS_BASE + 363)
+#define SYS_sigaction (SYS_BASE + 416)
+#define SYS_thr_exit (SYS_BASE + 431)
+#define SYS_thr_self (SYS_BASE + 432)
+#define SYS_thr_kill (SYS_BASE + 433)
+#define SYS__umtx_op (SYS_BASE + 454)
+#define SYS_thr_new (SYS_BASE + 455)
+#define SYS_mmap (SYS_BASE + 477)
TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
MOVW 0(FP), R0
@@ -15,7 +44,8 @@ TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
MOVW 8(FP), R2
MOVW 12(FP), R3
ADD $20, R13 // arg 5 is passed on stack
- SWI $454
+ MOVW $SYS__umtx_op, R7
+ SWI $0
SUB $20, R13
// BCS error
RET
@@ -23,7 +53,8 @@ TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
TEXT runtime·thr_new(SB),NOSPLIT,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
- SWI $455
+ MOVW $SYS_thr_new, R7
+ SWI $0
RET
TEXT runtime·thr_start(SB),NOSPLIT,$0
@@ -41,14 +72,16 @@ TEXT runtime·thr_start(SB),NOSPLIT,$0
// Exit the entire program (like C exit)
TEXT runtime·exit(SB),NOSPLIT,$-8
MOVW 0(FP), R0 // arg 1 exit status
- SWI $1
+ MOVW $SYS_exit, R7
+ SWI $0
MOVW.CS $0, R8 // crash on syscall failure
MOVW.CS R8, (R8)
RET
TEXT runtime·exit1(SB),NOSPLIT,$-8
MOVW 0(FP), R0 // arg 1 exit status
- SWI $431
+ MOVW $SYS_thr_exit, R7
+ SWI $0
MOVW.CS $0, R8 // crash on syscall failure
MOVW.CS R8, (R8)
RET
@@ -57,57 +90,65 @@ TEXT runtime·open(SB),NOSPLIT,$-8
MOVW 0(FP), R0 // arg 1 name
MOVW 4(FP), R1 // arg 2 mode
MOVW 8(FP), R2 // arg 3 perm
- SWI $5
+ MOVW $SYS_open, R7
+ SWI $0
RET
TEXT runtime·read(SB),NOSPLIT,$-8
MOVW 0(FP), R0 // arg 1 fd
MOVW 4(FP), R1 // arg 2 buf
MOVW 8(FP), R2 // arg 3 count
- SWI $3
+ MOVW $SYS_read, R7
+ SWI $0
RET
TEXT runtime·write(SB),NOSPLIT,$-8
MOVW 0(FP), R0 // arg 1 fd
MOVW 4(FP), R1 // arg 2 buf
MOVW 8(FP), R2 // arg 3 count
- SWI $4
+ MOVW $SYS_write, R7
+ SWI $0
RET
TEXT runtime·close(SB),NOSPLIT,$-8
MOVW 0(FP), R0 // arg 1 fd
- SWI $6
+ MOVW $SYS_close, R7
+ SWI $0
RET
TEXT runtime·getrlimit(SB),NOSPLIT,$-8
MOVW 0(FP), R0
MOVW 4(FP), R1
- MOVW 8(FP), R2
- SWI $194
+ MOVW $SYS_getrlimit, R7
+ SWI $0
RET
TEXT runtime·raise(SB),NOSPLIT,$8
// thr_self(&4(R13))\n
MOVW $4(R13), R0 // arg 1 &4(R13)\n
- SWI $432
+ MOVW $SYS_thr_self, R7
+ SWI $0
// thr_kill(self, SIGPIPE)\n
MOVW 4(R13), R0 // arg 1 id\n
MOVW sig+0(FP), R1 // arg 2 - signal\n
- SWI $433
+ MOVW $SYS_thr_kill, R7
+ SWI $0
RET
TEXT runtime·setitimer(SB), NOSPLIT, $-8
MOVW 0(FP), R0
MOVW 4(FP), R1
MOVW 8(FP), R2
- SWI $83
+ MOVW $SYS_setitimer, R7
+ SWI $0
RET
// func now() (sec int64, nsec int32)\n
TEXT time·now(SB), NOSPLIT, $32
MOVW $0, R0 // CLOCK_REALTIME
MOVW $8(R13), R1
- SWI $232 // clock_gettime
+ MOVW $SYS_clock_gettime, R7
+ SWI $0
MOVW 8(R13), R0 // sec.low
MOVW 12(R13), R1 // sec.high
@@ -123,7 +164,8 @@ TEXT time·now(SB), NOSPLIT, $32
TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVW $0, R0 // CLOCK_REALTIME
MOVW $8(R13), R1
- SWI $232 // clock_gettime
+ MOVW $SYS_clock_gettime, R7
+ SWI $0
MOVW 8(R13), R0 // sec.low
MOVW 12(R13), R4 // sec.high
@@ -144,7 +186,8 @@ TEXT runtime·sigaction(SB),NOSPLIT,$-8
MOVW 0(FP), R0 // arg 1 sig
MOVW 4(FP), R1 // arg 2 act
MOVW 8(FP), R2 // arg 3 oact
- SWI $416
+ MOVW $SYS_sigaction, R7
+ SWI $0
MOVW.CS $0, R8 // crash on syscall failure
MOVW.CS R8, (R8)
RET
@@ -183,7 +226,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$24
MOVW 20(R13), g
RET
-TEXT runtime·mmap(SB),NOSPLIT,$12
+TEXT runtime·mmap(SB),NOSPLIT,$16
MOVW 0(FP), R0 // arg 1 addr
MOVW 4(FP), R1 // arg 2 len
MOVW 8(FP), R2 // arg 3 prot
@@ -193,18 +236,22 @@ TEXT runtime·mmap(SB),NOSPLIT,$12
MOVW 16(FP), R4 // arg 5
MOVW R4, 4(R13)
MOVW 20(FP), R5 // arg 6 lower 32-bit
- MOVW R5, 8(R13)
- MOVW $0, R6 // higher 32-bit for arg 6
- MOVW R6, 12(R13)
- ADD $4, R13 // pass arg 5 and arg 6 on stack
- SWI $477
+ // the word at 8(R13) is skipped due to 64-bit argument alignment.
+ MOVW R5, 12(R13)
+ MOVW $0, R6 // higher 32-bit for arg 6
+ MOVW R6, 16(R13)
+ ADD $4, R13
+ MOVW $SYS_mmap, R7
+ SWI $0
SUB $4, R13
+ // TODO(dfc) error checking ?
RET
TEXT runtime·munmap(SB),NOSPLIT,$0
MOVW 0(FP), R0 // arg 1 addr
MOVW 4(FP), R1 // arg 2 len
- SWI $73
+ MOVW $SYS_munmap, R7
+ SWI $0
MOVW.CS $0, R8 // crash on syscall failure
MOVW.CS R8, (R8)
RET
@@ -213,14 +260,16 @@ TEXT runtime·madvise(SB),NOSPLIT,$0
MOVW 0(FP), R0 // arg 1 addr
MOVW 4(FP), R1 // arg 2 len
MOVW 8(FP), R2 // arg 3 flags
- SWI $75
+ MOVW $SYS_madvise, R7
+ SWI $0
// ignore failure - maybe pages are locked
RET
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
MOVW new+0(FP), R0
MOVW old+4(FP), R1
- SWI $53
+ MOVW $SYS_sigaltstack, R7
+ SWI $0
MOVW.CS $0, R8 // crash on syscall failure
MOVW.CS R8, (R8)
RET
@@ -241,54 +290,56 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
MOVW $4(R13), R0 // arg 1 - rqtp
MOVW $0, R1 // arg 2 - rmtp
- SWI $240 // sys_nanosleep
+ MOVW $SYS_nanosleep, R7
+ SWI $0
RET
TEXT runtime·sysctl(SB),NOSPLIT,$0
MOVW 0(FP), R0 // arg 1 - name
MOVW 4(FP), R1 // arg 2 - namelen
- MOVW 8(FP), R2 // arg 3 - oldp
+ MOVW 8(FP), R2 // arg 3 - old
MOVW 12(FP), R3 // arg 4 - oldlenp
// arg 5 (newp) and arg 6 (newlen) are passed on stack
ADD $20, R13
- SWI $202 // sys___sysctl
+ MOVW $SYS___sysctl, R7
+ SWI $0
SUB.CS $0, R0, R0
SUB $20, R13
RET
TEXT runtime·osyield(SB),NOSPLIT,$-4
- SWI $331 // sys_sched_yield
+ MOVW $SYS_sched_yield, R7
+ SWI $0
RET
TEXT runtime·sigprocmask(SB),NOSPLIT,$0
MOVW $3, R0 // arg 1 - how (SIG_SETMASK)
MOVW 0(FP), R1 // arg 2 - set
MOVW 4(FP), R2 // arg 3 - oset
- SWI $340 // sys_sigprocmask
+ MOVW $SYS_sigprocmask, R7
+ SWI $0
MOVW.CS $0, R8 // crash on syscall failure
MOVW.CS R8, (R8)
RET
// int32 runtime·kqueue(void)\n
TEXT runtime·kqueue(SB),NOSPLIT,$0
- SWI $362 // sys_kqueue
+ MOVW $SYS_kqueue, R7
+ SWI $0
RSB.CS $0, R0
RET
// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout)\n
-TEXT runtime·kevent(SB),NOSPLIT,$8
+TEXT runtime·kevent(SB),NOSPLIT,$0
MOVW 0(FP), R0 // kq
MOVW 4(FP), R1 // changelist
MOVW 8(FP), R2 // nchanges
MOVW 12(FP), R3 // eventlist
- MOVW 16(FP), R4 // nevents
- MOVW R4, 4(R13)
- MOVW 20(FP), R4 // timeout
- MOVW R4, 8(R13)
- ADD $4, R13 // pass arg 5 and 6 on stack
- SWI $363 // sys_kevent
+ ADD $20, R13 // pass arg 5 and 6 on stack
+ MOVW $SYS_kevent, R7
+ SWI $0
RSB.CS $0, R0
- SUB $4, R13
+ SUB $20, R13
RET
// void runtime·closeonexec(int32 fd)\n
@@ -296,7 +347,8 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0
MOVW 0(FP), R0 // fd
MOVW $2, R1 // F_SETFD
MOVW $1, R2 // FD_CLOEXEC
- SWI $92 // sys_fcntl
+ MOVW $SYS_fcntl, R7
+ SWI $0
RET
TEXT runtime·casp(SB),NOSPLIT,$0
src/pkg/syscall/asm_freebsd_arm.s
--- a/src/pkg/syscall/asm_freebsd_arm.s
+++ b/src/pkg/syscall/asm_freebsd_arm.s
@@ -14,10 +14,10 @@
TEXT ·Syscall(SB),NOSPLIT,$0-28
BL runtime·entersyscall(SB)
- MOVW 0(FP), R0 // sigcall num
- MOVW 4(FP), R1 // a1
- MOVW 8(FP), R2 // a2
- MOVW 12(FP), R3 // a3
+ MOVW 0(FP), R7 // sigcall num
+ MOVW 4(FP), R0 // a1
+ MOVW 8(FP), R1 // a2
+ MOVW 12(FP), R2 // a3
SWI $0 // syscall
MOVW $0, R2
BCS error
@@ -36,14 +36,14 @@ error:\
TEXT ·Syscall6(SB),NOSPLIT,$0-40
BL runtime·entersyscall(SB)
- MOVW 0(FP), R0 // sigcall num
- MOVW 4(FP), R1 // a1
- MOVW 8(FP), R2 // a2
- MOVW 12(FP), R3 // a3
- MOVW R13, R4
- MOVW $16(FP), R13 // a4 to a6 are passed on stack
+ MOVW 0(FP), R7 // sigcall num
+ MOVW 4(FP), R0 // a1
+ MOVW 8(FP), R1 // a2
+ MOVW 12(FP), R2 // a3
+ MOVW 16(FP), R3 // a4
+ ADD $24, R13 // a5 to a6 are passed on stack
SWI $0 // syscall
- MOVW R4, R13
+ SUB $24, R13
MOVW $0, R2
BCS error6
MOVW R0, 28(FP) // r1
@@ -61,14 +61,14 @@ error6:\
TEXT ·Syscall9(SB),NOSPLIT,$0-52
BL runtime·entersyscall(SB)
- MOVW 0(FP), R0 // sigcall num
- MOVW 4(FP), R1 // a1
- MOVW 8(FP), R2 // a2
- MOVW 12(FP), R3 // a3
- MOVW R13, R4
- MOVW $16(FP), R13 // a4 to a9 are passed on stack
+ MOVW 0(FP), R7 // sigcall num
+ MOVW 4(FP), R0 // a1
+ MOVW 8(FP), R1 // a2
+ MOVW 12(FP), R2 // a3
+ MOVW 16(FP), R3 // a4
+ ADD $24, R13 // a5 to a9 are passed on stack
SWI $0 // syscall
- MOVW R4, R13
+ SUB $24, R13
MOVW $0, R2
BCS error9
MOVW R0, 40(FP) // r1
@@ -85,10 +85,10 @@ error9:\
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
- MOVW 0(FP), R0 // sigcall num
- MOVW 4(FP), R1 // a1
- MOVW 8(FP), R2 // a2
- MOVW 12(FP), R3 // a3
+ MOVW 0(FP), R7 // sigcall num
+ MOVW 4(FP), R0 // a1
+ MOVW 8(FP), R1 // a2
+ MOVW 12(FP), R2 // a3
SWI $0 // syscall
MOVW $0, R2
BCS errorr
@@ -104,14 +104,14 @@ errorr:\
RET
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
- MOVW 0(FP), R0 // sigcall num
- MOVW 4(FP), R1 // a1
- MOVW 8(FP), R2 // a2
- MOVW 12(FP), R3 // a3
- MOVW R13, R4
- MOVW $16(FP), R13 // a4 to a9 are passed on stack
+ MOVW 0(FP), R7 // sigcall num
+ MOVW 4(FP), R0 // a1
+ MOVW 8(FP), R1 // a2
+ MOVW 12(FP), R2 // a3
+ MOVW 16(FP), R3 // a4
+ ADD $24, R13 // a5 to a6 are passed on stack
SWI $0 // syscall
- MOVW R4, R13
+ SUB $24, R13
MOVW $0, R2
BCS errorr6
MOVW R0, 28(FP) // r1
コアとなるコードの解説
src/pkg/runtime/sys_freebsd_arm.s
このファイルは、Goランタイムが直接呼び出す低レベルなシステムコールラッパーを定義しています。
#define SYS_...
: 各システムコールに対応する番号が定義されています。これはFreeBSDのシステムコールテーブルと一致します。例えば、SYS_exit
はプログラム終了、SYS_read
はファイル読み込み、SYS_mmap
はメモリマップなどです。TEXT runtime·syscall_name(SB),NOSPLIT,$0
: 各システムコールラッパー関数の定義です。NOSPLIT
はスタックフレームを分割しないことを意味し、$0
はローカル変数に0バイトを割り当てることを意味します。MOVW 0(FP), R0
など: 関数引数をレジスタにロードする命令です。0(FP)
はフレームポインタ(FP
)からのオフセット0にある引数を意味し、それをR0
レジスタに移動します。MOVW $SYS_syscall_name, R7
: このコミットの最も重要な変更点の一つです。 以前はSWI $システムコール番号
のように直接システムコール番号をSWI
命令のオペランドとして指定していましたが、EABIではシステムコール番号をR7
レジスタに設定する必要があります。この行は、定義されたシステムコール番号をR7
レジスタにロードします。SWI $0
: もう一つの重要な変更点です。 EABIでは、システムコールを呼び出すためのソフトウェア割り込み命令は常にSWI #0
(またはSVC #0
)です。システムコール番号はR7
レジスタによって指定されます。ADD $X, R13
/SUB $X, R13
: スタックポインタ(R13
)を調整して、スタックに引数を渡したり、スタックフレームをクリーンアップしたりします。特にmmap
のような引数が多いシステムコールでは、レジスタに収まらない引数をスタックに積む必要があります。mmap
の変更では、64ビット引数のアライメントのために、スタック上のワードをスキップする処理が追加されています。
src/pkg/syscall/asm_freebsd_arm.s
このファイルは、Goのsyscall
パッケージが提供する汎用的なシステムコール呼び出し関数を定義しています。これらの関数は、Goのユーザーコードからシステムコールを呼び出す際に使用されます。
TEXT ·Syscall(SB),NOSPLIT,$0-28
など:Syscall
、Syscall6
、Syscall9
、RawSyscall
、RawSyscall6
といった関数は、それぞれ異なる数の引数を持つシステムコールを呼び出すためのラッパーです。BL runtime·entersyscall(SB)
: システムコールに入る前にGoランタイムのentersyscall
関数を呼び出します。これは、Goスケジューラがシステムコール中にゴルーチンをブロックしないようにするための処理です。MOVW 0(FP), R7 // sigcall num
: ここも重要な変更点です。syscall
パッケージの関数に渡された最初の引数(システムコール番号)をR7
レジスタにロードします。これにより、EABIの規約に従ってシステムコール番号がカーネルに渡されます。MOVW 4(FP), R0 // a1
など:syscall
パッケージの関数に渡された残りの引数をR0
、R1
、R2
、R3
レジスタにロードします。これはEABIの引数渡し規約に準拠しています。SWI $0 // syscall
:runtime
パッケージと同様に、EABIに準拠したSWI #0
命令でシステムコールを実行します。BCS error
/BCS error6
/BCS error9
/BCS errorr
/BCS errorr6
: システムコールがエラーを返した場合(ARMでは通常、キャリーフラグがセットされることで示される)、エラー処理ルーチンに分岐します。MOVW R0, 28(FP) // r1
など: システムコールからの戻り値をスタック上の適切な位置に格納します。Goのsyscall
関数は複数の戻り値(戻り値、エラーコードなど)を持つため、それらを正しく配置します。BL runtime·exitsyscall(SB)
: システムコールから戻った後にGoランタイムのexitsyscall
関数を呼び出します。これは、Goスケジューラがゴルーチンを再開できるようにするための処理です。
これらの変更により、Goランタイムとsyscall
パッケージは、FreeBSD/ARM環境でEABIに準拠したシステムコール呼び出しを正確に実行できるようになり、Goプログラムの安定性と互換性が大幅に向上します。
関連リンク
- Go Issue #6451: https://github.com/golang/go/issues/6451
- Go CL 13824044: https://golang.org/cl/13824044
参考にした情報源リンク
- ARM Architecture Reference Manual (ARM ARM)
- ARM EABI documentation (例: https://developer.arm.com/documentation/den0013/d/)
- FreeBSD System Calls Manual Pages
- Go言語のソースコード (特に
src/runtime
とsrc/syscall
ディレクトリ内のARMアセンブリファイル) - Go言語のIssueトラッカーとChange List (CL)
- https://en.wikipedia.org/wiki/ARM_architecture#Application_Binary_Interface_(ABI)
- https://en.wikipedia.org/wiki/Application_Binary_Interface
- https://www.freebsd.org/doc/en/books/developers-handbook/kernel-syscalls.html
- https://go.dev/doc/asm
- https://go.dev/src/runtime/sys_freebsd_arm.s (コミット適用後のファイル)
- https://go.dev/src/syscall/asm_freebsd_arm.s (コミット適用後のファイル)