1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
3
4//go:build go1.27 && !cgo && linux
5
6#include "textflag.h"
7#include "go_asm.h"
8
9// these trampolines map the gcc ABI to Go ABI and then calls into the Go equivalent functions.
10// Note that C arguments are passed in R2-R6, which matches Go ABIInternal for the first five arguments.
11// R1 is used as a temporary register.
12
13TEXT x_cgo_init_trampoline(SB), NOSPLIT|NOFRAME, $0-0
14 MOVD R15, R1
15 SUB $192, R15
16 MOVD R1, 0(R15) // backchain
17 MOVD R14, 160(R15) // save R14
18 MOVD R9, 168(R15) // save R9 (Go runtime needs this preserved)
19
20 MOVD ·x_cgo_init_call(SB), R1
21 MOVD (R1), R1
22 BL R1
23
24 MOVD 168(R15), R9
25 MOVD 160(R15), R14
26 ADD $192, R15
27 BR R14
28
29TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT|NOFRAME, $0-0
30 MOVD R15, R1
31 SUB $176, R15
32 MOVD R1, 0(R15) // backchain
33 MOVD R14, 152(R15) // save R14
34
35 MOVD ·x_cgo_thread_start_call(SB), R1
36 MOVD (R1), R1
37 BL R1
38
39 MOVD 152(R15), R14
40 ADD $176, R15
41 BR R14
42
43TEXT x_cgo_setenv_trampoline(SB), NOSPLIT|NOFRAME, $0-0
44 MOVD R15, R1
45 SUB $176, R15
46 MOVD R1, 0(R15) // backchain
47 MOVD R14, 152(R15) // save R14
48
49 MOVD ·x_cgo_setenv_call(SB), R1
50 MOVD (R1), R1
51 BL R1
52
53 MOVD 152(R15), R14
54 ADD $176, R15
55 BR R14
56
57TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT|NOFRAME, $0-0
58 MOVD R15, R1
59 SUB $176, R15
60 MOVD R1, 0(R15) // backchain
61 MOVD R14, 152(R15) // save R14
62
63 MOVD ·x_cgo_unsetenv_call(SB), R1
64 MOVD (R1), R1
65 BL R1
66
67 MOVD 152(R15), R14
68 ADD $176, R15
69 BR R14
70
71// These just tail-call into Go functions
72TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT|NOFRAME, $0-0
73 BR ·x_cgo_notify_runtime_init_done(SB)
74
75TEXT x_cgo_bindm_trampoline(SB), NOSPLIT|NOFRAME, $0-0
76 BR ·x_cgo_bindm(SB)
77
78// setg_trampoline(setg uintptr, g uintptr) - called from Go
79TEXT ·setg_trampoline(SB), NOSPLIT|NOFRAME, $0-16
80 MOVD 8(R15), R1 // setg function pointer
81 MOVD 16(R15), R2 // g pointer -> C arg
82
83 MOVD R14, R0
84 MOVD R15, R3
85 SUB $160, R15
86 MOVD R3, 0(R15)
87 MOVD R0, 112(R15)
88 MOVD R2, 120(R15) // save newg before call
89
90 BL R1 // call setg_gcc
91
92 // Assign g directly instead of calling runtime·load_g
93 // setg_gcc has already stored newg into TLS; put it in the g register too.
94 MOVD 120(R15), g
95
96 MOVD 112(R15), R14
97 ADD $160, R15
98 BR R14
99
100TEXT threadentry_trampoline(SB), NOSPLIT|NOFRAME, $0-0
101 STMG R6, R15, 48(R15) // C save area
102 MOVD R15, R1
103 SUB $176, R15
104 MOVD R1, 0(R15) // backchain
105
106 MOVD ·threadentry_call(SB), R1
107 MOVD (R1), R1
108 BL R1
109
110 ADD $176, R15
111 LMG 48(R15), R6, R15
112 RET
113
114TEXT ·call5(SB), NOSPLIT|NOFRAME, $0-56
115 // Load Go args before modifying R15
116 MOVD 8(R15), R1 // fn
117 MOVD 16(R15), R7 // a1
118 MOVD 24(R15), R8 // a2
119 MOVD 32(R15), R9 // a3
120 MOVD 40(R15), R10 // a4
121 MOVD 48(R15), R11 // a5
122
123 // Save state
124 MOVD R15, R0 // original R15
125 MOVD R12, R6 // Go's R12
126 ADD $-128, R15
127
128 // Set up C frame with backchain
129 MOVD R0, 0(R15) // backchain -> original R15
130 MOVD R0, R3 // R3 = original R15 (can't use R0 as base!)
131 MOVD 0(R3), R7 // save 0(original R15)
132 MOVD $0, 0(R3) // terminate backchain
133
134 // Save context
135 MOVD R14, 8(R15)
136 MOVD R6, 16(R15) // R12
137 MOVD R0, 24(R15) // original R15
138 MOVD R7, 32(R15) // saved backchain
139
140 // Set up C args (reload a1 since R7 was clobbered)
141 MOVD 16(R3), R2 // a1 (use R3 as base, not R0!)
142 MOVD R8, R3 // a2
143 MOVD R9, R4 // a3
144 MOVD R10, R5 // a4
145 MOVD R11, R6 // a5
146
147 BL R1
148
149 // Store result and restore
150 MOVD 24(R15), R3 // original R15
151 MOVD R2, 56(R3) // return value
152 MOVD 32(R15), R7
153 MOVD R7, 0(R3) // restore backchain
154
155 MOVD 8(R15), R14
156 MOVD 16(R15), R12
157 MOVD 24(R15), R15
158 BR R14