1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
3
4//go:build !cgo && (freebsd || linux)
5
6#include "textflag.h"
7#include "go_asm.h"
8
9// These trampolines map the gcc ABI to Go ABI0 and then call into the Go equivalent functions.
10// On i386, both GCC and Go use stack-based calling conventions.
11//
12// When C calls a function, the stack looks like:
13// 0(SP) = return address
14// 4(SP) = arg1
15// 8(SP) = arg2
16// ...
17//
18// When we declare a Go function with frame size $N-0, Go's prologue
19// effectively does SUB $N, SP, so the C arguments shift up by N bytes:
20// N+0(SP) = return address
21// N+4(SP) = arg1
22// N+8(SP) = arg2
23//
24// Go ABI0 on 386 expects arguments starting at 0(FP) which equals N+4(SP)
25// after the prologue (where N is the local frame size).
26
27TEXT x_cgo_init_trampoline(SB), NOSPLIT, $8-0
28 // C args at 12(SP) and 16(SP) after frame setup (8 bytes local + 4 bytes ret addr)
29 // Go function expects args at 0(SP) and 4(SP) in local frame
30 MOVL 12(SP), AX // first C arg
31 MOVL 16(SP), BX // second C arg
32 MOVL AX, 0(SP) // Go arg 1
33 MOVL BX, 4(SP) // Go arg 2
34 MOVL ·x_cgo_init_call(SB), CX
35 MOVL (CX), CX
36 CALL CX
37 RET
38
39TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT, $4-0
40 // C args at 8(SP) after frame setup (4 bytes local + 4 bytes ret addr)
41 MOVL 8(SP), AX // first C arg
42 MOVL AX, 0(SP) // Go arg 1
43 MOVL ·x_cgo_thread_start_call(SB), CX
44 MOVL (CX), CX
45 CALL CX
46 RET
47
48TEXT x_cgo_setenv_trampoline(SB), NOSPLIT, $4-0
49 MOVL 8(SP), AX // first C arg
50 MOVL AX, 0(SP) // Go arg 1
51 MOVL ·x_cgo_setenv_call(SB), CX
52 MOVL (CX), CX
53 CALL CX
54 RET
55
56TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT, $4-0
57 MOVL 8(SP), AX // first C arg
58 MOVL AX, 0(SP) // Go arg 1
59 MOVL ·x_cgo_unsetenv_call(SB), CX
60 MOVL (CX), CX
61 CALL CX
62 RET
63
64TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0-0
65 CALL ·x_cgo_notify_runtime_init_done(SB)
66 RET
67
68TEXT x_cgo_bindm_trampoline(SB), NOSPLIT, $0
69 CALL ·x_cgo_bindm(SB)
70 RET
71
72// func setg_trampoline(setg uintptr, g uintptr)
73// This is called from Go, so args are at normal FP positions
74TEXT ·setg_trampoline(SB), NOSPLIT, $4-8
75 MOVL g+4(FP), AX
76 MOVL setg+0(FP), BX
77
78 // setg expects g in 0(SP)
79 MOVL AX, 0(SP)
80 CALL BX
81 RET
82
83TEXT threadentry_trampoline(SB), NOSPLIT, $4-0
84 MOVL 8(SP), AX // first C arg
85 MOVL AX, 0(SP) // Go arg 1
86 MOVL ·threadentry_call(SB), CX
87 MOVL (CX), CX
88 CALL CX
89 RET
90
91TEXT ·call5(SB), NOSPLIT, $20-28
92 MOVL fn+0(FP), AX
93 MOVL a1+4(FP), BX
94 MOVL a2+8(FP), CX
95 MOVL a3+12(FP), DX
96 MOVL a4+16(FP), SI
97 MOVL a5+20(FP), DI
98
99 // Place arguments on local stack frame for C calling convention
100 MOVL BX, 0(SP) // a1
101 MOVL CX, 4(SP) // a2
102 MOVL DX, 8(SP) // a3
103 MOVL SI, 12(SP) // a4
104 MOVL DI, 16(SP) // a5
105 CALL AX
106 MOVL AX, r1+24(FP)
107 RET