1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
3
4#include "textflag.h"
5#include "internal/abi/abi_amd64.h"
6#include "go_asm.h"
7#include "funcdata.h"
8
9// syscall9X calls a function in libc on behalf of the syscall package.
10// syscall9X takes a pointer to a struct like:
11// struct {
12// fn uintptr
13// a1 uintptr
14// a2 uintptr
15// a3 uintptr
16// a4 uintptr
17// a5 uintptr
18// a6 uintptr
19// a7 uintptr
20// a8 uintptr
21// a9 uintptr
22// r1 uintptr
23// r2 uintptr
24// err uintptr
25// }
26// syscall9X must be called on the g0 stack with the
27// C calling convention (use libcCall).
28GLOBL ·syscall9XABI0(SB), NOPTR|RODATA, $8
29DATA ·syscall9XABI0(SB)/8, $syscall9X(SB)
30TEXT syscall9X(SB), NOSPLIT, $0
31 PUSHQ BP
32 MOVQ SP, BP
33 SUBQ $32, SP
34 MOVQ DI, 24(BP) // save the pointer
35 MOVQ syscall9Args_fn(DI), R10 // fn
36 MOVQ syscall9Args_a2(DI), SI // a2
37 MOVQ syscall9Args_a3(DI), DX // a3
38 MOVQ syscall9Args_a4(DI), CX // a4
39 MOVQ syscall9Args_a5(DI), R8 // a5
40 MOVQ syscall9Args_a6(DI), R9 // a6
41 MOVQ syscall9Args_a7(DI), R11 // a7
42 MOVQ syscall9Args_a8(DI), R12 // a8
43 MOVQ syscall9Args_a9(DI), R13 // a9
44 MOVQ syscall9Args_a1(DI), DI // a1
45
46 // these may be float arguments
47 // so we put them also where C expects floats
48 MOVQ DI, X0 // a1
49 MOVQ SI, X1 // a2
50 MOVQ DX, X2 // a3
51 MOVQ CX, X3 // a4
52 MOVQ R8, X4 // a5
53 MOVQ R9, X5 // a6
54 MOVQ R11, X6 // a7
55 MOVQ R12, X7 // a8
56
57 // push the remaining paramters onto the stack
58 MOVQ R11, 0(SP) // push a7
59 MOVQ R12, 8(SP) // push a8
60 MOVQ R13, 16(SP) // push a9
61 XORL AX, AX // vararg: say "no float args"
62
63 CALL R10
64
65 MOVQ 24(BP), DI // get the pointer back
66 MOVQ AX, syscall9Args_r1(DI) // r1
67 MOVQ DX, syscall9Args_r2(DI) // r2
68
69 XORL AX, AX // no error (it's ignored anyway)
70 ADDQ $32, SP
71 MOVQ BP, SP
72 POPQ BP
73 RET
74
75// runtime·cgocallback expects a call to the ABIInternal function
76// However, the tag <ABIInternal> is only available in the runtime :(
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
81TEXT callbackWrapInternal<>(SB), NOSPLIT, $0-0
82 MOVQ AX, arg+16(SP)
83 JMP ·callbackWrapPicker(SB)
84 RET
85
86TEXT callbackasm1(SB), NOSPLIT, $0
87 // remove return address from stack, we are not returning to callbackasm, but to its caller.
88 MOVQ 0(SP), AX
89 ADDQ $8, SP
90
91 MOVQ 0(SP), R12 // get the return SP so that we can align register args with stack args
92
93 // make space for first six arguments below the frame
94 ADJSP $6*8, SP
95 MOVQ DI, 8(SP)
96 MOVQ SI, 16(SP)
97 MOVQ DX, 24(SP)
98 MOVQ CX, 32(SP)
99 MOVQ R8, 40(SP)
100 MOVQ R9, 48(SP)
101 LEAQ 8(SP), R8 // R8 = address of args vector
102
103 MOVQ R12, 0(SP) // push the stack pointer below registers
104
105 // determine index into runtime·cbs table
106 MOVQ $callbackasm(SB), DX
107 SUBQ DX, AX
108 MOVQ $0, DX
109 MOVQ $5, CX // divide by 5 because each call instruction in ·callbacks is 5 bytes long
110 DIVL CX
111 SUBQ $1, AX // subtract 1 because return PC is to the next slot
112
113 // Switch from the host ABI to the Go ABI.
114 PUSH_REGS_HOST_TO_ABI0()
115
116 // Create a struct callbackArgs on our stack to be passed as
117 // the "frame" to cgocallback and on to callbackWrap.
118 // $32 to make enough room for the arguments to runtime.cgocallback
119 // and on Go 1.15 to take a pointer to the pointer to callbackArgs
120 SUBQ $(32+callbackArgs__size), SP
121 MOVQ AX, (32+callbackArgs_index)(SP) // callback index
122 MOVQ R8, (32+callbackArgs_args)(SP) // address of args vector
123 MOVQ $0, (32+callbackArgs_result)(SP) // result
124 LEAQ 32(SP), AX // take the address of callbackArgs
125
126 MOVQ AX, 24(SP) // get a **callbackArgs for go 1.15
127 LEAQ 24(SP), AX // ^^^^
128
129 // Call cgocallback, which will call callbackWrap(frame).
130 MOVQ $8, 16(SP) // context is 0 or argsize (including return value) for Go 1.15
131 MOVQ AX, 8(SP) // frame (address of callbackArgs)
132 MOVQ $callbackWrapInternal<>(SB), BX
133 MOVQ BX, 0(SP) // PC of function value to call (callbackWrap)
134 CALL runtime·cgocallback(SB) // runtime.cgocallback(fn, frame, ctxt uintptr)
135
136 // Get callback result.
137 MOVQ (32+callbackArgs_result)(SP), AX
138 ADDQ $(32+callbackArgs__size), SP // remove callbackArgs struct
139
140 POP_REGS_HOST_TO_ABI0()
141
142 MOVQ 0(SP), R12 // get the SP back
143
144 ADJSP $-6*8, SP // remove arguments
145
146 MOVQ R12, 0(SP)
147
148 RET