trampolines_ppc64le.s raw
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: 2026 The Ebitengine Authors
3
4 //go:build !cgo && linux
5
6 #include "textflag.h"
7 #include "go_asm.h"
8
9 // These trampolines map the C ABI to Go ABI and call into the Go equivalent functions.
10 //
11 // PPC64LE ELFv2 ABI stack frame layout:
12 // 0(R1) = backchain (pointer to caller's frame)
13 // 8(R1) = CR save area
14 // 16(R1) = LR save area
15 // 24(R1) = reserved
16 // 32(R1) = parameter save area (minimum 64 bytes for 8 args)
17 //
18 // Two patterns are used depending on call direction:
19 //
20 // C→Go trampolines: The C caller already provides a 32-byte linkage area.
21 // Save LR/CR into caller's frame at 16(R1)/8(R1) BEFORE allocating,
22 // then use MOVDU to allocate and set backchain atomically.
23 //
24 // Go→C trampolines: Go callers don't provide ELFv2 linkage area.
25 // Allocate frame first with MOVDU, then save LR/CR into OUR frame.
26
27 TEXT x_cgo_init_trampoline(SB), NOSPLIT|NOFRAME, $0-0
28 MOVD LR, 16(R1)
29 MOVW CR, R0
30 MOVD R0, 8(R1)
31
32 MOVDU R1, -32(R1)
33
34 // R3, R4 already have the arguments
35 MOVD ·x_cgo_init_call(SB), R12
36 MOVD (R12), R12
37 MOVD R12, CTR
38 CALL CTR
39
40 ADD $32, R1
41
42 MOVD 16(R1), LR
43 MOVD 8(R1), R0
44 MOVW R0, CR
45 RET
46
47 TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT|NOFRAME, $0-0
48 MOVD LR, 16(R1)
49 MOVW CR, R0
50 MOVD R0, 8(R1)
51
52 MOVDU R1, -32(R1)
53
54 MOVD ·x_cgo_thread_start_call(SB), R12
55 MOVD (R12), R12
56 MOVD R12, CTR
57 CALL CTR
58
59 ADD $32, R1
60
61 MOVD 16(R1), LR
62 MOVD 8(R1), R0
63 MOVW R0, CR
64 RET
65
66 // void (*_cgo_setenv)(char**)
67 // C arg: R3 = pointer to env
68 // This is C→Go: caller is C ABI.
69 TEXT x_cgo_setenv_trampoline(SB), NOSPLIT|NOFRAME, $0-0
70 MOVD LR, 16(R1)
71 MOVW CR, R0
72 MOVD R0, 8(R1)
73
74 MOVDU R1, -32(R1)
75
76 MOVD ·x_cgo_setenv_call(SB), R12
77 MOVD (R12), R12
78 MOVD R12, CTR
79 CALL CTR
80
81 ADD $32, R1
82
83 MOVD 16(R1), LR
84 MOVD 8(R1), R0
85 MOVW R0, CR
86 RET
87
88 TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT|NOFRAME, $0-0
89 MOVD LR, 16(R1)
90 MOVW CR, R0
91 MOVD R0, 8(R1)
92
93 MOVDU R1, -32(R1)
94
95 MOVD ·x_cgo_unsetenv_call(SB), R12
96 MOVD (R12), R12
97 MOVD R12, CTR
98 CALL CTR
99
100 ADD $32, R1
101
102 MOVD 16(R1), LR
103 MOVD 8(R1), R0
104 MOVW R0, CR
105 RET
106
107 TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT|NOFRAME, $0-0
108 MOVD LR, 16(R1)
109 MOVW CR, R0
110 MOVD R0, 8(R1)
111
112 MOVDU R1, -32(R1)
113
114 CALL ·x_cgo_notify_runtime_init_done(SB)
115
116 ADD $32, R1
117
118 MOVD 16(R1), LR
119 MOVD 8(R1), R0
120 MOVW R0, CR
121 RET
122
123 TEXT x_cgo_bindm_trampoline(SB), NOSPLIT|NOFRAME, $0-0
124 MOVD LR, 16(R1)
125 MOVW CR, R0
126 MOVD R0, 8(R1)
127
128 MOVDU R1, -32(R1)
129
130 CALL ·x_cgo_bindm(SB)
131
132 ADD $32, R1
133
134 MOVD 16(R1), LR
135 MOVD 8(R1), R0
136 MOVW R0, CR
137 RET
138
139 TEXT ·setg_trampoline(SB), NOSPLIT|NOFRAME, $0-16
140 // Save LR, CR, and R31 to non-volatile registers (C ABI preserves R14-R31)
141 MOVD LR, R20
142 MOVW CR, R21
143 MOVD R31, R22 // save R31 because load_g clobbers it
144
145 // Load arguments from Go stack
146 MOVD 32(R1), R12 // setg function pointer
147 MOVD 40(R1), R3 // g pointer → first C arg
148
149 // Allocate ELFv2 frame for the C callee (32 bytes minimum)
150 MOVDU R1, -32(R1)
151
152 // Call setg_gcc which stores g to TLS
153 MOVD R12, CTR
154 CALL CTR
155
156 // setg_gcc stored g to TLS but restored old g in R30.
157 // Call load_g to reload g from TLS into R30.
158 // Note: load_g clobbers R31
159 CALL runtime·load_g(SB)
160
161 // Deallocate frame
162 ADD $32, R1
163
164 // Clear R0 before returning to Go code.
165 // Go uses R0 as a constant 0 for things like "std r0,X(r1)" to zero stack locations.
166 // C/assembly functions may leave garbage in R0.
167 XOR R0, R0, R0
168
169 // Restore LR, CR, and R31 from non-volatile registers
170 MOVD R22, R31 // restore R31
171 MOVD R20, LR
172 MOVW R21, CR
173 RET
174
175 TEXT threadentry_trampoline(SB), NOSPLIT|NOFRAME, $0-0
176 MOVD LR, 16(R1)
177 MOVW CR, R0
178 MOVD R0, 8(R1)
179
180 MOVDU R1, -32(R1)
181
182 MOVD ·threadentry_call(SB), R12
183 MOVD (R12), R12
184 MOVD R12, CTR
185 CALL CTR
186
187 ADD $32, R1
188
189 MOVD 16(R1), LR
190 MOVD 8(R1), R0
191 MOVW R0, CR
192 RET
193
194 TEXT ·call5(SB), NOSPLIT|NOFRAME, $0-56
195 MOVD LR, R20
196 MOVW CR, R21
197
198 // Load arguments from Go stack into C argument registers
199 // Go placed args at 32(R1), 40(R1), etc.
200 MOVD 32(R1), R12 // fn
201 MOVD 40(R1), R3 // a1 → first C arg
202 MOVD 48(R1), R4 // a2 → second C arg
203 MOVD 56(R1), R5 // a3 → third C arg
204 MOVD 64(R1), R6 // a4 → fourth C arg
205 MOVD 72(R1), R7 // a5 → fifth C arg
206
207 MOVDU R1, -32(R1)
208
209 MOVD R12, CTR
210 CALL CTR
211
212 // Store return value
213 // After MOVDU -32, original 80(R1) is now at 80+32=112(R1)
214 MOVD R3, (80+32)(R1)
215
216 // Deallocate frame
217 ADD $32, R1
218
219 // Clear R0 before returning to Go code.
220 // Go uses R0 as a constant 0 register for things like "std r0,X(r1)"
221 // to zero stack locations. C functions may leave garbage in R0.
222 XOR R0, R0, R0
223
224 // Restore LR/CR from non-volatile registers
225 MOVD R20, LR
226 MOVW R21, CR
227 RET
228