mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: fix syscall9 on darwin/arm64
The aarch64 ABI says that only the first 8 arguments should be passed as registers, subsequent arguments should be put on the stack. Syscall9 is not putting the 9th argument on the stack, and it should. The standard library hasn't hit this issue because it uses Syscall9 for functions that only require 7 or 8 parameters. Change-Id: I1fafca5b16f977ea856e3f08b4ff3d0a2a7a4dfe Reviewed-on: https://go-review.googlesource.com/c/go/+/702297 Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
60c1ee9183
commit
7acb0d0446
5 changed files with 197 additions and 5 deletions
|
|
@ -724,13 +724,9 @@ TEXT runtime·syscall9(SB),NOSPLIT,$0
|
||||||
MOVD 56(R0), R6 // a7
|
MOVD 56(R0), R6 // a7
|
||||||
MOVD 64(R0), R7 // a8
|
MOVD 64(R0), R7 // a8
|
||||||
MOVD 72(R0), R8 // a9
|
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
|
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)
|
BL (R12)
|
||||||
|
|
||||||
MOVD 8(RSP), R2 // pop structure pointer
|
MOVD 8(RSP), R2 // pop structure pointer
|
||||||
|
|
|
||||||
28
src/runtime/syscall_test.go
Normal file
28
src/runtime/syscall_test.go
Normal file
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/runtime/testdata/testsyscall/testsyscall.go
vendored
Normal file
65
src/runtime/testdata/testsyscall/testsyscall.go
vendored
Normal file
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/runtime/testdata/testsyscall/testsyscall.s
vendored
Normal file
55
src/runtime/testdata/testsyscall/testsyscall.s
vendored
Normal file
|
|
@ -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)
|
||||||
48
src/runtime/testdata/testsyscall/testsyscallc/testsyscallc.go
vendored
Normal file
48
src/runtime/testdata/testsyscall/testsyscallc/testsyscallc.go
vendored
Normal file
|
|
@ -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"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue