diff --git a/runtime.go b/runtime.go index 6083a29a..443f99f1 100644 --- a/runtime.go +++ b/runtime.go @@ -10,6 +10,9 @@ import ( "unsafe" ) +//go:linkname syscall_syscall6X syscall.syscall6X +func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) // from runtime/sys_darwin_64.s + //go:linkname runtime_libcCall runtime.libcCall //go:linkname runtime_entersyscall runtime.entersyscall //go:linkname runtime_exitsyscall runtime.exitsyscall diff --git a/sys_darwin_amd64.s b/sys_darwin_amd64.s index ce556b28..6ef17a9a 100644 --- a/sys_darwin_amd64.s +++ b/sys_darwin_amd64.s @@ -51,7 +51,7 @@ TEXT ·syscall9X(SB), NOSPLIT, $0 MOVQ R11, X6 // a7 MOVQ R12, X7 // a8 - // push the remainding paramters onto the stack + // push the remaining paramters onto the stack MOVQ R11, 0(SP) // push a7 MOVQ R12, 8(SP) // push a8 MOVQ R13, 16(SP) // push a9 diff --git a/sys_darwin_arm64.s b/sys_darwin_arm64.s index b4f797c1..595d6798 100644 --- a/sys_darwin_arm64.s +++ b/sys_darwin_arm64.s @@ -37,6 +37,7 @@ TEXT ·syscall9X(SB), NOSPLIT, $0 MOVD 56(R0), R6 // a7 MOVD 64(R0), R7 // a8 MOVD 72(R0), R8 // a9 + MOVD 8(R0), R0 // a1 // these may be float arguments // so we put them also where C expects floats @@ -46,12 +47,12 @@ TEXT ·syscall9X(SB), NOSPLIT, $0 FMOVD R3, F3 // a4 FMOVD R4, F4 // a5 FMOVD R5, F5 // a6 - FMOVD R6, F6 // a4 - FMOVD R7, F7 // a5 + FMOVD R6, F6 // a7 + FMOVD R7, F7 // a8 MOVD R8, (RSP) // push a9 onto stack - MOVD 8(R0), R0 // a1 - BL (R12) + + BL (R12) MOVD 8(RSP), R2 // pop structure pointer ADD $16, RSP diff --git a/syscall.go b/syscall.go index b0a79ed5..fe0f73d1 100644 --- a/syscall.go +++ b/syscall.go @@ -17,17 +17,23 @@ const maxArgs = 9 // NOTE: SyscallN does not properly call functions that have both integer and float parameters. // See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607 // for an explanation of why that is. +// +// On amd64, if there are more than 8 floats the 9th and so on will be placed incorrectly on the +// stack. func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) { if len(args) > maxArgs { panic("too many arguments to SyscallN") } - if len(args) < maxArgs { - // add padding so there is no out-of-bounds slicing - var tmp = make([]uintptr, maxArgs) - copy(tmp, args) - args = tmp + // add padding so there is no out-of-bounds slicing + var tmp [maxArgs]uintptr + copy(tmp[:], args) + if len(args) <= 6 { + // use the 6 argument version because + // gl.GenFramebuffersEXT would fail with the 9 version + // See https://github.com/hajimehoshi/ebiten/issues/2102#issuecomment-1134679352 + return syscall_syscall6X(fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5]) } - return syscall_syscall9X(fn, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]) + return syscall_syscall9X(fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8]) } func callc(fn uintptr, args unsafe.Pointer) {