detached bda3acf

purego: add //go:uintptrescapes to SyscallN (#7)

this forces the uintptr arguments to escape in SyscallN. When optimizations were enabled Go assumed that the pointer arguments in SyscallN were no longer needed. This is why functions like gl.GenFramebuffersEXT would fail. Although this change forces all of the arguments to be placed on the heap it ensures that no optimizations will remove our precious arguments. This also allows us to only have one implementation inside SyscallN (i.e. syscall_syscall9X). A potential replacement would be //go:cgo_unsafe_args but that can only be used in CGO generated files. There is also //go:uintptrkeepalive although that was not enough to stop the function from failing. That is why I went with //go:uintptrescapes

I tested this change on darwin (arm64 & amd64) as well as with -gcflags=all=-N and without. All tests pass on these platforms.

I have not tested this on windows. If you could that would be much appreciated.
commit
bda3acfed6e93f77ef1418d21a2bc2012a58fbfd
author
TotallyGamerJet · · 2022-06-19 03:41 UTC
committer
GitHub · · 2022-06-19 03:41 UTC
parent
cce0ae8
signature
GPG Unverified4AEE18F83AFDEB23 The key is unknown
4 files · +2 -40
M runtime.go +0 -3
@@ -10,9 +10,6 @@ import (
1010 "unsafe"
1111 )
1212
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-
1613 //go:linkname runtime_libcCall runtime.libcCall
1714 //go:linkname runtime_entersyscall runtime.entersyscall
1815 //go:linkname runtime_exitsyscall runtime.exitsyscall
@@ -10,9 +10,6 @@ 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-
16 //go:linkname runtime_libcCall runtime.libcCall13 //go:linkname runtime_libcCall runtime.libcCall
17 //go:linkname runtime_entersyscall runtime.entersyscall14 //go:linkname runtime_entersyscall runtime.entersyscall
18 //go:linkname runtime_exitsyscall runtime.exitsyscall15 //go:linkname runtime_exitsyscall runtime.exitsyscall
M syscall.go +2 -15
@@ -8,20 +8,6 @@ package purego
88
99 const maxArgs = 9
1010
11-// f matches argument numbers to a Syscall implementation that can take that many
12-var f = map[int]func(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr){
13- 0: syscall_syscallX3,
14- 1: syscall_syscallX3,
15- 2: syscall_syscallX3,
16- 3: syscall_syscallX3,
17- 4: syscall_syscallX6,
18- 5: syscall_syscallX6,
19- 6: syscall_syscallX6,
20- 7: syscall_syscall9X,
21- 8: syscall_syscall9X,
22- 9: syscall_syscall9X,
23-}
24-
2511 // SyscallN takes fn, a C function pointer and a list of arguments as uintptr.
2612 // There is an internal maximum number of arguments that SyscallN can take. It panics
2713 // when the maximum is exceeded. It returns the result and the libc error code if there is one.
@@ -33,6 +19,7 @@ var f = map[int]func(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, er
3319 // On amd64, if there are more than 8 floats the 9th and so on will be placed incorrectly on the
3420 // stack.
3521 //go:nosplit
22+//go:uintptrescapes
3623 func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
3724 if len(args) > maxArgs {
3825 panic("too many arguments to SyscallN")
@@ -40,5 +27,5 @@ func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
4027 // add padding so there is no out-of-bounds slicing
4128 var tmp [maxArgs]uintptr
4229 copy(tmp[:], args)
43- return f[len(args)](fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8])
30+ return syscall_syscall9X(fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8])
4431 }
@@ -8,20 +8,6 @@ package purego
8 8
9 const maxArgs = 99 const maxArgs = 9
10 10
11-// f matches argument numbers to a Syscall implementation that can take that many
12-var f = map[int]func(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr){
13- 0: syscall_syscallX3,
14- 1: syscall_syscallX3,
15- 2: syscall_syscallX3,
16- 3: syscall_syscallX3,
17- 4: syscall_syscallX6,
18- 5: syscall_syscallX6,
19- 6: syscall_syscallX6,
20- 7: syscall_syscall9X,
21- 8: syscall_syscall9X,
22- 9: syscall_syscall9X,
23-}
24-
25 // SyscallN takes fn, a C function pointer and a list of arguments as uintptr.11 // SyscallN takes fn, a C function pointer and a list of arguments as uintptr.
26 // There is an internal maximum number of arguments that SyscallN can take. It panics12 // There is an internal maximum number of arguments that SyscallN can take. It panics
27 // when the maximum is exceeded. It returns the result and the libc error code if there is one.13 // when the maximum is exceeded. It returns the result and the libc error code if there is one.
@@ -33,6 +19,7 @@ var f = map[int]func(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, er
33 // On amd64, if there are more than 8 floats the 9th and so on will be placed incorrectly on the19 // On amd64, if there are more than 8 floats the 9th and so on will be placed incorrectly on the
34 // stack.20 // stack.
35 //go:nosplit21 //go:nosplit
22+//go:uintptrescapes
36 func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {23 func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
37 if len(args) > maxArgs {24 if len(args) > maxArgs {
38 panic("too many arguments to SyscallN")25 panic("too many arguments to SyscallN")
@@ -40,5 +27,5 @@ func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
40 // add padding so there is no out-of-bounds slicing27 // add padding so there is no out-of-bounds slicing
41 var tmp [maxArgs]uintptr28 var tmp [maxArgs]uintptr
42 copy(tmp[:], args)29 copy(tmp[:], args)
43- return f[len(args)](fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8])30+ return syscall_syscall9X(fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8])
44 }31 }
M syscall_darwin.go +0 -10
@@ -8,16 +8,6 @@ func callc(fn uintptr, args unsafe.Pointer) {
88 runtime_exitsyscall()
99 }
1010
11-//go:nosplit
12-func syscall_syscallX3(fn, a1, a2, a3, _, _, _, _, _, _ uintptr) (r1, r2, err uintptr) {
13- return syscall_syscall6X(fn, a1, a2, a3, 0, 0, 0)
14-}
15-
16-//go:nosplit
17-func syscall_syscallX6(fn, a1, a2, a3, a4, a5, a6, _, _, _ uintptr) (r1, r2, err uintptr) {
18- return syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6)
19-}
20-
2111 var syscall9XABI0 uintptr
2212
2313 func syscall9X() // implemented in assembly
@@ -8,16 +8,6 @@ func callc(fn uintptr, args unsafe.Pointer) {
8 runtime_exitsyscall()8 runtime_exitsyscall()
9 }9 }
10 10
11-//go:nosplit
12-func syscall_syscallX3(fn, a1, a2, a3, _, _, _, _, _, _ uintptr) (r1, r2, err uintptr) {
13- return syscall_syscall6X(fn, a1, a2, a3, 0, 0, 0)
14-}
15-
16-//go:nosplit
17-func syscall_syscallX6(fn, a1, a2, a3, a4, a5, a6, _, _, _ uintptr) (r1, r2, err uintptr) {
18- return syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6)
19-}
20-
21 var syscall9XABI0 uintptr11 var syscall9XABI0 uintptr
22 12
23 func syscall9X() // implemented in assembly13 func syscall9X() // implemented in assembly
M syscall_windows.go +0 -12
@@ -4,18 +4,6 @@ import (
44 "syscall"
55 )
66
7-//go:nosplit
8-func syscall_syscallX3(fn, a1, a2, a3, _, _, _, _, _, _ uintptr) (r1, r2, err uintptr) {
9- r1, r2, errno := syscall.Syscall(fn, 3, a1, a2, a3)
10- return r1, r2, uintptr(errno)
11-}
12-
13-//go:nosplit
14-func syscall_syscallX6(fn, a1, a2, a3, a4, a5, a6, _, _, _ uintptr) (r1, r2, err uintptr) {
15- r1, r2, errno := syscall.Syscall6(fn, 6, a1, a2, a3, a4, a5, a6)
16- return r1, r2, uintptr(errno)
17-}
18-
197 //go:nosplit
208 func syscall_syscall9X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
219 r1, r2, errno := syscall.Syscall9(fn, 9, a1, a2, a3, a4, a5, a6, a7, a8, a9)
@@ -4,18 +4,6 @@ import (
4 "syscall"4 "syscall"
5 )5 )
6 6
7-//go:nosplit
8-func syscall_syscallX3(fn, a1, a2, a3, _, _, _, _, _, _ uintptr) (r1, r2, err uintptr) {
9- r1, r2, errno := syscall.Syscall(fn, 3, a1, a2, a3)
10- return r1, r2, uintptr(errno)
11-}
12-
13-//go:nosplit
14-func syscall_syscallX6(fn, a1, a2, a3, a4, a5, a6, _, _, _ uintptr) (r1, r2, err uintptr) {
15- r1, r2, errno := syscall.Syscall6(fn, 6, a1, a2, a3, a4, a5, a6)
16- return r1, r2, uintptr(errno)
17-}
18-
19 //go:nosplit7 //go:nosplit
20 func syscall_syscall9X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {8 func syscall_syscall9X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
21 r1, r2, errno := syscall.Syscall9(fn, 9, a1, a2, a3, a4, a5, a6, a7, a8, a9)9 r1, r2, errno := syscall.Syscall9(fn, 9, a1, a2, a3, a4, a5, a6, a7, a8, a9)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close