1*cc6dc5fbSWilly Tarreau /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2*cc6dc5fbSWilly Tarreau /*
3*cc6dc5fbSWilly Tarreau * x86 specific definitions for NOLIBC (both 32- and 64-bit)
4*cc6dc5fbSWilly Tarreau * Copyright (C) 2017-2025 Willy Tarreau <w@1wt.eu>
5*cc6dc5fbSWilly Tarreau */
6*cc6dc5fbSWilly Tarreau
7*cc6dc5fbSWilly Tarreau #ifndef _NOLIBC_ARCH_X86_H
8*cc6dc5fbSWilly Tarreau #define _NOLIBC_ARCH_X86_H
9*cc6dc5fbSWilly Tarreau
10*cc6dc5fbSWilly Tarreau #include "compiler.h"
11*cc6dc5fbSWilly Tarreau #include "crt.h"
12*cc6dc5fbSWilly Tarreau
13*cc6dc5fbSWilly Tarreau #if !defined(__x86_64__)
14*cc6dc5fbSWilly Tarreau
15*cc6dc5fbSWilly Tarreau /* Syscalls for i386 :
16*cc6dc5fbSWilly Tarreau * - mostly similar to x86_64
17*cc6dc5fbSWilly Tarreau * - registers are 32-bit
18*cc6dc5fbSWilly Tarreau * - syscall number is passed in eax
19*cc6dc5fbSWilly Tarreau * - arguments are in ebx, ecx, edx, esi, edi, ebp respectively
20*cc6dc5fbSWilly Tarreau * - all registers are preserved (except eax of course)
21*cc6dc5fbSWilly Tarreau * - the system call is performed by calling int $0x80
22*cc6dc5fbSWilly Tarreau * - syscall return comes in eax
23*cc6dc5fbSWilly Tarreau * - the arguments are cast to long and assigned into the target registers
24*cc6dc5fbSWilly Tarreau * which are then simply passed as registers to the asm code, so that we
25*cc6dc5fbSWilly Tarreau * don't have to experience issues with register constraints.
26*cc6dc5fbSWilly Tarreau * - the syscall number is always specified last in order to allow to force
27*cc6dc5fbSWilly Tarreau * some registers before (gcc refuses a %-register at the last position).
28*cc6dc5fbSWilly Tarreau *
29*cc6dc5fbSWilly Tarreau * Also, i386 supports the old_select syscall if newselect is not available
30*cc6dc5fbSWilly Tarreau */
31*cc6dc5fbSWilly Tarreau #define __ARCH_WANT_SYS_OLD_SELECT
32*cc6dc5fbSWilly Tarreau
33*cc6dc5fbSWilly Tarreau #define my_syscall0(num) \
34*cc6dc5fbSWilly Tarreau ({ \
35*cc6dc5fbSWilly Tarreau long _ret; \
36*cc6dc5fbSWilly Tarreau register long _num __asm__ ("eax") = (num); \
37*cc6dc5fbSWilly Tarreau \
38*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
39*cc6dc5fbSWilly Tarreau "int $0x80\n" \
40*cc6dc5fbSWilly Tarreau : "=a" (_ret) \
41*cc6dc5fbSWilly Tarreau : "0"(_num) \
42*cc6dc5fbSWilly Tarreau : "memory", "cc" \
43*cc6dc5fbSWilly Tarreau ); \
44*cc6dc5fbSWilly Tarreau _ret; \
45*cc6dc5fbSWilly Tarreau })
46*cc6dc5fbSWilly Tarreau
47*cc6dc5fbSWilly Tarreau #define my_syscall1(num, arg1) \
48*cc6dc5fbSWilly Tarreau ({ \
49*cc6dc5fbSWilly Tarreau long _ret; \
50*cc6dc5fbSWilly Tarreau register long _num __asm__ ("eax") = (num); \
51*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("ebx") = (long)(arg1); \
52*cc6dc5fbSWilly Tarreau \
53*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
54*cc6dc5fbSWilly Tarreau "int $0x80\n" \
55*cc6dc5fbSWilly Tarreau : "=a" (_ret) \
56*cc6dc5fbSWilly Tarreau : "r"(_arg1), \
57*cc6dc5fbSWilly Tarreau "0"(_num) \
58*cc6dc5fbSWilly Tarreau : "memory", "cc" \
59*cc6dc5fbSWilly Tarreau ); \
60*cc6dc5fbSWilly Tarreau _ret; \
61*cc6dc5fbSWilly Tarreau })
62*cc6dc5fbSWilly Tarreau
63*cc6dc5fbSWilly Tarreau #define my_syscall2(num, arg1, arg2) \
64*cc6dc5fbSWilly Tarreau ({ \
65*cc6dc5fbSWilly Tarreau long _ret; \
66*cc6dc5fbSWilly Tarreau register long _num __asm__ ("eax") = (num); \
67*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("ebx") = (long)(arg1); \
68*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("ecx") = (long)(arg2); \
69*cc6dc5fbSWilly Tarreau \
70*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
71*cc6dc5fbSWilly Tarreau "int $0x80\n" \
72*cc6dc5fbSWilly Tarreau : "=a" (_ret) \
73*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), \
74*cc6dc5fbSWilly Tarreau "0"(_num) \
75*cc6dc5fbSWilly Tarreau : "memory", "cc" \
76*cc6dc5fbSWilly Tarreau ); \
77*cc6dc5fbSWilly Tarreau _ret; \
78*cc6dc5fbSWilly Tarreau })
79*cc6dc5fbSWilly Tarreau
80*cc6dc5fbSWilly Tarreau #define my_syscall3(num, arg1, arg2, arg3) \
81*cc6dc5fbSWilly Tarreau ({ \
82*cc6dc5fbSWilly Tarreau long _ret; \
83*cc6dc5fbSWilly Tarreau register long _num __asm__ ("eax") = (num); \
84*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("ebx") = (long)(arg1); \
85*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("ecx") = (long)(arg2); \
86*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("edx") = (long)(arg3); \
87*cc6dc5fbSWilly Tarreau \
88*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
89*cc6dc5fbSWilly Tarreau "int $0x80\n" \
90*cc6dc5fbSWilly Tarreau : "=a" (_ret) \
91*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), \
92*cc6dc5fbSWilly Tarreau "0"(_num) \
93*cc6dc5fbSWilly Tarreau : "memory", "cc" \
94*cc6dc5fbSWilly Tarreau ); \
95*cc6dc5fbSWilly Tarreau _ret; \
96*cc6dc5fbSWilly Tarreau })
97*cc6dc5fbSWilly Tarreau
98*cc6dc5fbSWilly Tarreau #define my_syscall4(num, arg1, arg2, arg3, arg4) \
99*cc6dc5fbSWilly Tarreau ({ \
100*cc6dc5fbSWilly Tarreau long _ret; \
101*cc6dc5fbSWilly Tarreau register long _num __asm__ ("eax") = (num); \
102*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("ebx") = (long)(arg1); \
103*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("ecx") = (long)(arg2); \
104*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("edx") = (long)(arg3); \
105*cc6dc5fbSWilly Tarreau register long _arg4 __asm__ ("esi") = (long)(arg4); \
106*cc6dc5fbSWilly Tarreau \
107*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
108*cc6dc5fbSWilly Tarreau "int $0x80\n" \
109*cc6dc5fbSWilly Tarreau : "=a" (_ret) \
110*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
111*cc6dc5fbSWilly Tarreau "0"(_num) \
112*cc6dc5fbSWilly Tarreau : "memory", "cc" \
113*cc6dc5fbSWilly Tarreau ); \
114*cc6dc5fbSWilly Tarreau _ret; \
115*cc6dc5fbSWilly Tarreau })
116*cc6dc5fbSWilly Tarreau
117*cc6dc5fbSWilly Tarreau #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
118*cc6dc5fbSWilly Tarreau ({ \
119*cc6dc5fbSWilly Tarreau long _ret; \
120*cc6dc5fbSWilly Tarreau register long _num __asm__ ("eax") = (num); \
121*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("ebx") = (long)(arg1); \
122*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("ecx") = (long)(arg2); \
123*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("edx") = (long)(arg3); \
124*cc6dc5fbSWilly Tarreau register long _arg4 __asm__ ("esi") = (long)(arg4); \
125*cc6dc5fbSWilly Tarreau register long _arg5 __asm__ ("edi") = (long)(arg5); \
126*cc6dc5fbSWilly Tarreau \
127*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
128*cc6dc5fbSWilly Tarreau "int $0x80\n" \
129*cc6dc5fbSWilly Tarreau : "=a" (_ret) \
130*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
131*cc6dc5fbSWilly Tarreau "0"(_num) \
132*cc6dc5fbSWilly Tarreau : "memory", "cc" \
133*cc6dc5fbSWilly Tarreau ); \
134*cc6dc5fbSWilly Tarreau _ret; \
135*cc6dc5fbSWilly Tarreau })
136*cc6dc5fbSWilly Tarreau
137*cc6dc5fbSWilly Tarreau #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
138*cc6dc5fbSWilly Tarreau ({ \
139*cc6dc5fbSWilly Tarreau long _eax = (long)(num); \
140*cc6dc5fbSWilly Tarreau long _arg6 = (long)(arg6); /* Always in memory */ \
141*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
142*cc6dc5fbSWilly Tarreau "pushl %[_arg6]\n\t" \
143*cc6dc5fbSWilly Tarreau "pushl %%ebp\n\t" \
144*cc6dc5fbSWilly Tarreau "movl 4(%%esp),%%ebp\n\t" \
145*cc6dc5fbSWilly Tarreau "int $0x80\n\t" \
146*cc6dc5fbSWilly Tarreau "popl %%ebp\n\t" \
147*cc6dc5fbSWilly Tarreau "addl $4,%%esp\n\t" \
148*cc6dc5fbSWilly Tarreau : "+a"(_eax) /* %eax */ \
149*cc6dc5fbSWilly Tarreau : "b"(arg1), /* %ebx */ \
150*cc6dc5fbSWilly Tarreau "c"(arg2), /* %ecx */ \
151*cc6dc5fbSWilly Tarreau "d"(arg3), /* %edx */ \
152*cc6dc5fbSWilly Tarreau "S"(arg4), /* %esi */ \
153*cc6dc5fbSWilly Tarreau "D"(arg5), /* %edi */ \
154*cc6dc5fbSWilly Tarreau [_arg6]"m"(_arg6) /* memory */ \
155*cc6dc5fbSWilly Tarreau : "memory", "cc" \
156*cc6dc5fbSWilly Tarreau ); \
157*cc6dc5fbSWilly Tarreau _eax; \
158*cc6dc5fbSWilly Tarreau })
159*cc6dc5fbSWilly Tarreau
160*cc6dc5fbSWilly Tarreau /* startup code */
161*cc6dc5fbSWilly Tarreau /*
162*cc6dc5fbSWilly Tarreau * i386 System V ABI mandates:
163*cc6dc5fbSWilly Tarreau * 1) last pushed argument must be 16-byte aligned.
164*cc6dc5fbSWilly Tarreau * 2) The deepest stack frame should be set to zero
165*cc6dc5fbSWilly Tarreau *
166*cc6dc5fbSWilly Tarreau */
_start(void)167*cc6dc5fbSWilly Tarreau void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
168*cc6dc5fbSWilly Tarreau {
169*cc6dc5fbSWilly Tarreau __asm__ volatile (
170*cc6dc5fbSWilly Tarreau "xor %ebp, %ebp\n" /* zero the stack frame */
171*cc6dc5fbSWilly Tarreau "mov %esp, %eax\n" /* save stack pointer to %eax, as arg1 of _start_c */
172*cc6dc5fbSWilly Tarreau "sub $12, %esp\n" /* sub 12 to keep it aligned after the push %eax */
173*cc6dc5fbSWilly Tarreau "push %eax\n" /* push arg1 on stack to support plain stack modes too */
174*cc6dc5fbSWilly Tarreau "call _start_c\n" /* transfer to c runtime */
175*cc6dc5fbSWilly Tarreau "hlt\n" /* ensure it does not return */
176*cc6dc5fbSWilly Tarreau );
177*cc6dc5fbSWilly Tarreau __nolibc_entrypoint_epilogue();
178*cc6dc5fbSWilly Tarreau }
179*cc6dc5fbSWilly Tarreau
180*cc6dc5fbSWilly Tarreau #else /* !defined(__x86_64__) */
181*cc6dc5fbSWilly Tarreau
182*cc6dc5fbSWilly Tarreau /* Syscalls for x86_64 :
183*cc6dc5fbSWilly Tarreau * - registers are 64-bit
184*cc6dc5fbSWilly Tarreau * - syscall number is passed in rax
185*cc6dc5fbSWilly Tarreau * - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively
186*cc6dc5fbSWilly Tarreau * - the system call is performed by calling the syscall instruction
187*cc6dc5fbSWilly Tarreau * - syscall return comes in rax
188*cc6dc5fbSWilly Tarreau * - rcx and r11 are clobbered, others are preserved.
189*cc6dc5fbSWilly Tarreau * - the arguments are cast to long and assigned into the target registers
190*cc6dc5fbSWilly Tarreau * which are then simply passed as registers to the asm code, so that we
191*cc6dc5fbSWilly Tarreau * don't have to experience issues with register constraints.
192*cc6dc5fbSWilly Tarreau * - the syscall number is always specified last in order to allow to force
193*cc6dc5fbSWilly Tarreau * some registers before (gcc refuses a %-register at the last position).
194*cc6dc5fbSWilly Tarreau * - see also x86-64 ABI section A.2 AMD64 Linux Kernel Conventions, A.2.1
195*cc6dc5fbSWilly Tarreau * Calling Conventions.
196*cc6dc5fbSWilly Tarreau *
197*cc6dc5fbSWilly Tarreau * Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/home
198*cc6dc5fbSWilly Tarreau *
199*cc6dc5fbSWilly Tarreau */
200*cc6dc5fbSWilly Tarreau
201*cc6dc5fbSWilly Tarreau #define my_syscall0(num) \
202*cc6dc5fbSWilly Tarreau ({ \
203*cc6dc5fbSWilly Tarreau long _ret; \
204*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \
205*cc6dc5fbSWilly Tarreau \
206*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
207*cc6dc5fbSWilly Tarreau "syscall\n" \
208*cc6dc5fbSWilly Tarreau : "=a"(_ret) \
209*cc6dc5fbSWilly Tarreau : "0"(_num) \
210*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \
211*cc6dc5fbSWilly Tarreau ); \
212*cc6dc5fbSWilly Tarreau _ret; \
213*cc6dc5fbSWilly Tarreau })
214*cc6dc5fbSWilly Tarreau
215*cc6dc5fbSWilly Tarreau #define my_syscall1(num, arg1) \
216*cc6dc5fbSWilly Tarreau ({ \
217*cc6dc5fbSWilly Tarreau long _ret; \
218*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \
219*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("rdi") = (long)(arg1); \
220*cc6dc5fbSWilly Tarreau \
221*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
222*cc6dc5fbSWilly Tarreau "syscall\n" \
223*cc6dc5fbSWilly Tarreau : "=a"(_ret) \
224*cc6dc5fbSWilly Tarreau : "r"(_arg1), \
225*cc6dc5fbSWilly Tarreau "0"(_num) \
226*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \
227*cc6dc5fbSWilly Tarreau ); \
228*cc6dc5fbSWilly Tarreau _ret; \
229*cc6dc5fbSWilly Tarreau })
230*cc6dc5fbSWilly Tarreau
231*cc6dc5fbSWilly Tarreau #define my_syscall2(num, arg1, arg2) \
232*cc6dc5fbSWilly Tarreau ({ \
233*cc6dc5fbSWilly Tarreau long _ret; \
234*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \
235*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("rdi") = (long)(arg1); \
236*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("rsi") = (long)(arg2); \
237*cc6dc5fbSWilly Tarreau \
238*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
239*cc6dc5fbSWilly Tarreau "syscall\n" \
240*cc6dc5fbSWilly Tarreau : "=a"(_ret) \
241*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), \
242*cc6dc5fbSWilly Tarreau "0"(_num) \
243*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \
244*cc6dc5fbSWilly Tarreau ); \
245*cc6dc5fbSWilly Tarreau _ret; \
246*cc6dc5fbSWilly Tarreau })
247*cc6dc5fbSWilly Tarreau
248*cc6dc5fbSWilly Tarreau #define my_syscall3(num, arg1, arg2, arg3) \
249*cc6dc5fbSWilly Tarreau ({ \
250*cc6dc5fbSWilly Tarreau long _ret; \
251*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \
252*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("rdi") = (long)(arg1); \
253*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("rsi") = (long)(arg2); \
254*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("rdx") = (long)(arg3); \
255*cc6dc5fbSWilly Tarreau \
256*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
257*cc6dc5fbSWilly Tarreau "syscall\n" \
258*cc6dc5fbSWilly Tarreau : "=a"(_ret) \
259*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), \
260*cc6dc5fbSWilly Tarreau "0"(_num) \
261*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \
262*cc6dc5fbSWilly Tarreau ); \
263*cc6dc5fbSWilly Tarreau _ret; \
264*cc6dc5fbSWilly Tarreau })
265*cc6dc5fbSWilly Tarreau
266*cc6dc5fbSWilly Tarreau #define my_syscall4(num, arg1, arg2, arg3, arg4) \
267*cc6dc5fbSWilly Tarreau ({ \
268*cc6dc5fbSWilly Tarreau long _ret; \
269*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \
270*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("rdi") = (long)(arg1); \
271*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("rsi") = (long)(arg2); \
272*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("rdx") = (long)(arg3); \
273*cc6dc5fbSWilly Tarreau register long _arg4 __asm__ ("r10") = (long)(arg4); \
274*cc6dc5fbSWilly Tarreau \
275*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
276*cc6dc5fbSWilly Tarreau "syscall\n" \
277*cc6dc5fbSWilly Tarreau : "=a"(_ret) \
278*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
279*cc6dc5fbSWilly Tarreau "0"(_num) \
280*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \
281*cc6dc5fbSWilly Tarreau ); \
282*cc6dc5fbSWilly Tarreau _ret; \
283*cc6dc5fbSWilly Tarreau })
284*cc6dc5fbSWilly Tarreau
285*cc6dc5fbSWilly Tarreau #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
286*cc6dc5fbSWilly Tarreau ({ \
287*cc6dc5fbSWilly Tarreau long _ret; \
288*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \
289*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("rdi") = (long)(arg1); \
290*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("rsi") = (long)(arg2); \
291*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("rdx") = (long)(arg3); \
292*cc6dc5fbSWilly Tarreau register long _arg4 __asm__ ("r10") = (long)(arg4); \
293*cc6dc5fbSWilly Tarreau register long _arg5 __asm__ ("r8") = (long)(arg5); \
294*cc6dc5fbSWilly Tarreau \
295*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
296*cc6dc5fbSWilly Tarreau "syscall\n" \
297*cc6dc5fbSWilly Tarreau : "=a"(_ret) \
298*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
299*cc6dc5fbSWilly Tarreau "0"(_num) \
300*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \
301*cc6dc5fbSWilly Tarreau ); \
302*cc6dc5fbSWilly Tarreau _ret; \
303*cc6dc5fbSWilly Tarreau })
304*cc6dc5fbSWilly Tarreau
305*cc6dc5fbSWilly Tarreau #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
306*cc6dc5fbSWilly Tarreau ({ \
307*cc6dc5fbSWilly Tarreau long _ret; \
308*cc6dc5fbSWilly Tarreau register long _num __asm__ ("rax") = (num); \
309*cc6dc5fbSWilly Tarreau register long _arg1 __asm__ ("rdi") = (long)(arg1); \
310*cc6dc5fbSWilly Tarreau register long _arg2 __asm__ ("rsi") = (long)(arg2); \
311*cc6dc5fbSWilly Tarreau register long _arg3 __asm__ ("rdx") = (long)(arg3); \
312*cc6dc5fbSWilly Tarreau register long _arg4 __asm__ ("r10") = (long)(arg4); \
313*cc6dc5fbSWilly Tarreau register long _arg5 __asm__ ("r8") = (long)(arg5); \
314*cc6dc5fbSWilly Tarreau register long _arg6 __asm__ ("r9") = (long)(arg6); \
315*cc6dc5fbSWilly Tarreau \
316*cc6dc5fbSWilly Tarreau __asm__ volatile ( \
317*cc6dc5fbSWilly Tarreau "syscall\n" \
318*cc6dc5fbSWilly Tarreau : "=a"(_ret) \
319*cc6dc5fbSWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
320*cc6dc5fbSWilly Tarreau "r"(_arg6), "0"(_num) \
321*cc6dc5fbSWilly Tarreau : "rcx", "r11", "memory", "cc" \
322*cc6dc5fbSWilly Tarreau ); \
323*cc6dc5fbSWilly Tarreau _ret; \
324*cc6dc5fbSWilly Tarreau })
325*cc6dc5fbSWilly Tarreau
326*cc6dc5fbSWilly Tarreau /* startup code */
327*cc6dc5fbSWilly Tarreau /*
328*cc6dc5fbSWilly Tarreau * x86-64 System V ABI mandates:
329*cc6dc5fbSWilly Tarreau * 1) %rsp must be 16-byte aligned right before the function call.
330*cc6dc5fbSWilly Tarreau * 2) The deepest stack frame should be zero (the %rbp).
331*cc6dc5fbSWilly Tarreau *
332*cc6dc5fbSWilly Tarreau */
_start(void)333*cc6dc5fbSWilly Tarreau void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
334*cc6dc5fbSWilly Tarreau {
335*cc6dc5fbSWilly Tarreau __asm__ volatile (
336*cc6dc5fbSWilly Tarreau "xor %ebp, %ebp\n" /* zero the stack frame */
337*cc6dc5fbSWilly Tarreau "mov %rsp, %rdi\n" /* save stack pointer to %rdi, as arg1 of _start_c */
338*cc6dc5fbSWilly Tarreau "call _start_c\n" /* transfer to c runtime */
339*cc6dc5fbSWilly Tarreau "hlt\n" /* ensure it does not return */
340*cc6dc5fbSWilly Tarreau );
341*cc6dc5fbSWilly Tarreau __nolibc_entrypoint_epilogue();
342*cc6dc5fbSWilly Tarreau }
343*cc6dc5fbSWilly Tarreau
344*cc6dc5fbSWilly Tarreau #define NOLIBC_ARCH_HAS_MEMMOVE
345*cc6dc5fbSWilly Tarreau void *memmove(void *dst, const void *src, size_t len);
346*cc6dc5fbSWilly Tarreau
347*cc6dc5fbSWilly Tarreau #define NOLIBC_ARCH_HAS_MEMCPY
348*cc6dc5fbSWilly Tarreau void *memcpy(void *dst, const void *src, size_t len);
349*cc6dc5fbSWilly Tarreau
350*cc6dc5fbSWilly Tarreau #define NOLIBC_ARCH_HAS_MEMSET
351*cc6dc5fbSWilly Tarreau void *memset(void *dst, int c, size_t len);
352*cc6dc5fbSWilly Tarreau
353*cc6dc5fbSWilly Tarreau __asm__ (
354*cc6dc5fbSWilly Tarreau ".section .text.nolibc_memmove_memcpy\n"
355*cc6dc5fbSWilly Tarreau ".weak memmove\n"
356*cc6dc5fbSWilly Tarreau ".weak memcpy\n"
357*cc6dc5fbSWilly Tarreau "memmove:\n"
358*cc6dc5fbSWilly Tarreau "memcpy:\n"
359*cc6dc5fbSWilly Tarreau "movq %rdx, %rcx\n\t"
360*cc6dc5fbSWilly Tarreau "movq %rdi, %rax\n\t"
361*cc6dc5fbSWilly Tarreau "movq %rdi, %rdx\n\t"
362*cc6dc5fbSWilly Tarreau "subq %rsi, %rdx\n\t"
363*cc6dc5fbSWilly Tarreau "cmpq %rcx, %rdx\n\t"
364*cc6dc5fbSWilly Tarreau "jb 1f\n\t"
365*cc6dc5fbSWilly Tarreau "rep movsb\n\t"
366*cc6dc5fbSWilly Tarreau "retq\n"
367*cc6dc5fbSWilly Tarreau "1:" /* backward copy */
368*cc6dc5fbSWilly Tarreau "leaq -1(%rdi, %rcx, 1), %rdi\n\t"
369*cc6dc5fbSWilly Tarreau "leaq -1(%rsi, %rcx, 1), %rsi\n\t"
370*cc6dc5fbSWilly Tarreau "std\n\t"
371*cc6dc5fbSWilly Tarreau "rep movsb\n\t"
372*cc6dc5fbSWilly Tarreau "cld\n\t"
373*cc6dc5fbSWilly Tarreau "retq\n"
374*cc6dc5fbSWilly Tarreau
375*cc6dc5fbSWilly Tarreau ".section .text.nolibc_memset\n"
376*cc6dc5fbSWilly Tarreau ".weak memset\n"
377*cc6dc5fbSWilly Tarreau "memset:\n"
378*cc6dc5fbSWilly Tarreau "xchgl %eax, %esi\n\t"
379*cc6dc5fbSWilly Tarreau "movq %rdx, %rcx\n\t"
380*cc6dc5fbSWilly Tarreau "pushq %rdi\n\t"
381*cc6dc5fbSWilly Tarreau "rep stosb\n\t"
382*cc6dc5fbSWilly Tarreau "popq %rax\n\t"
383*cc6dc5fbSWilly Tarreau "retq\n"
384*cc6dc5fbSWilly Tarreau );
385*cc6dc5fbSWilly Tarreau
386*cc6dc5fbSWilly Tarreau #endif /* !defined(__x86_64__) */
387*cc6dc5fbSWilly Tarreau #endif /* _NOLIBC_ARCH_X86_H */
388