xref: /linux/tools/include/nolibc/arch-x86.h (revision b1c21075d30c40762750be0cded9822791df422b)
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