1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
3 * i386 specific definitions for NOLIBC
4 * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
7 #ifndef _NOLIBC_ARCH_I386_H
8 #define _NOLIBC_ARCH_I386_H
12 /* Syscalls for i386 :
13 * - mostly similar to x86_64
14 * - registers are 32-bit
15 * - syscall number is passed in eax
16 * - arguments are in ebx, ecx, edx, esi, edi, ebp respectively
17 * - all registers are preserved (except eax of course)
18 * - the system call is performed by calling int $0x80
19 * - syscall return comes in eax
20 * - the arguments are cast to long and assigned into the target registers
21 * which are then simply passed as registers to the asm code, so that we
22 * don't have to experience issues with register constraints.
23 * - the syscall number is always specified last in order to allow to force
24 * some registers before (gcc refuses a %-register at the last position).
26 * Also, i386 supports the old_select syscall if newselect is not available
28 #define __ARCH_WANT_SYS_OLD_SELECT
30 #define my_syscall0(num) \
33 register long _num __asm__ ("eax") = (num); \
44 #define my_syscall1(num, arg1) \
47 register long _num __asm__ ("eax") = (num); \
48 register long _arg1 __asm__ ("ebx") = (long)(arg1); \
60 #define my_syscall2(num, arg1, arg2) \
63 register long _num __asm__ ("eax") = (num); \
64 register long _arg1 __asm__ ("ebx") = (long)(arg1); \
65 register long _arg2 __asm__ ("ecx") = (long)(arg2); \
70 : "r"(_arg1), "r"(_arg2), \
77 #define my_syscall3(num, arg1, arg2, arg3) \
80 register long _num __asm__ ("eax") = (num); \
81 register long _arg1 __asm__ ("ebx") = (long)(arg1); \
82 register long _arg2 __asm__ ("ecx") = (long)(arg2); \
83 register long _arg3 __asm__ ("edx") = (long)(arg3); \
88 : "r"(_arg1), "r"(_arg2), "r"(_arg3), \
95 #define my_syscall4(num, arg1, arg2, arg3, arg4) \
98 register long _num __asm__ ("eax") = (num); \
99 register long _arg1 __asm__ ("ebx") = (long)(arg1); \
100 register long _arg2 __asm__ ("ecx") = (long)(arg2); \
101 register long _arg3 __asm__ ("edx") = (long)(arg3); \
102 register long _arg4 __asm__ ("esi") = (long)(arg4); \
107 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
114 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
117 register long _num __asm__ ("eax") = (num); \
118 register long _arg1 __asm__ ("ebx") = (long)(arg1); \
119 register long _arg2 __asm__ ("ecx") = (long)(arg2); \
120 register long _arg3 __asm__ ("edx") = (long)(arg3); \
121 register long _arg4 __asm__ ("esi") = (long)(arg4); \
122 register long _arg5 __asm__ ("edi") = (long)(arg5); \
127 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
134 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
136 long _eax = (long)(num); \
137 long _arg6 = (long)(arg6); /* Always in memory */ \
139 "pushl %[_arg6]\n\t" \
141 "movl 4(%%esp),%%ebp\n\t" \
144 "addl $4,%%esp\n\t" \
145 : "+a"(_eax) /* %eax */ \
146 : "b"(arg1), /* %ebx */ \
147 "c"(arg2), /* %ecx */ \
148 "d"(arg3), /* %edx */ \
149 "S"(arg4), /* %esi */ \
150 "D"(arg5), /* %edi */ \
151 [_arg6]"m"(_arg6) /* memory */ \
157 char **environ __attribute__((weak));
158 const unsigned long *_auxv __attribute__((weak));
162 * i386 System V ABI mandates:
163 * 1) last pushed argument must be 16-byte aligned.
164 * 2) The deepest stack frame should be set to zero
167 void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
170 #ifdef _NOLIBC_STACKPROTECTOR
171 "call __stack_chk_init\n" /* initialize stack protector */
173 "pop %eax\n" /* argc (first arg, %eax) */
174 "mov %esp, %ebx\n" /* argv[] (second arg, %ebx) */
175 "lea 4(%ebx,%eax,4),%ecx\n" /* then a NULL then envp (third arg, %ecx) */
176 "mov %ecx, environ\n" /* save environ */
177 "xor %ebp, %ebp\n" /* zero the stack frame */
178 "mov %ecx, %edx\n" /* search for auxv (follows NULL after last env) */
180 "add $4, %edx\n" /* search for auxv using edx, it follows the */
181 "cmp -4(%edx), %ebp\n" /* ... NULL after last env (ebp is zero here) */
183 "mov %edx, _auxv\n" /* save it into _auxv */
184 "and $-16, %esp\n" /* x86 ABI : esp must be 16-byte aligned before */
185 "sub $4, %esp\n" /* the call instruction (args are aligned) */
186 "push %ecx\n" /* push all registers on the stack so that we */
187 "push %ebx\n" /* support both regparm and plain stack modes */
189 "call main\n" /* main() returns the status code in %eax */
190 "mov %eax, %ebx\n" /* retrieve exit code (32-bit int) */
191 "movl $1, %eax\n" /* NR_exit == 1 */
192 "int $0x80\n" /* exit now */
193 "hlt\n" /* ensure it does not */
195 __builtin_unreachable();
198 #endif /* _NOLIBC_ARCH_I386_H */