diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s index 788fdf87b77..a3901bdb3bf 100644 --- a/src/runtime/sys_darwin_arm64.s +++ b/src/runtime/sys_darwin_arm64.s @@ -724,13 +724,9 @@ TEXT runtime·syscall9(SB),NOSPLIT,$0 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 diff --git a/src/runtime/syscall_test.go b/src/runtime/syscall_test.go new file mode 100644 index 00000000000..18f3e8e3151 --- /dev/null +++ b/src/runtime/syscall_test.go @@ -0,0 +1,28 @@ +// 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) + } +} diff --git a/src/runtime/testdata/testsyscall/testsyscall.go b/src/runtime/testdata/testsyscall/testsyscall.go new file mode 100644 index 00000000000..23cca16494d --- /dev/null +++ b/src/runtime/testdata/testsyscall/testsyscall.go @@ -0,0 +1,65 @@ +// 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") + } +} diff --git a/src/runtime/testdata/testsyscall/testsyscall.s b/src/runtime/testdata/testsyscall/testsyscall.s new file mode 100644 index 00000000000..c8d556dfd9a --- /dev/null +++ b/src/runtime/testdata/testsyscall/testsyscall.s @@ -0,0 +1,55 @@ +// 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) diff --git a/src/runtime/testdata/testsyscall/testsyscallc/testsyscallc.go b/src/runtime/testdata/testsyscall/testsyscallc/testsyscallc.go new file mode 100644 index 00000000000..0b2a220b590 --- /dev/null +++ b/src/runtime/testdata/testsyscall/testsyscallc/testsyscallc.go @@ -0,0 +1,48 @@ +// 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"