purego: use syscall.Syscall6X for functions with 6 or less arguments (#3)
- commit
- 0f6873f422228dc80b97e34d325bd8bc6df6377b
- author
- TotallyGamerJet · · 2022-05-25 02:51 UTC
- committer
- GitHub · · 2022-05-25 02:51 UTC
- parent
- 36e492b
- signature
- GPG Unverified
4AEE18F83AFDEB23The key is unknown
4 files · +21 -11
M runtime.go +3 -0
| @@ -10,6 +10,9 @@ import ( | |||
| 10 | 10 | "unsafe" | |
| 11 | 11 | ) | |
| 12 | 12 | ||
| 13 | + | //go:linkname syscall_syscall6X syscall.syscall6X | |
| 14 | + | func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) // from runtime/sys_darwin_64.s | |
| 15 | + | ||
| 13 | 16 | //go:linkname runtime_libcCall runtime.libcCall | |
| 14 | 17 | //go:linkname runtime_entersyscall runtime.entersyscall | |
| 15 | 18 | //go:linkname runtime_exitsyscall runtime.exitsyscall | |
| @@ -10,6 +10,9 @@ import ( | |||||
| 10 | "unsafe" | 10 | "unsafe" | ||
| 11 | ) | 11 | ) | ||
| 12 | 12 | ||||
| 13 | + | //go:linkname syscall_syscall6X syscall.syscall6X | |||
| 14 | + | func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) // from runtime/sys_darwin_64.s | |||
| 15 | + | ||||
| 13 | //go:linkname runtime_libcCall runtime.libcCall | 16 | //go:linkname runtime_libcCall runtime.libcCall | ||
| 14 | //go:linkname runtime_entersyscall runtime.entersyscall | 17 | //go:linkname runtime_entersyscall runtime.entersyscall | ||
| 15 | //go:linkname runtime_exitsyscall runtime.exitsyscall | 18 | //go:linkname runtime_exitsyscall runtime.exitsyscall | ||
M sys_darwin_amd64.s +1 -1
| @@ -51,7 +51,7 @@ TEXT ·syscall9X(SB), NOSPLIT, $0 | |||
| 51 | 51 | MOVQ R11, X6 // a7 | |
| 52 | 52 | MOVQ R12, X7 // a8 | |
| 53 | 53 | ||
| 54 | - | // push the remainding paramters onto the stack | |
| 54 | + | // push the remaining paramters onto the stack | |
| 55 | 55 | MOVQ R11, 0(SP) // push a7 | |
| 56 | 56 | MOVQ R12, 8(SP) // push a8 | |
| 57 | 57 | MOVQ R13, 16(SP) // push a9 | |
| @@ -51,7 +51,7 @@ TEXT ·syscall9X(SB), NOSPLIT, $0 | |||||
| 51 | MOVQ R11, X6 // a7 | 51 | MOVQ R11, X6 // a7 | ||
| 52 | MOVQ R12, X7 // a8 | 52 | MOVQ R12, X7 // a8 | ||
| 53 | 53 | ||||
| 54 | - | // push the remainding paramters onto the stack | 54 | + | // push the remaining paramters onto the stack |
| 55 | MOVQ R11, 0(SP) // push a7 | 55 | MOVQ R11, 0(SP) // push a7 | ||
| 56 | MOVQ R12, 8(SP) // push a8 | 56 | MOVQ R12, 8(SP) // push a8 | ||
| 57 | MOVQ R13, 16(SP) // push a9 | 57 | MOVQ R13, 16(SP) // push a9 | ||
M sys_darwin_arm64.s +5 -4
| @@ -37,6 +37,7 @@ TEXT ·syscall9X(SB), NOSPLIT, $0 | |||
| 37 | 37 | MOVD 56(R0), R6 // a7 | |
| 38 | 38 | MOVD 64(R0), R7 // a8 | |
| 39 | 39 | MOVD 72(R0), R8 // a9 | |
| 40 | + | MOVD 8(R0), R0 // a1 | |
| 40 | 41 | ||
| 41 | 42 | // these may be float arguments | |
| 42 | 43 | // so we put them also where C expects floats | |
| @@ -46,12 +47,12 @@ TEXT ·syscall9X(SB), NOSPLIT, $0 | |||
| 46 | 47 | FMOVD R3, F3 // a4 | |
| 47 | 48 | FMOVD R4, F4 // a5 | |
| 48 | 49 | FMOVD R5, F5 // a6 | |
| 49 | - | FMOVD R6, F6 // a4 | |
| 50 | - | FMOVD R7, F7 // a5 | |
| 50 | + | FMOVD R6, F6 // a7 | |
| 51 | + | FMOVD R7, F7 // a8 | |
| 51 | 52 | ||
| 52 | 53 | MOVD R8, (RSP) // push a9 onto stack | |
| 53 | - | MOVD 8(R0), R0 // a1 | |
| 54 | - | BL (R12) | |
| 54 | + | ||
| 55 | + | BL (R12) | |
| 55 | 56 | ||
| 56 | 57 | MOVD 8(RSP), R2 // pop structure pointer | |
| 57 | 58 | ADD $16, RSP | |
| @@ -37,6 +37,7 @@ TEXT ·syscall9X(SB), NOSPLIT, $0 | |||||
| 37 | MOVD 56(R0), R6 // a7 | 37 | MOVD 56(R0), R6 // a7 | ||
| 38 | MOVD 64(R0), R7 // a8 | 38 | MOVD 64(R0), R7 // a8 | ||
| 39 | MOVD 72(R0), R8 // a9 | 39 | MOVD 72(R0), R8 // a9 | ||
| 40 | + | MOVD 8(R0), R0 // a1 | |||
| 40 | 41 | ||||
| 41 | // these may be float arguments | 42 | // these may be float arguments | ||
| 42 | // so we put them also where C expects floats | 43 | // so we put them also where C expects floats | ||
| @@ -46,12 +47,12 @@ TEXT ·syscall9X(SB), NOSPLIT, $0 | |||||
| 46 | FMOVD R3, F3 // a4 | 47 | FMOVD R3, F3 // a4 | ||
| 47 | FMOVD R4, F4 // a5 | 48 | FMOVD R4, F4 // a5 | ||
| 48 | FMOVD R5, F5 // a6 | 49 | FMOVD R5, F5 // a6 | ||
| 49 | - | FMOVD R6, F6 // a4 | 50 | + | FMOVD R6, F6 // a7 |
| 50 | - | FMOVD R7, F7 // a5 | 51 | + | FMOVD R7, F7 // a8 |
| 51 | 52 | ||||
| 52 | MOVD R8, (RSP) // push a9 onto stack | 53 | MOVD R8, (RSP) // push a9 onto stack | ||
| 53 | - | MOVD 8(R0), R0 // a1 | 54 | + | |
| 54 | - | BL (R12) | 55 | + | BL (R12) |
| 55 | 56 | ||||
| 56 | MOVD 8(RSP), R2 // pop structure pointer | 57 | MOVD 8(RSP), R2 // pop structure pointer | ||
| 57 | ADD $16, RSP | 58 | ADD $16, RSP | ||
M syscall.go +12 -6
| @@ -17,17 +17,23 @@ const maxArgs = 9 | |||
| 17 | 17 | // NOTE: SyscallN does not properly call functions that have both integer and float parameters. | |
| 18 | 18 | // See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607 | |
| 19 | 19 | // for an explanation of why that is. | |
| 20 | + | // | |
| 21 | + | // On amd64, if there are more than 8 floats the 9th and so on will be placed incorrectly on the | |
| 22 | + | // stack. | |
| 20 | 23 | func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) { | |
| 21 | 24 | if len(args) > maxArgs { | |
| 22 | 25 | panic("too many arguments to SyscallN") | |
| 23 | 26 | } | |
| 24 | - | if len(args) < maxArgs { | |
| 25 | - | // add padding so there is no out-of-bounds slicing | |
| 26 | - | var tmp = make([]uintptr, maxArgs) | |
| 27 | - | copy(tmp, args) | |
| 28 | - | args = tmp | |
| 27 | + | // add padding so there is no out-of-bounds slicing | |
| 28 | + | var tmp [maxArgs]uintptr | |
| 29 | + | copy(tmp[:], args) | |
| 30 | + | if len(args) <= 6 { | |
| 31 | + | // use the 6 argument version because | |
| 32 | + | // gl.GenFramebuffersEXT would fail with the 9 version | |
| 33 | + | // See https://github.com/hajimehoshi/ebiten/issues/2102#issuecomment-1134679352 | |
| 34 | + | return syscall_syscall6X(fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5]) | |
| 29 | 35 | } | |
| 30 | - | return syscall_syscall9X(fn, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]) | |
| 36 | + | return syscall_syscall9X(fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8]) | |
| 31 | 37 | } | |
| 32 | 38 | ||
| 33 | 39 | func callc(fn uintptr, args unsafe.Pointer) { | |
| @@ -17,17 +17,23 @@ const maxArgs = 9 | |||||
| 17 | // NOTE: SyscallN does not properly call functions that have both integer and float parameters. | 17 | // NOTE: SyscallN does not properly call functions that have both integer and float parameters. | ||
| 18 | // See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607 | 18 | // See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607 | ||
| 19 | // for an explanation of why that is. | 19 | // for an explanation of why that is. | ||
| 20 | + | // | |||
| 21 | + | // On amd64, if there are more than 8 floats the 9th and so on will be placed incorrectly on the | |||
| 22 | + | // stack. | |||
| 20 | func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) { | 23 | func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) { | ||
| 21 | if len(args) > maxArgs { | 24 | if len(args) > maxArgs { | ||
| 22 | panic("too many arguments to SyscallN") | 25 | panic("too many arguments to SyscallN") | ||
| 23 | } | 26 | } | ||
| 24 | - | if len(args) < maxArgs { | 27 | + | // add padding so there is no out-of-bounds slicing |
| 25 | - | // add padding so there is no out-of-bounds slicing | 28 | + | var tmp [maxArgs]uintptr |
| 26 | - | var tmp = make([]uintptr, maxArgs) | 29 | + | copy(tmp[:], args) |
| 27 | - | copy(tmp, args) | 30 | + | if len(args) <= 6 { |
| 28 | - | args = tmp | 31 | + | // use the 6 argument version because |
| 32 | + | // gl.GenFramebuffersEXT would fail with the 9 version | |||
| 33 | + | // See https://github.com/hajimehoshi/ebiten/issues/2102#issuecomment-1134679352 | |||
| 34 | + | return syscall_syscall6X(fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5]) | |||
| 29 | } | 35 | } | ||
| 30 | - | return syscall_syscall9X(fn, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]) | 36 | + | return syscall_syscall9X(fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8]) |
| 31 | } | 37 | } | ||
| 32 | 38 | ||||
| 33 | func callc(fn uintptr, args unsafe.Pointer) { | 39 | func callc(fn uintptr, args unsafe.Pointer) { | ||