1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2026 The Ebitengine Authors
3
4//go:build linux
5
6#include "textflag.h"
7#include "go_asm.h"
8#include "funcdata.h"
9
10#define STACK_SIZE 128
11#define PTR_ADDRESS (STACK_SIZE - 4)
12
13// syscallX calls a function in libc on behalf of the syscall package.
14// syscallX takes a pointer to a struct like:
15// struct {
16// fn uintptr
17// a1 uintptr
18// ...
19// a32 uintptr
20// f1 uintptr
21// ...
22// f16 uintptr
23// arm64_r8 uintptr
24// }
25// syscallX must be called on the g0 stack with the
26// C calling convention (use libcCall).
27GLOBL ·syscallXABI0(SB), NOPTR|RODATA, $4
28DATA ·syscallXABI0(SB)/4, $syscallX(SB)
29TEXT syscallX(SB), NOSPLIT|NOFRAME, $0-0
30 // Called via C calling convention: R0 = pointer to syscallArgs
31 // NOT via Go calling convention
32 // Save link register and callee-saved registers first
33 MOVW.W R14, -4(R13) // save LR (decrement and store)
34 MOVM.DB.W [R4, R5, R6, R7, R8, R9, R11], (R13) // save callee-saved regs
35
36 MOVW R0, R8
37 SUB $STACK_SIZE, R13
38 MOVW R8, PTR_ADDRESS(R13)
39
40 // Load function pointer first (before anything can corrupt R8)
41 MOVW syscallArgs_fn(R8), R5
42 MOVW R5, (PTR_ADDRESS-4)(R13) // save fn at offset 56
43
44 // Skip floating point registers if runtime.goarmsoftfp!=0.
45 MOVB runtime·goarmsoftfp(SB), R11
46 CMP $0, R11
47 BNE skipfpload
48 // Load floating point arguments
49 // Each float64 spans 2 uintptr slots (8 bytes) on ARM32, so we skip by 2
50 MOVD syscallArgs_f1(R8), F0 // f1+f2 -> D0
51 MOVD syscallArgs_f3(R8), F1 // f3+f4 -> D1
52 MOVD syscallArgs_f5(R8), F2 // f5+f6 -> D2
53 MOVD syscallArgs_f7(R8), F3 // f7+f8 -> D3
54 MOVD syscallArgs_f9(R8), F4 // f9+f10 -> D4
55 MOVD syscallArgs_f11(R8), F5 // f11+f12 -> D5
56 MOVD syscallArgs_f13(R8), F6 // f13+f14 -> D6
57 MOVD syscallArgs_f15(R8), F7 // f15+f16 -> D7
58
59skipfpload:
60 // Load integer arguments into registers (R0-R3 for ARM EABI)
61 MOVW syscallArgs_a1(R8), R0 // a1
62 MOVW syscallArgs_a2(R8), R1 // a2
63 MOVW syscallArgs_a3(R8), R2 // a3
64 MOVW syscallArgs_a4(R8), R3 // a4
65
66 // push a5-a32 onto stack
67 MOVW syscallArgs_a5(R8), R4
68 MOVW R4, 0(R13)
69 MOVW syscallArgs_a6(R8), R4
70 MOVW R4, 4(R13)
71 MOVW syscallArgs_a7(R8), R4
72 MOVW R4, 8(R13)
73 MOVW syscallArgs_a8(R8), R4
74 MOVW R4, 12(R13)
75 MOVW syscallArgs_a9(R8), R4
76 MOVW R4, 16(R13)
77 MOVW syscallArgs_a10(R8), R4
78 MOVW R4, 20(R13)
79 MOVW syscallArgs_a11(R8), R4
80 MOVW R4, 24(R13)
81 MOVW syscallArgs_a12(R8), R4
82 MOVW R4, 28(R13)
83 MOVW syscallArgs_a13(R8), R4
84 MOVW R4, 32(R13)
85 MOVW syscallArgs_a14(R8), R4
86 MOVW R4, 36(R13)
87 MOVW syscallArgs_a15(R8), R4
88 MOVW R4, 40(R13)
89 MOVW syscallArgs_a16(R8), R4
90 MOVW R4, 44(R13)
91 MOVW syscallArgs_a17(R8), R4
92 MOVW R4, 48(R13)
93 MOVW syscallArgs_a18(R8), R4
94 MOVW R4, 52(R13)
95 MOVW syscallArgs_a19(R8), R4
96 MOVW R4, 56(R13)
97 MOVW syscallArgs_a20(R8), R4
98 MOVW R4, 60(R13)
99 MOVW syscallArgs_a21(R8), R4
100 MOVW R4, 64(R13)
101 MOVW syscallArgs_a22(R8), R4
102 MOVW R4, 68(R13)
103 MOVW syscallArgs_a23(R8), R4
104 MOVW R4, 72(R13)
105 MOVW syscallArgs_a24(R8), R4
106 MOVW R4, 76(R13)
107 MOVW syscallArgs_a25(R8), R4
108 MOVW R4, 80(R13)
109 MOVW syscallArgs_a26(R8), R4
110 MOVW R4, 84(R13)
111 MOVW syscallArgs_a27(R8), R4
112 MOVW R4, 88(R13)
113 MOVW syscallArgs_a28(R8), R4
114 MOVW R4, 92(R13)
115 MOVW syscallArgs_a29(R8), R4
116 MOVW R4, 96(R13)
117 MOVW syscallArgs_a30(R8), R4
118 MOVW R4, 100(R13)
119 MOVW syscallArgs_a31(R8), R4
120 MOVW R4, 104(R13)
121 MOVW syscallArgs_a32(R8), R4
122 MOVW R4, 108(R13)
123
124 // Load saved function pointer and call
125 MOVW (PTR_ADDRESS-4)(R13), R4
126
127 // Use BLX for Thumb interworking - Go assembler doesn't support BLX Rn
128 // BLX R4 = 0xE12FFF34 (ARM encoding, always condition)
129 WORD $0xE12FFF34 // blx r4
130
131 // pop structure pointer
132 MOVW PTR_ADDRESS(R13), R8
133 ADD $STACK_SIZE, R13
134
135 // save R0, R1
136 MOVW R0, syscallArgs_a1(R8)
137 MOVW R1, syscallArgs_a2(R8)
138
139 MOVB runtime·goarmsoftfp(SB), R11
140 CMP $0, R11
141 BNE skipfpsave
142 // save f0-f3 (each float64 spans 2 uintptr slots on ARM32)
143 MOVD F0, syscallArgs_f1(R8)
144 MOVD F1, syscallArgs_f3(R8)
145 MOVD F2, syscallArgs_f5(R8)
146 MOVD F3, syscallArgs_f7(R8)
147
148skipfpsave:
149 // Restore callee-saved registers and return
150 MOVM.IA.W (R13), [R4, R5, R6, R7, R8, R9, R11]
151 MOVW.P 4(R13), R15 // pop LR into PC (return)