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

[インデックス 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が存在します。

  1. OABI (Old Application Binary Interface): 以前のARM Linuxディストリビューションなどで使用されていました。システムコール呼び出し規約がEABIとは異なります。
  2. 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.ssrc/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命令のオペランドとして指定していたのとは異なります。

変更点の内訳

  1. src/pkg/runtime/sys_freebsd_arm.s:

    • システムコール番号の定義: 各システムコールに対応する番号を#defineディレクティブで定義しています。例えば、SYS_exitSYS_readSYS_writeなどです。これらの定義は、FreeBSDのシステムコール番号と一致します。
    • SWI命令の変更: 以前はSWI $システムコール番号のように直接システムコール番号をオペランドとして指定していましたが、EABIに準拠するため、MOVW $SYS_syscall_name, R7R7レジスタにシステムコール番号を設定し、その後SWI $0を実行するように変更されています。
    • 引数の渡し方: mmapなどの複数の引数を取るシステムコールにおいて、引数がレジスタとスタックに正しく配置されるように調整されています。特に、64ビット引数のアライメントに関する考慮が追加されています。
  2. src/pkg/syscall/asm_freebsd_arm.s:

    • SyscallSyscall6Syscall9RawSyscallRawSyscall6関数の変更: これらの関数は、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 など: SyscallSyscall6Syscall9RawSyscallRawSyscall6といった関数は、それぞれ異なる数の引数を持つシステムコールを呼び出すためのラッパーです。
  • BL runtime·entersyscall(SB): システムコールに入る前にGoランタイムのentersyscall関数を呼び出します。これは、Goスケジューラがシステムコール中にゴルーチンをブロックしないようにするための処理です。
  • MOVW 0(FP), R7 // sigcall num: ここも重要な変更点です。 syscallパッケージの関数に渡された最初の引数(システムコール番号)をR7レジスタにロードします。これにより、EABIの規約に従ってシステムコール番号がカーネルに渡されます。
  • MOVW 4(FP), R0 // a1 など: syscallパッケージの関数に渡された残りの引数をR0R1R2R3レジスタにロードします。これは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プログラムの安定性と互換性が大幅に向上します。

関連リンク

参考にした情報源リンク