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 27 TEXT 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 39 TEXT 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 48 TEXT 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 56 TEXT 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 64 TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0-0
65 CALL ·x_cgo_notify_runtime_init_done(SB)
66 RET
67 68 TEXT 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
74 TEXT ·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 83 TEXT 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 91 TEXT ·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
108