detached 6ed67cd

fix callback calling convention (#26)

runtime.cgocallback takes a function pointer to the ABIInternal entry. The only way to get the ABIInternal entry is using the ABI selector <ABIInternal>. However, this is only available when compiling the runtime.  This commit circumvents this limitation by using build constraints to determine if the Go version uses stack or register calling convention. Then in callbackWrapPicker the proper argument is sent to the real callbackWrap function.

Closes #25
commit
6ed67cd5f570b9c0d5710dfced2b1e77ad92ca1b
author
TotallyGamerJet · · 2022-08-29 17:19 UTC
committer
GitHub · · 2022-08-29 17:19 UTC
parent
58aa9be
signature
GPG Unverified4AEE18F83AFDEB23 The key is unknown
5 files · +50 -8
A registercc_darwin.go +12 -0
@@ -0,0 +1,12 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3+
4+//go:build (arm64 && go1.18) || (amd64 && go1.17)
5+// +build arm64,go1.18 amd64,go1.17
6+
7+package purego
8+
9+// stackCallingConvention represents whether the stacks or the
10+// registers are used to pass parameters to functions. This is used to circumvent
11+// the need for ABIInternal tag which is only allowed in the runtime.
12+const stackCallingConvention = false
@@ -0,0 +1,12 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3+
4+//go:build (arm64 && go1.18) || (amd64 && go1.17)
5+// +build arm64,go1.18 amd64,go1.17
6+
7+package purego
8+
9+// stackCallingConvention represents whether the stacks or the
10+// registers are used to pass parameters to functions. This is used to circumvent
11+// the need for ABIInternal tag which is only allowed in the runtime.
12+const stackCallingConvention = false
A stackcc_darwin.go +12 -0
@@ -0,0 +1,12 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3+
4+//go:build (arm64 && !go1.18) || (amd64 && !go1.17)
5+// +build arm64,!go1.18 amd64,!go1.17
6+
7+package purego
8+
9+// stackCallingConvention represents whether the stacks or the
10+// registers are used to pass parameters to functions. This is used to circumvent
11+// the need for ABIInternal tag which is only allowed in the runtime.
12+const stackCallingConvention = true
@@ -0,0 +1,12 @@
1+// SPDX-License-Identifier: Apache-2.0
2+// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3+
4+//go:build (arm64 && !go1.18) || (amd64 && !go1.17)
5+// +build arm64,!go1.18 amd64,!go1.17
6+
7+package purego
8+
9+// stackCallingConvention represents whether the stacks or the
10+// registers are used to pass parameters to functions. This is used to circumvent
11+// the need for ABIInternal tag which is only allowed in the runtime.
12+const stackCallingConvention = true
M sys_darwin_amd64.s +6 -4
@@ -74,11 +74,13 @@ TEXT syscall9X(SB), NOSPLIT, $0
7474
7575 // runtime·cgocallback expects a call to the ABIInternal function
7676 // However, the tag <ABIInternal> is only available in the runtime :(
77-// This is a small wrapper function that moves the parameter from AX to the stack
78-// where the Go function can find it. It then jumps to callbackWrap
77+// This is a small wrapper function that copies both whatever is in the register
78+// and is on the stack and places both on the stack. It then calls callbackWrapPicker
79+// which will choose which parameter should be used depending on the version of Go.
80+// It then calls the real version of callbackWrap
7981 TEXT callbackWrapInternal<>(SB), NOSPLIT, $0-0
80- MOVQ AX, arg+8(SP)
81- JMP ·callbackWrap(SB)
82+ MOVQ AX, arg+16(SP)
83+ JMP ·callbackWrapPicker(SB)
8284 RET
8385
8486 TEXT callbackasm1(SB), NOSPLIT, $0
@@ -74,11 +74,13 @@ TEXT syscall9X(SB), NOSPLIT, $0
74 74
75 // runtime·cgocallback expects a call to the ABIInternal function75 // runtime·cgocallback expects a call to the ABIInternal function
76 // However, the tag <ABIInternal> is only available in the runtime :(76 // However, the tag <ABIInternal> is only available in the runtime :(
77-// This is a small wrapper function that moves the parameter from AX to the stack77+// This is a small wrapper function that copies both whatever is in the register
78-// where the Go function can find it. It then jumps to callbackWrap78+// and is on the stack and places both on the stack. It then calls callbackWrapPicker
79+// which will choose which parameter should be used depending on the version of Go.
80+// It then calls the real version of callbackWrap
79 TEXT callbackWrapInternal<>(SB), NOSPLIT, $0-081 TEXT callbackWrapInternal<>(SB), NOSPLIT, $0-0
80- MOVQ AX, arg+8(SP)82+ MOVQ AX, arg+16(SP)
81- JMP ·callbackWrap(SB)83+ JMP ·callbackWrapPicker(SB)
82 RET84 RET
83 85
84 TEXT callbackasm1(SB), NOSPLIT, $086 TEXT callbackasm1(SB), NOSPLIT, $0
M sys_darwin_arm64.s +6 -4
@@ -65,11 +65,13 @@ TEXT syscall9X(SB), NOSPLIT, $0
6565
6666 // runtime·cgocallback expects a call to the ABIInternal function
6767 // However, the tag <ABIInternal> is only available in the runtime :(
68-// This is a small wrapper function that moves the parameter from R0 to the stack
69-// where the Go function can find it. It then branches without link.
68+// This is a small wrapper function that copies both whatever is in the register
69+// and is on the stack and places both on the stack. It then calls callbackWrapPicker
70+// which will choose which parameter should be used depending on the version of Go.
71+// It then calls the real version of callbackWrap
7072 TEXT callbackWrapInternal<>(SB), NOSPLIT, $0-0
71- MOVD R0, 8(RSP)
72- B ·callbackWrap(SB)
73+ MOVD R0, 16(RSP)
74+ B ·callbackWrapPicker(SB)
7375 RET
7476
7577 TEXT callbackasm1(SB), NOSPLIT, $208-0
@@ -65,11 +65,13 @@ TEXT syscall9X(SB), NOSPLIT, $0
65 65
66 // runtime·cgocallback expects a call to the ABIInternal function66 // runtime·cgocallback expects a call to the ABIInternal function
67 // However, the tag <ABIInternal> is only available in the runtime :(67 // However, the tag <ABIInternal> is only available in the runtime :(
68-// This is a small wrapper function that moves the parameter from R0 to the stack68+// This is a small wrapper function that copies both whatever is in the register
69-// where the Go function can find it. It then branches without link.69+// and is on the stack and places both on the stack. It then calls callbackWrapPicker
70+// which will choose which parameter should be used depending on the version of Go.
71+// It then calls the real version of callbackWrap
70 TEXT callbackWrapInternal<>(SB), NOSPLIT, $0-072 TEXT callbackWrapInternal<>(SB), NOSPLIT, $0-0
71- MOVD R0, 8(RSP)73+ MOVD R0, 16(RSP)
72- B ·callbackWrap(SB)74+ B ·callbackWrapPicker(SB)
73 RET75 RET
74 76
75 TEXT callbackasm1(SB), NOSPLIT, $208-077 TEXT callbackasm1(SB), NOSPLIT, $208-0
M syscall_darwin.go +14 -0
@@ -95,6 +95,20 @@ const callbackMaxFrame = 64 * ptrSize
9595 // callbackasmABI0 is implemented in zcallback_GOOS_GOARCH.s
9696 var callbackasmABI0 uintptr
9797
98+// callbackWrapPicker gets whatever is on the stack and in the first register.
99+// Depending on which version of Go that uses stack or register-based
100+// calling it passes the respective argument to the real calbackWrap function.
101+// The other argument is therefore invalid and points to undefined memory so don't use it.
102+// This function is necessary since we can't use the ABIInternal selector which is only
103+// valid in the runtime.
104+func callbackWrapPicker(stack, register *callbackArgs) {
105+ if stackCallingConvention {
106+ callbackWrap(stack)
107+ } else {
108+ callbackWrap(register)
109+ }
110+}
111+
98112 // callbackWrap is called by assembly code which determines which Go function to call.
99113 // This function takes the arguments and passes them to the Go function and returns the result.
100114 func callbackWrap(a *callbackArgs) {
@@ -95,6 +95,20 @@ const callbackMaxFrame = 64 * ptrSize
95 // callbackasmABI0 is implemented in zcallback_GOOS_GOARCH.s95 // callbackasmABI0 is implemented in zcallback_GOOS_GOARCH.s
96 var callbackasmABI0 uintptr96 var callbackasmABI0 uintptr
97 97
98+// callbackWrapPicker gets whatever is on the stack and in the first register.
99+// Depending on which version of Go that uses stack or register-based
100+// calling it passes the respective argument to the real calbackWrap function.
101+// The other argument is therefore invalid and points to undefined memory so don't use it.
102+// This function is necessary since we can't use the ABIInternal selector which is only
103+// valid in the runtime.
104+func callbackWrapPicker(stack, register *callbackArgs) {
105+ if stackCallingConvention {
106+ callbackWrap(stack)
107+ } else {
108+ callbackWrap(register)
109+ }
110+}
111+
98 // callbackWrap is called by assembly code which determines which Go function to call.112 // callbackWrap is called by assembly code which determines which Go function to call.
99 // This function takes the arguments and passes them to the Go function and returns the result.113 // This function takes the arguments and passes them to the Go function and returns the result.
100 func callbackWrap(a *callbackArgs) {114 func callbackWrap(a *callbackArgs) {

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