MOVD 56(R0), R6 // a7
MOVD 64(R0), R7 // a8
MOVD 72(R0), R8 // a9
+ MOVD R8, 0(RSP) // the 9th arg and onwards must be passed on the stack
MOVD 8(R0), R0 // a1
- // If fn is declared as vararg, we have to pass the vararg arguments on the stack.
- // See syscall above. The only function this applies to is openat, for which the 4th
- // arg must be on the stack.
- MOVD R3, (RSP)
-
BL (R12)
MOVD 8(RSP), R2 // pop structure pointer
--- /dev/null
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "internal/testenv"
+ "runtime"
+ "testing"
+)
+
+func TestSyscallArgs(t *testing.T) {
+ if runtime.GOOS != "darwin" {
+ t.Skipf("skipping test: GOARCH=%s", runtime.GOARCH)
+ }
+ testenv.MustHaveCGO(t)
+
+ exe, err := buildTestProg(t, "testsyscall")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ cmd := testenv.Command(t, exe)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("test program failed: %v\n%s", err, out)
+ }
+}
--- /dev/null
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ _ "runtime/testdata/testsyscall/testsyscallc" // unfortunately, we can't put C and assembly in the package
+ _ "unsafe" // for go:linkname
+)
+
+//go:linkname syscall_syscall syscall.syscall
+func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+
+//go:linkname syscall_syscall6 syscall.syscall6
+func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+
+//go:linkname syscall_syscall9 syscall.syscall9
+func syscall_syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr)
+
+var (
+ syscall_check0_trampoline_addr uintptr
+ syscall_check1_trampoline_addr uintptr
+ syscall_check2_trampoline_addr uintptr
+ syscall_check3_trampoline_addr uintptr
+ syscall_check4_trampoline_addr uintptr
+ syscall_check5_trampoline_addr uintptr
+ syscall_check6_trampoline_addr uintptr
+ syscall_check7_trampoline_addr uintptr
+ syscall_check8_trampoline_addr uintptr
+ syscall_check9_trampoline_addr uintptr
+)
+
+func main() {
+ if ret, _, _ := syscall_syscall(syscall_check0_trampoline_addr, 0, 0, 0); ret != 1 {
+ panic("hello0")
+ }
+ if ret, _, _ := syscall_syscall(syscall_check1_trampoline_addr, 1, 0, 0); ret != 1 {
+ panic("hello1")
+ }
+ if ret, _, _ := syscall_syscall(syscall_check2_trampoline_addr, 1, 2, 0); ret != 1 {
+ panic("hello2")
+ }
+ if ret, _, _ := syscall_syscall(syscall_check3_trampoline_addr, 1, 2, 3); ret != 1 {
+ panic("hello3")
+ }
+ if ret, _, _ := syscall_syscall6(syscall_check4_trampoline_addr, 1, 2, 3, 4, 0, 0); ret != 1 {
+ panic("hello4")
+ }
+ if ret, _, _ := syscall_syscall6(syscall_check5_trampoline_addr, 1, 2, 3, 4, 5, 0); ret != 1 {
+ panic("hello5")
+ }
+ if ret, _, _ := syscall_syscall6(syscall_check6_trampoline_addr, 1, 2, 3, 4, 5, 6); ret != 1 {
+ panic("hello6")
+ }
+ if ret, _, _ := syscall_syscall9(syscall_check7_trampoline_addr, 1, 2, 3, 4, 5, 6, 7, 0, 0); ret != 1 {
+ panic("hello7")
+ }
+ if ret, _, _ := syscall_syscall9(syscall_check8_trampoline_addr, 1, 2, 3, 4, 5, 6, 7, 8, 0); ret != 1 {
+ panic("hello8")
+ }
+ if ret, _, _ := syscall_syscall9(syscall_check9_trampoline_addr, 1, 2, 3, 4, 5, 6, 7, 8, 9); ret != 1 {
+ panic("hello9")
+ }
+}
--- /dev/null
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+TEXT syscall_check0_trampoline<>(SB),NOSPLIT,$0-0
+ JMP syscall_check0(SB)
+GLOBL ·syscall_check0_trampoline_addr(SB), RODATA, $8
+DATA ·syscall_check0_trampoline_addr(SB)/8, $syscall_check0_trampoline<>(SB)
+
+TEXT syscall_check1_trampoline<>(SB),NOSPLIT,$0-0
+ JMP syscall_check1(SB)
+GLOBL ·syscall_check1_trampoline_addr(SB), RODATA, $8
+DATA ·syscall_check1_trampoline_addr(SB)/8, $syscall_check1_trampoline<>(SB)
+
+TEXT syscall_check2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP syscall_check2(SB)
+GLOBL ·syscall_check2_trampoline_addr(SB), RODATA, $8
+DATA ·syscall_check2_trampoline_addr(SB)/8, $syscall_check2_trampoline<>(SB)
+
+TEXT syscall_check3_trampoline<>(SB),NOSPLIT,$0-0
+ JMP syscall_check3(SB)
+GLOBL ·syscall_check3_trampoline_addr(SB), RODATA, $8
+DATA ·syscall_check3_trampoline_addr(SB)/8, $syscall_check3_trampoline<>(SB)
+
+TEXT syscall_check4_trampoline<>(SB),NOSPLIT,$0-0
+ JMP syscall_check4(SB)
+GLOBL ·syscall_check4_trampoline_addr(SB), RODATA, $8
+DATA ·syscall_check4_trampoline_addr(SB)/8, $syscall_check4_trampoline<>(SB)
+
+TEXT syscall_check5_trampoline<>(SB),NOSPLIT,$0-0
+ JMP syscall_check5(SB)
+GLOBL ·syscall_check5_trampoline_addr(SB), RODATA, $8
+DATA ·syscall_check5_trampoline_addr(SB)/8, $syscall_check5_trampoline<>(SB)
+
+TEXT syscall_check6_trampoline<>(SB),NOSPLIT,$0-0
+ JMP syscall_check6(SB)
+GLOBL ·syscall_check6_trampoline_addr(SB), RODATA, $8
+DATA ·syscall_check6_trampoline_addr(SB)/8, $syscall_check6_trampoline<>(SB)
+
+TEXT syscall_check7_trampoline<>(SB),NOSPLIT,$0-0
+ JMP syscall_check7(SB)
+GLOBL ·syscall_check7_trampoline_addr(SB), RODATA, $8
+DATA ·syscall_check7_trampoline_addr(SB)/8, $syscall_check7_trampoline<>(SB)
+
+TEXT syscall_check8_trampoline<>(SB),NOSPLIT,$0-0
+ JMP syscall_check8(SB)
+GLOBL ·syscall_check8_trampoline_addr(SB), RODATA, $8
+DATA ·syscall_check8_trampoline_addr(SB)/8, $syscall_check8_trampoline<>(SB)
+
+TEXT syscall_check9_trampoline<>(SB),NOSPLIT,$0-0
+ JMP syscall_check9(SB)
+GLOBL ·syscall_check9_trampoline_addr(SB), RODATA, $8
+DATA ·syscall_check9_trampoline_addr(SB)/8, $syscall_check9_trampoline<>(SB)
--- /dev/null
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testsyscallc
+
+/*
+int syscall_check0(void) {
+ return 1;
+}
+
+int syscall_check1(int a1) {
+ return a1 == 1;
+}
+
+int syscall_check2(int a1, int a2) {
+ return a1 == 1 && a2 == 2;
+}
+
+int syscall_check3(int a1, int a2, int a3) {
+ return a1 == 1 && a2 == 2 && a3 == 3;
+}
+
+int syscall_check4(int a1, int a2, int a3, int a4) {
+ return a1 == 1 && a2 == 2 && a3 == 3 && a4 == 4;
+}
+
+int syscall_check5(int a1, int a2, int a3, int a4, int a5) {
+ return a1 == 1 && a2 == 2 && a3 == 3 && a4 == 4 && a5 == 5;
+}
+
+int syscall_check6(int a1, int a2, int a3, int a4, int a5, int a6) {
+ return a1 == 1 && a2 == 2 && a3 == 3 && a4 == 4 && a5 == 5 && a6 == 6;
+}
+
+int syscall_check7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) {
+ return a1 == 1 && a2 == 2 && a3 == 3 && a4 == 4 && a5 == 5 && a6 == 6 && a7 == 7;
+}
+
+int syscall_check8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) {
+ return a1 == 1 && a2 == 2 && a3 == 3 && a4 == 4 && a5 == 5 && a6 == 6 && a7 == 7 && a8 == 8;
+}
+
+int syscall_check9(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9) {
+ return a1 == 1 && a2 == 2 && a3 == 3 && a4 == 4 && a5 == 5 && a6 == 6 && a7 == 7 && a8 == 8 && a9 == 9;
+}
+*/
+import "C"