Loading...
Note: File does not exist in v5.4.
1/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2/*
3 * i386 specific definitions for NOLIBC
4 * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
5 */
6
7#ifndef _NOLIBC_ARCH_I386_H
8#define _NOLIBC_ARCH_I386_H
9
10/* O_* macros for fcntl/open are architecture-specific */
11#define O_RDONLY 0
12#define O_WRONLY 1
13#define O_RDWR 2
14#define O_CREAT 0x40
15#define O_EXCL 0x80
16#define O_NOCTTY 0x100
17#define O_TRUNC 0x200
18#define O_APPEND 0x400
19#define O_NONBLOCK 0x800
20#define O_DIRECTORY 0x10000
21
22/* The struct returned by the stat() syscall, 32-bit only, the syscall returns
23 * exactly 56 bytes (stops before the unused array).
24 */
25struct sys_stat_struct {
26 unsigned long st_dev;
27 unsigned long st_ino;
28 unsigned short st_mode;
29 unsigned short st_nlink;
30 unsigned short st_uid;
31 unsigned short st_gid;
32
33 unsigned long st_rdev;
34 unsigned long st_size;
35 unsigned long st_blksize;
36 unsigned long st_blocks;
37
38 unsigned long st_atime;
39 unsigned long st_atime_nsec;
40 unsigned long st_mtime;
41 unsigned long st_mtime_nsec;
42
43 unsigned long st_ctime;
44 unsigned long st_ctime_nsec;
45 unsigned long __unused[2];
46};
47
48/* Syscalls for i386 :
49 * - mostly similar to x86_64
50 * - registers are 32-bit
51 * - syscall number is passed in eax
52 * - arguments are in ebx, ecx, edx, esi, edi, ebp respectively
53 * - all registers are preserved (except eax of course)
54 * - the system call is performed by calling int $0x80
55 * - syscall return comes in eax
56 * - the arguments are cast to long and assigned into the target registers
57 * which are then simply passed as registers to the asm code, so that we
58 * don't have to experience issues with register constraints.
59 * - the syscall number is always specified last in order to allow to force
60 * some registers before (gcc refuses a %-register at the last position).
61 *
62 * Also, i386 supports the old_select syscall if newselect is not available
63 */
64#define __ARCH_WANT_SYS_OLD_SELECT
65
66#define my_syscall0(num) \
67({ \
68 long _ret; \
69 register long _num __asm__ ("eax") = (num); \
70 \
71 __asm__ volatile ( \
72 "int $0x80\n" \
73 : "=a" (_ret) \
74 : "0"(_num) \
75 : "memory", "cc" \
76 ); \
77 _ret; \
78})
79
80#define my_syscall1(num, arg1) \
81({ \
82 long _ret; \
83 register long _num __asm__ ("eax") = (num); \
84 register long _arg1 __asm__ ("ebx") = (long)(arg1); \
85 \
86 __asm__ volatile ( \
87 "int $0x80\n" \
88 : "=a" (_ret) \
89 : "r"(_arg1), \
90 "0"(_num) \
91 : "memory", "cc" \
92 ); \
93 _ret; \
94})
95
96#define my_syscall2(num, arg1, arg2) \
97({ \
98 long _ret; \
99 register long _num __asm__ ("eax") = (num); \
100 register long _arg1 __asm__ ("ebx") = (long)(arg1); \
101 register long _arg2 __asm__ ("ecx") = (long)(arg2); \
102 \
103 __asm__ volatile ( \
104 "int $0x80\n" \
105 : "=a" (_ret) \
106 : "r"(_arg1), "r"(_arg2), \
107 "0"(_num) \
108 : "memory", "cc" \
109 ); \
110 _ret; \
111})
112
113#define my_syscall3(num, arg1, arg2, arg3) \
114({ \
115 long _ret; \
116 register long _num __asm__ ("eax") = (num); \
117 register long _arg1 __asm__ ("ebx") = (long)(arg1); \
118 register long _arg2 __asm__ ("ecx") = (long)(arg2); \
119 register long _arg3 __asm__ ("edx") = (long)(arg3); \
120 \
121 __asm__ volatile ( \
122 "int $0x80\n" \
123 : "=a" (_ret) \
124 : "r"(_arg1), "r"(_arg2), "r"(_arg3), \
125 "0"(_num) \
126 : "memory", "cc" \
127 ); \
128 _ret; \
129})
130
131#define my_syscall4(num, arg1, arg2, arg3, arg4) \
132({ \
133 long _ret; \
134 register long _num __asm__ ("eax") = (num); \
135 register long _arg1 __asm__ ("ebx") = (long)(arg1); \
136 register long _arg2 __asm__ ("ecx") = (long)(arg2); \
137 register long _arg3 __asm__ ("edx") = (long)(arg3); \
138 register long _arg4 __asm__ ("esi") = (long)(arg4); \
139 \
140 __asm__ volatile ( \
141 "int $0x80\n" \
142 : "=a" (_ret) \
143 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
144 "0"(_num) \
145 : "memory", "cc" \
146 ); \
147 _ret; \
148})
149
150#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
151({ \
152 long _ret; \
153 register long _num __asm__ ("eax") = (num); \
154 register long _arg1 __asm__ ("ebx") = (long)(arg1); \
155 register long _arg2 __asm__ ("ecx") = (long)(arg2); \
156 register long _arg3 __asm__ ("edx") = (long)(arg3); \
157 register long _arg4 __asm__ ("esi") = (long)(arg4); \
158 register long _arg5 __asm__ ("edi") = (long)(arg5); \
159 \
160 __asm__ volatile ( \
161 "int $0x80\n" \
162 : "=a" (_ret) \
163 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
164 "0"(_num) \
165 : "memory", "cc" \
166 ); \
167 _ret; \
168})
169
170#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
171({ \
172 long _eax = (long)(num); \
173 long _arg6 = (long)(arg6); /* Always in memory */ \
174 __asm__ volatile ( \
175 "pushl %[_arg6]\n\t" \
176 "pushl %%ebp\n\t" \
177 "movl 4(%%esp),%%ebp\n\t" \
178 "int $0x80\n\t" \
179 "popl %%ebp\n\t" \
180 "addl $4,%%esp\n\t" \
181 : "+a"(_eax) /* %eax */ \
182 : "b"(arg1), /* %ebx */ \
183 "c"(arg2), /* %ecx */ \
184 "d"(arg3), /* %edx */ \
185 "S"(arg4), /* %esi */ \
186 "D"(arg5), /* %edi */ \
187 [_arg6]"m"(_arg6) /* memory */ \
188 : "memory", "cc" \
189 ); \
190 _eax; \
191})
192
193/* startup code */
194/*
195 * i386 System V ABI mandates:
196 * 1) last pushed argument must be 16-byte aligned.
197 * 2) The deepest stack frame should be set to zero
198 *
199 */
200__asm__ (".section .text\n"
201 ".weak _start\n"
202 "_start:\n"
203 "pop %eax\n" // argc (first arg, %eax)
204 "mov %esp, %ebx\n" // argv[] (second arg, %ebx)
205 "lea 4(%ebx,%eax,4),%ecx\n" // then a NULL then envp (third arg, %ecx)
206 "xor %ebp, %ebp\n" // zero the stack frame
207 "and $-16, %esp\n" // x86 ABI : esp must be 16-byte aligned before
208 "sub $4, %esp\n" // the call instruction (args are aligned)
209 "push %ecx\n" // push all registers on the stack so that we
210 "push %ebx\n" // support both regparm and plain stack modes
211 "push %eax\n"
212 "call main\n" // main() returns the status code in %eax
213 "mov %eax, %ebx\n" // retrieve exit code (32-bit int)
214 "movl $1, %eax\n" // NR_exit == 1
215 "int $0x80\n" // exit now
216 "hlt\n" // ensure it does not
217 "");
218
219#endif // _NOLIBC_ARCH_I386_H