purego: get ABIInternal wrapper using closure (#75)
The function runtime.cgocallback takes an ABIInternal function pointer. However, the assembly tag <ABIInternal> is only allowed in the runtime. This PR gets the ABIInternal function pointer by using the closure technique from #73. It also removes the hacky trampoline.
- commit
- 2055de312f95c0cf00acfb7857eec7bcbf64826f
- author
- TotallyGamerJet · · 2022-12-02 18:28 UTC
- committer
- GitHub · · 2022-12-02 18:28 UTC
- parent
- fcdb024
- signature
- GPG Unverified
4AEE18F83AFDEB23The key is unknown
3 files · +18 -24
M sys_darwin_amd64.s +6 -12
| @@ -71,13 +71,6 @@ TEXT syscall9X(SB), NOSPLIT, $0 | |||
| 71 | 71 | POPQ BP | |
| 72 | 72 | RET | |
| 73 | 73 | ||
| 74 | - | // runtime·cgocallback expects a call to the ABIInternal function | |
| 75 | - | // However, the tag <ABIInternal> is only available in the runtime :( | |
| 76 | - | TEXT callbackWrapInternal<>(SB), NOSPLIT, $0-0 | |
| 77 | - | MOVQ AX, arg+8(SP) | |
| 78 | - | JMP ·callbackWrap(SB) | |
| 79 | - | RET | |
| 80 | - | ||
| 81 | 74 | TEXT callbackasm1(SB), NOSPLIT, $0 | |
| 82 | 75 | // remove return address from stack, we are not returning to callbackasm, but to its caller. | |
| 83 | 76 | MOVQ 0(SP), AX | |
| @@ -118,11 +111,12 @@ TEXT callbackasm1(SB), NOSPLIT, $0 | |||
| 118 | 111 | LEAQ 24(SP), AX // take the address of callbackArgs | |
| 119 | 112 | ||
| 120 | 113 | // Call cgocallback, which will call callbackWrap(frame). | |
| 121 | - | MOVQ $0, 16(SP) // context | |
| 122 | - | MOVQ AX, 8(SP) // frame (address of callbackArgs) | |
| 123 | - | MOVQ $callbackWrapInternal<>(SB), BX | |
| 124 | - | MOVQ BX, 0(SP) // PC of function value to call (callbackWrap) | |
| 125 | - | CALL runtime·cgocallback(SB) // runtime.cgocallback(fn, frame, ctxt uintptr) | |
| 114 | + | MOVQ $0, 16(SP) // context | |
| 115 | + | MOVQ AX, 8(SP) // frame (address of callbackArgs) | |
| 116 | + | MOVQ ·callbackWrap_call(SB), DX // Get the ABIInternal function pointer | |
| 117 | + | MOVQ (DX), CX // without <ABIInternal> by using a closure. | |
| 118 | + | MOVQ CX, 0(SP) // PC of function value to call (callbackWrap) | |
| 119 | + | CALL runtime·cgocallback(SB) // runtime.cgocallback(fn, frame, ctxt uintptr) | |
| 126 | 120 | ||
| 127 | 121 | // Get callback result. | |
| 128 | 122 | MOVQ (24+callbackArgs_result)(SP), AX | |
| @@ -71,13 +71,6 @@ TEXT syscall9X(SB), NOSPLIT, $0 | |||||
| 71 | POPQ BP | 71 | POPQ BP | ||
| 72 | RET | 72 | RET | ||
| 73 | 73 | ||||
| 74 | - | // runtime·cgocallback expects a call to the ABIInternal function | |||
| 75 | - | // However, the tag <ABIInternal> is only available in the runtime :( | |||
| 76 | - | TEXT callbackWrapInternal<>(SB), NOSPLIT, $0-0 | |||
| 77 | - | MOVQ AX, arg+8(SP) | |||
| 78 | - | JMP ·callbackWrap(SB) | |||
| 79 | - | RET | |||
| 80 | - | ||||
| 81 | TEXT callbackasm1(SB), NOSPLIT, $0 | 74 | TEXT callbackasm1(SB), NOSPLIT, $0 | ||
| 82 | // remove return address from stack, we are not returning to callbackasm, but to its caller. | 75 | // remove return address from stack, we are not returning to callbackasm, but to its caller. | ||
| 83 | MOVQ 0(SP), AX | 76 | MOVQ 0(SP), AX | ||
| @@ -118,11 +111,12 @@ TEXT callbackasm1(SB), NOSPLIT, $0 | |||||
| 118 | LEAQ 24(SP), AX // take the address of callbackArgs | 111 | LEAQ 24(SP), AX // take the address of callbackArgs | ||
| 119 | 112 | ||||
| 120 | // Call cgocallback, which will call callbackWrap(frame). | 113 | // Call cgocallback, which will call callbackWrap(frame). | ||
| 121 | - | MOVQ $0, 16(SP) // context | 114 | + | MOVQ $0, 16(SP) // context |
| 122 | - | MOVQ AX, 8(SP) // frame (address of callbackArgs) | 115 | + | MOVQ AX, 8(SP) // frame (address of callbackArgs) |
| 123 | - | MOVQ $callbackWrapInternal<>(SB), BX | 116 | + | MOVQ ·callbackWrap_call(SB), DX // Get the ABIInternal function pointer |
| 124 | - | MOVQ BX, 0(SP) // PC of function value to call (callbackWrap) | 117 | + | MOVQ (DX), CX // without <ABIInternal> by using a closure. |
| 125 | - | CALL runtime·cgocallback(SB) // runtime.cgocallback(fn, frame, ctxt uintptr) | 118 | + | MOVQ CX, 0(SP) // PC of function value to call (callbackWrap) |
| 119 | + | CALL runtime·cgocallback(SB) // runtime.cgocallback(fn, frame, ctxt uintptr) | |||
| 126 | 120 | ||||
| 127 | // Get callback result. | 121 | // Get callback result. | ||
| 128 | MOVQ (24+callbackArgs_result)(SP), AX | 122 | MOVQ (24+callbackArgs_result)(SP), AX | ||
M sys_darwin_arm64.s +6 -12
| @@ -61,15 +61,6 @@ TEXT syscall9X(SB), NOSPLIT, $0 | |||
| 61 | 61 | FMOVD F0, syscall9Args_r2(R2) // save r2 | |
| 62 | 62 | RET | |
| 63 | 63 | ||
| 64 | - | // runtime·cgocallback expects a call to the ABIInternal function | |
| 65 | - | // However, the tag <ABIInternal> is only available in the runtime :( | |
| 66 | - | // This is a small wrapper function that moves the parameter from R0 to the stack | |
| 67 | - | // where the Go function can find it. It then branches without link. | |
| 68 | - | TEXT callbackWrapInternal<>(SB), NOSPLIT, $0-0 | |
| 69 | - | MOVD R0, 8(RSP) | |
| 70 | - | B ·callbackWrap(SB) | |
| 71 | - | RET | |
| 72 | - | ||
| 73 | 64 | TEXT callbackasm1(SB), NOSPLIT, $208-0 | |
| 74 | 65 | NO_LOCAL_POINTERS | |
| 75 | 66 | ||
| @@ -97,9 +88,12 @@ TEXT callbackasm1(SB), NOSPLIT, $208-0 | |||
| 97 | 88 | MOVD R0, callbackArgs_result(R13) // result | |
| 98 | 89 | ||
| 99 | 90 | // Move parameters into registers | |
| 100 | - | MOVD $callbackWrapInternal<>(SB), R0 // fn unsafe.Pointer | |
| 101 | - | MOVD R13, R1 // frame (&callbackArgs{...}) | |
| 102 | - | MOVD $0, R3 // ctxt uintptr | |
| 91 | + | // Get the ABIInternal function pointer | |
| 92 | + | // without <ABIInternal> by using a closure. | |
| 93 | + | MOVD ·callbackWrap_call(SB), R26 | |
| 94 | + | MOVD (R26), R0 // fn unsafe.Pointer | |
| 95 | + | MOVD R13, R1 // frame (&callbackArgs{...}) | |
| 96 | + | MOVD $0, R3 // ctxt uintptr | |
| 103 | 97 | ||
| 104 | 98 | // We still need to save all callee save register as before, and then | |
| 105 | 99 | // push 3 args for fn (R0, R1, R3), skipping R2. | |
| @@ -61,15 +61,6 @@ TEXT syscall9X(SB), NOSPLIT, $0 | |||||
| 61 | FMOVD F0, syscall9Args_r2(R2) // save r2 | 61 | FMOVD F0, syscall9Args_r2(R2) // save r2 | ||
| 62 | RET | 62 | RET | ||
| 63 | 63 | ||||
| 64 | - | // runtime·cgocallback expects a call to the ABIInternal function | |||
| 65 | - | // However, the tag <ABIInternal> is only available in the runtime :( | |||
| 66 | - | // This is a small wrapper function that moves the parameter from R0 to the stack | |||
| 67 | - | // where the Go function can find it. It then branches without link. | |||
| 68 | - | TEXT callbackWrapInternal<>(SB), NOSPLIT, $0-0 | |||
| 69 | - | MOVD R0, 8(RSP) | |||
| 70 | - | B ·callbackWrap(SB) | |||
| 71 | - | RET | |||
| 72 | - | ||||
| 73 | TEXT callbackasm1(SB), NOSPLIT, $208-0 | 64 | TEXT callbackasm1(SB), NOSPLIT, $208-0 | ||
| 74 | NO_LOCAL_POINTERS | 65 | NO_LOCAL_POINTERS | ||
| 75 | 66 | ||||
| @@ -97,9 +88,12 @@ TEXT callbackasm1(SB), NOSPLIT, $208-0 | |||||
| 97 | MOVD R0, callbackArgs_result(R13) // result | 88 | MOVD R0, callbackArgs_result(R13) // result | ||
| 98 | 89 | ||||
| 99 | // Move parameters into registers | 90 | // Move parameters into registers | ||
| 100 | - | MOVD $callbackWrapInternal<>(SB), R0 // fn unsafe.Pointer | 91 | + | // Get the ABIInternal function pointer |
| 101 | - | MOVD R13, R1 // frame (&callbackArgs{...}) | 92 | + | // without <ABIInternal> by using a closure. |
| 102 | - | MOVD $0, R3 // ctxt uintptr | 93 | + | MOVD ·callbackWrap_call(SB), R26 |
| 94 | + | MOVD (R26), R0 // fn unsafe.Pointer | |||
| 95 | + | MOVD R13, R1 // frame (&callbackArgs{...}) | |||
| 96 | + | MOVD $0, R3 // ctxt uintptr | |||
| 103 | 97 | ||||
| 104 | // We still need to save all callee save register as before, and then | 98 | // We still need to save all callee save register as before, and then | ||
| 105 | // push 3 args for fn (R0, R1, R3), skipping R2. | 99 | // push 3 args for fn (R0, R1, R3), skipping R2. | ||
M syscall_darwin.go +6 -0
| @@ -114,6 +114,12 @@ const callbackMaxFrame = 64 * ptrSize | |||
| 114 | 114 | // callbackasmABI0 is implemented in zcallback_GOOS_GOARCH.s | |
| 115 | 115 | var callbackasmABI0 uintptr | |
| 116 | 116 | ||
| 117 | + | // callbackWrap_call allows the calling of the ABIInternal wrapper | |
| 118 | + | // which is required for runtime.cgocallback without the | |
| 119 | + | // <ABIInternal> tag which is only allowed in the runtime. | |
| 120 | + | // This closure is used inside sys_darwin_GOARCH.s | |
| 121 | + | var callbackWrap_call = callbackWrap | |
| 122 | + | ||
| 117 | 123 | // callbackWrap is called by assembly code which determines which Go function to call. | |
| 118 | 124 | // This function takes the arguments and passes them to the Go function and returns the result. | |
| 119 | 125 | func callbackWrap(a *callbackArgs) { | |
| @@ -114,6 +114,12 @@ const callbackMaxFrame = 64 * ptrSize | |||||
| 114 | // callbackasmABI0 is implemented in zcallback_GOOS_GOARCH.s | 114 | // callbackasmABI0 is implemented in zcallback_GOOS_GOARCH.s | ||
| 115 | var callbackasmABI0 uintptr | 115 | var callbackasmABI0 uintptr | ||
| 116 | 116 | ||||
| 117 | + | // callbackWrap_call allows the calling of the ABIInternal wrapper | |||
| 118 | + | // which is required for runtime.cgocallback without the | |||
| 119 | + | // <ABIInternal> tag which is only allowed in the runtime. | |||
| 120 | + | // This closure is used inside sys_darwin_GOARCH.s | |||
| 121 | + | var callbackWrap_call = callbackWrap | |||
| 122 | + | ||||
| 117 | // callbackWrap is called by assembly code which determines which Go function to call. | 123 | // callbackWrap is called by assembly code which determines which Go function to call. | ||
| 118 | // This function takes the arguments and passes them to the Go function and returns the result. | 124 | // This function takes the arguments and passes them to the Go function and returns the result. | ||
| 119 | func callbackWrap(a *callbackArgs) { | 125 | func callbackWrap(a *callbackArgs) { | ||