Commit | Line | Data |
---|---|---|
66b6f755 WT |
1 | /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ |
2 | /* nolibc.h | |
3 | * Copyright (C) 2017-2018 Willy Tarreau <w@1wt.eu> | |
4 | */ | |
5 | ||
cc72a509 WT |
6 | /* |
7 | * This file is designed to be used as a libc alternative for minimal programs | |
8 | * with very limited requirements. It consists of a small number of syscall and | |
9 | * type definitions, and the minimal startup code needed to call main(). | |
10 | * All syscalls are declared as static functions so that they can be optimized | |
11 | * away by the compiler when not used. | |
12 | * | |
13 | * Syscalls are split into 3 levels: | |
14 | * - The lower level is the arch-specific syscall() definition, consisting in | |
15 | * assembly code in compound expressions. These are called my_syscall0() to | |
16 | * my_syscall6() depending on the number of arguments. The MIPS | |
17 | * implementation is limited to 5 arguments. All input arguments are cast | |
18 | * to a long stored in a register. These expressions always return the | |
19 | * syscall's return value as a signed long value which is often either a | |
20 | * pointer or the negated errno value. | |
21 | * | |
22 | * - The second level is mostly architecture-independent. It is made of | |
23 | * static functions called sys_<name>() which rely on my_syscallN() | |
24 | * depending on the syscall definition. These functions are responsible | |
25 | * for exposing the appropriate types for the syscall arguments (int, | |
26 | * pointers, etc) and for setting the appropriate return type (often int). | |
27 | * A few of them are architecture-specific because the syscalls are not all | |
28 | * mapped exactly the same among architectures. For example, some archs do | |
29 | * not implement select() and need pselect6() instead, so the sys_select() | |
30 | * function will have to abstract this. | |
31 | * | |
32 | * - The third level is the libc call definition. It exposes the lower raw | |
33 | * sys_<name>() calls in a way that looks like what a libc usually does, | |
34 | * takes care of specific input values, and of setting errno upon error. | |
35 | * There can be minor variations compared to standard libc calls. For | |
36 | * example the open() call always takes 3 args here. | |
37 | * | |
38 | * The errno variable is declared static and unused. This way it can be | |
39 | * optimized away if not used. However this means that a program made of | |
40 | * multiple C files may observe different errno values (one per C file). For | |
41 | * the type of programs this project targets it usually is not a problem. The | |
42 | * resulting program may even be reduced by defining the NOLIBC_IGNORE_ERRNO | |
43 | * macro, in which case the errno value will never be assigned. | |
44 | * | |
45 | * Some stdint-like integer types are defined. These are valid on all currently | |
46 | * supported architectures, because signs are enforced, ints are assumed to be | |
47 | * 32 bits, longs the size of a pointer and long long 64 bits. If more | |
48 | * architectures have to be supported, this may need to be adapted. | |
49 | * | |
50 | * Some macro definitions like the O_* values passed to open(), and some | |
51 | * structures like the sys_stat struct depend on the architecture. | |
52 | * | |
53 | * The definitions start with the architecture-specific parts, which are picked | |
54 | * based on what the compiler knows about the target architecture, and are | |
55 | * completed with the generic code. Since it is the compiler which sets the | |
56 | * target architecture, cross-compiling normally works out of the box without | |
57 | * having to specify anything. | |
58 | * | |
59 | * Finally some very common libc-level functions are provided. It is the case | |
60 | * for a few functions usually found in string.h, ctype.h, or stdlib.h. Nothing | |
61 | * is currently provided regarding stdio emulation. | |
62 | * | |
63 | * The macro NOLIBC is always defined, so that it is possible for a program to | |
64 | * check this macro to know if it is being built against and decide to disable | |
65 | * some features or simply not to include some standard libc files. | |
66 | * | |
67 | * Ideally this file should be split in multiple files for easier long term | |
68 | * maintenance, but provided as a single file as it is now, it's quite | |
69 | * convenient to use. Maybe some variations involving a set of includes at the | |
70 | * top could work. | |
71 | * | |
72 | * A simple static executable may be built this way : | |
73 | * $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \ | |
74 | * -static -include nolibc.h -lgcc -o hello hello.c | |
75 | * | |
76 | * A very useful calling convention table may be found here : | |
77 | * http://man7.org/linux/man-pages/man2/syscall.2.html | |
78 | * | |
79 | * This doc is quite convenient though not necessarily up to date : | |
80 | * https://w3challs.com/syscalls/ | |
81 | * | |
82 | */ | |
83 | ||
84 | /* Some archs (at least aarch64) don't expose the regular syscalls anymore by | |
66b6f755 WT |
85 | * default, either because they have an "_at" replacement, or because there are |
86 | * more modern alternatives. For now we'd rather still use them. | |
87 | */ | |
88 | #define __ARCH_WANT_SYSCALL_NO_AT | |
89 | #define __ARCH_WANT_SYSCALL_NO_FLAGS | |
90 | #define __ARCH_WANT_SYSCALL_DEPRECATED | |
91 | ||
92 | #include <asm/unistd.h> | |
93 | #include <asm/ioctls.h> | |
94 | #include <asm/errno.h> | |
95 | #include <linux/fs.h> | |
96 | #include <linux/loop.h> | |
97 | ||
98 | #define NOLIBC | |
99 | ||
66b6f755 WT |
100 | /* this way it will be removed if unused */ |
101 | static int errno; | |
102 | ||
103 | #ifndef NOLIBC_IGNORE_ERRNO | |
104 | #define SET_ERRNO(v) do { errno = (v); } while (0) | |
105 | #else | |
106 | #define SET_ERRNO(v) do { } while (0) | |
107 | #endif | |
108 | ||
109 | /* errno codes all ensure that they will not conflict with a valid pointer | |
06dc8d45 | 110 | * because they all correspond to the highest addressable memory page. |
66b6f755 WT |
111 | */ |
112 | #define MAX_ERRNO 4095 | |
113 | ||
114 | /* Declare a few quite common macros and types that usually are in stdlib.h, | |
115 | * stdint.h, ctype.h, unistd.h and a few other common locations. | |
116 | */ | |
117 | ||
118 | #define NULL ((void *)0) | |
119 | ||
120 | /* stdint types */ | |
121 | typedef unsigned char uint8_t; | |
122 | typedef signed char int8_t; | |
123 | typedef unsigned short uint16_t; | |
124 | typedef signed short int16_t; | |
125 | typedef unsigned int uint32_t; | |
126 | typedef signed int int32_t; | |
127 | typedef unsigned long long uint64_t; | |
128 | typedef signed long long int64_t; | |
129 | typedef unsigned long size_t; | |
130 | typedef signed long ssize_t; | |
131 | typedef unsigned long uintptr_t; | |
132 | typedef signed long intptr_t; | |
133 | typedef signed long ptrdiff_t; | |
134 | ||
135 | /* for stat() */ | |
136 | typedef unsigned int dev_t; | |
137 | typedef unsigned long ino_t; | |
138 | typedef unsigned int mode_t; | |
139 | typedef signed int pid_t; | |
140 | typedef unsigned int uid_t; | |
141 | typedef unsigned int gid_t; | |
142 | typedef unsigned long nlink_t; | |
143 | typedef signed long off_t; | |
144 | typedef signed long blksize_t; | |
145 | typedef signed long blkcnt_t; | |
146 | typedef signed long time_t; | |
147 | ||
148 | /* for poll() */ | |
149 | struct pollfd { | |
85ebb12c WT |
150 | int fd; |
151 | short int events; | |
152 | short int revents; | |
66b6f755 WT |
153 | }; |
154 | ||
155 | /* for select() */ | |
156 | struct timeval { | |
157 | long tv_sec; | |
158 | long tv_usec; | |
159 | }; | |
160 | ||
161 | /* for pselect() */ | |
162 | struct timespec { | |
163 | long tv_sec; | |
164 | long tv_nsec; | |
165 | }; | |
166 | ||
167 | /* for gettimeofday() */ | |
168 | struct timezone { | |
169 | int tz_minuteswest; | |
170 | int tz_dsttime; | |
171 | }; | |
172 | ||
173 | /* for getdents64() */ | |
174 | struct linux_dirent64 { | |
175 | uint64_t d_ino; | |
176 | int64_t d_off; | |
177 | unsigned short d_reclen; | |
178 | unsigned char d_type; | |
179 | char d_name[]; | |
180 | }; | |
181 | ||
182 | /* commonly an fd_set represents 256 FDs */ | |
183 | #define FD_SETSIZE 256 | |
184 | typedef struct { uint32_t fd32[FD_SETSIZE/32]; } fd_set; | |
185 | ||
186 | /* needed by wait4() */ | |
187 | struct rusage { | |
188 | struct timeval ru_utime; | |
189 | struct timeval ru_stime; | |
190 | long ru_maxrss; | |
191 | long ru_ixrss; | |
192 | long ru_idrss; | |
193 | long ru_isrss; | |
194 | long ru_minflt; | |
195 | long ru_majflt; | |
196 | long ru_nswap; | |
197 | long ru_inblock; | |
198 | long ru_oublock; | |
199 | long ru_msgsnd; | |
200 | long ru_msgrcv; | |
201 | long ru_nsignals; | |
202 | long ru_nvcsw; | |
203 | long ru_nivcsw; | |
204 | }; | |
205 | ||
206 | /* stat flags (WARNING, octal here) */ | |
207 | #define S_IFDIR 0040000 | |
208 | #define S_IFCHR 0020000 | |
209 | #define S_IFBLK 0060000 | |
210 | #define S_IFREG 0100000 | |
211 | #define S_IFIFO 0010000 | |
212 | #define S_IFLNK 0120000 | |
213 | #define S_IFSOCK 0140000 | |
214 | #define S_IFMT 0170000 | |
215 | ||
216 | #define S_ISDIR(mode) (((mode) & S_IFDIR) == S_IFDIR) | |
217 | #define S_ISCHR(mode) (((mode) & S_IFCHR) == S_IFCHR) | |
218 | #define S_ISBLK(mode) (((mode) & S_IFBLK) == S_IFBLK) | |
219 | #define S_ISREG(mode) (((mode) & S_IFREG) == S_IFREG) | |
220 | #define S_ISFIFO(mode) (((mode) & S_IFIFO) == S_IFIFO) | |
221 | #define S_ISLNK(mode) (((mode) & S_IFLNK) == S_IFLNK) | |
222 | #define S_ISSOCK(mode) (((mode) & S_IFSOCK) == S_IFSOCK) | |
223 | ||
224 | #define DT_UNKNOWN 0 | |
225 | #define DT_FIFO 1 | |
226 | #define DT_CHR 2 | |
227 | #define DT_DIR 4 | |
228 | #define DT_BLK 6 | |
229 | #define DT_REG 8 | |
230 | #define DT_LNK 10 | |
231 | #define DT_SOCK 12 | |
232 | ||
233 | /* all the *at functions */ | |
6c5b9de2 | 234 | #ifndef AT_FDCWD |
66b6f755 WT |
235 | #define AT_FDCWD -100 |
236 | #endif | |
237 | ||
238 | /* lseek */ | |
239 | #define SEEK_SET 0 | |
240 | #define SEEK_CUR 1 | |
241 | #define SEEK_END 2 | |
242 | ||
243 | /* reboot */ | |
244 | #define LINUX_REBOOT_MAGIC1 0xfee1dead | |
245 | #define LINUX_REBOOT_MAGIC2 0x28121969 | |
246 | #define LINUX_REBOOT_CMD_HALT 0xcdef0123 | |
247 | #define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc | |
248 | #define LINUX_REBOOT_CMD_RESTART 0x01234567 | |
249 | #define LINUX_REBOOT_CMD_SW_SUSPEND 0xd000fce2 | |
250 | ||
251 | ||
252 | /* The format of the struct as returned by the libc to the application, which | |
253 | * significantly differs from the format returned by the stat() syscall flavours. | |
254 | */ | |
255 | struct stat { | |
256 | dev_t st_dev; /* ID of device containing file */ | |
257 | ino_t st_ino; /* inode number */ | |
258 | mode_t st_mode; /* protection */ | |
259 | nlink_t st_nlink; /* number of hard links */ | |
260 | uid_t st_uid; /* user ID of owner */ | |
261 | gid_t st_gid; /* group ID of owner */ | |
262 | dev_t st_rdev; /* device ID (if special file) */ | |
263 | off_t st_size; /* total size, in bytes */ | |
264 | blksize_t st_blksize; /* blocksize for file system I/O */ | |
265 | blkcnt_t st_blocks; /* number of 512B blocks allocated */ | |
266 | time_t st_atime; /* time of last access */ | |
267 | time_t st_mtime; /* time of last modification */ | |
268 | time_t st_ctime; /* time of last status change */ | |
269 | }; | |
270 | ||
271 | #define WEXITSTATUS(status) (((status) & 0xff00) >> 8) | |
272 | #define WIFEXITED(status) (((status) & 0x7f) == 0) | |
273 | ||
274 | ||
275 | /* Below comes the architecture-specific code. For each architecture, we have | |
276 | * the syscall declarations and the _start code definition. This is the only | |
277 | * global part. On all architectures the kernel puts everything in the stack | |
278 | * before jumping to _start just above us, without any return address (_start | |
279 | * is not a function but an entry pint). So at the stack pointer we find argc. | |
280 | * Then argv[] begins, and ends at the first NULL. Then we have envp which | |
281 | * starts and ends with a NULL as well. So envp=argv+argc+1. | |
282 | */ | |
283 | ||
284 | #if defined(__x86_64__) | |
285 | /* Syscalls for x86_64 : | |
286 | * - registers are 64-bit | |
287 | * - syscall number is passed in rax | |
288 | * - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively | |
289 | * - the system call is performed by calling the syscall instruction | |
290 | * - syscall return comes in rax | |
291 | * - rcx and r8..r11 may be clobbered, others are preserved. | |
292 | * - the arguments are cast to long and assigned into the target registers | |
293 | * which are then simply passed as registers to the asm code, so that we | |
294 | * don't have to experience issues with register constraints. | |
295 | * - the syscall number is always specified last in order to allow to force | |
296 | * some registers before (gcc refuses a %-register at the last position). | |
297 | */ | |
298 | ||
299 | #define my_syscall0(num) \ | |
300 | ({ \ | |
301 | long _ret; \ | |
302 | register long _num asm("rax") = (num); \ | |
303 | \ | |
304 | asm volatile ( \ | |
305 | "syscall\n" \ | |
306 | : "=a" (_ret) \ | |
307 | : "0"(_num) \ | |
85ebb12c | 308 | : "rcx", "r8", "r9", "r10", "r11", "memory", "cc" \ |
66b6f755 WT |
309 | ); \ |
310 | _ret; \ | |
311 | }) | |
312 | ||
313 | #define my_syscall1(num, arg1) \ | |
314 | ({ \ | |
315 | long _ret; \ | |
316 | register long _num asm("rax") = (num); \ | |
317 | register long _arg1 asm("rdi") = (long)(arg1); \ | |
318 | \ | |
319 | asm volatile ( \ | |
320 | "syscall\n" \ | |
321 | : "=a" (_ret) \ | |
322 | : "r"(_arg1), \ | |
323 | "0"(_num) \ | |
85ebb12c | 324 | : "rcx", "r8", "r9", "r10", "r11", "memory", "cc" \ |
66b6f755 WT |
325 | ); \ |
326 | _ret; \ | |
327 | }) | |
328 | ||
329 | #define my_syscall2(num, arg1, arg2) \ | |
330 | ({ \ | |
331 | long _ret; \ | |
332 | register long _num asm("rax") = (num); \ | |
333 | register long _arg1 asm("rdi") = (long)(arg1); \ | |
334 | register long _arg2 asm("rsi") = (long)(arg2); \ | |
335 | \ | |
336 | asm volatile ( \ | |
337 | "syscall\n" \ | |
338 | : "=a" (_ret) \ | |
339 | : "r"(_arg1), "r"(_arg2), \ | |
340 | "0"(_num) \ | |
85ebb12c | 341 | : "rcx", "r8", "r9", "r10", "r11", "memory", "cc" \ |
66b6f755 WT |
342 | ); \ |
343 | _ret; \ | |
344 | }) | |
345 | ||
346 | #define my_syscall3(num, arg1, arg2, arg3) \ | |
347 | ({ \ | |
348 | long _ret; \ | |
349 | register long _num asm("rax") = (num); \ | |
350 | register long _arg1 asm("rdi") = (long)(arg1); \ | |
351 | register long _arg2 asm("rsi") = (long)(arg2); \ | |
352 | register long _arg3 asm("rdx") = (long)(arg3); \ | |
353 | \ | |
354 | asm volatile ( \ | |
355 | "syscall\n" \ | |
356 | : "=a" (_ret) \ | |
357 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ | |
358 | "0"(_num) \ | |
85ebb12c | 359 | : "rcx", "r8", "r9", "r10", "r11", "memory", "cc" \ |
66b6f755 WT |
360 | ); \ |
361 | _ret; \ | |
362 | }) | |
363 | ||
364 | #define my_syscall4(num, arg1, arg2, arg3, arg4) \ | |
365 | ({ \ | |
366 | long _ret; \ | |
367 | register long _num asm("rax") = (num); \ | |
368 | register long _arg1 asm("rdi") = (long)(arg1); \ | |
369 | register long _arg2 asm("rsi") = (long)(arg2); \ | |
370 | register long _arg3 asm("rdx") = (long)(arg3); \ | |
371 | register long _arg4 asm("r10") = (long)(arg4); \ | |
372 | \ | |
373 | asm volatile ( \ | |
374 | "syscall\n" \ | |
375 | : "=a" (_ret), "=r"(_arg4) \ | |
376 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ | |
377 | "0"(_num) \ | |
378 | : "rcx", "r8", "r9", "r11", "memory", "cc" \ | |
379 | ); \ | |
380 | _ret; \ | |
381 | }) | |
382 | ||
383 | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ | |
384 | ({ \ | |
385 | long _ret; \ | |
386 | register long _num asm("rax") = (num); \ | |
387 | register long _arg1 asm("rdi") = (long)(arg1); \ | |
388 | register long _arg2 asm("rsi") = (long)(arg2); \ | |
389 | register long _arg3 asm("rdx") = (long)(arg3); \ | |
390 | register long _arg4 asm("r10") = (long)(arg4); \ | |
391 | register long _arg5 asm("r8") = (long)(arg5); \ | |
392 | \ | |
393 | asm volatile ( \ | |
394 | "syscall\n" \ | |
395 | : "=a" (_ret), "=r"(_arg4), "=r"(_arg5) \ | |
396 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | |
397 | "0"(_num) \ | |
398 | : "rcx", "r9", "r11", "memory", "cc" \ | |
399 | ); \ | |
400 | _ret; \ | |
401 | }) | |
402 | ||
403 | #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ | |
404 | ({ \ | |
405 | long _ret; \ | |
406 | register long _num asm("rax") = (num); \ | |
407 | register long _arg1 asm("rdi") = (long)(arg1); \ | |
408 | register long _arg2 asm("rsi") = (long)(arg2); \ | |
409 | register long _arg3 asm("rdx") = (long)(arg3); \ | |
410 | register long _arg4 asm("r10") = (long)(arg4); \ | |
411 | register long _arg5 asm("r8") = (long)(arg5); \ | |
412 | register long _arg6 asm("r9") = (long)(arg6); \ | |
413 | \ | |
414 | asm volatile ( \ | |
415 | "syscall\n" \ | |
416 | : "=a" (_ret), "=r"(_arg4), "=r"(_arg5) \ | |
417 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | |
418 | "r"(_arg6), "0"(_num) \ | |
419 | : "rcx", "r11", "memory", "cc" \ | |
420 | ); \ | |
421 | _ret; \ | |
422 | }) | |
423 | ||
424 | /* startup code */ | |
425 | asm(".section .text\n" | |
426 | ".global _start\n" | |
427 | "_start:\n" | |
428 | "pop %rdi\n" // argc (first arg, %rdi) | |
429 | "mov %rsp, %rsi\n" // argv[] (second arg, %rsi) | |
430 | "lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx) | |
431 | "and $-16, %rsp\n" // x86 ABI : esp must be 16-byte aligned when | |
432 | "sub $8, %rsp\n" // entering the callee | |
433 | "call main\n" // main() returns the status code, we'll exit with it. | |
434 | "movzb %al, %rdi\n" // retrieve exit code from 8 lower bits | |
435 | "mov $60, %rax\n" // NR_exit == 60 | |
436 | "syscall\n" // really exit | |
437 | "hlt\n" // ensure it does not return | |
438 | ""); | |
439 | ||
440 | /* fcntl / open */ | |
441 | #define O_RDONLY 0 | |
442 | #define O_WRONLY 1 | |
443 | #define O_RDWR 2 | |
444 | #define O_CREAT 0x40 | |
445 | #define O_EXCL 0x80 | |
446 | #define O_NOCTTY 0x100 | |
447 | #define O_TRUNC 0x200 | |
448 | #define O_APPEND 0x400 | |
449 | #define O_NONBLOCK 0x800 | |
450 | #define O_DIRECTORY 0x10000 | |
451 | ||
452 | /* The struct returned by the stat() syscall, equivalent to stat64(). The | |
453 | * syscall returns 116 bytes and stops in the middle of __unused. | |
454 | */ | |
455 | struct sys_stat_struct { | |
456 | unsigned long st_dev; | |
457 | unsigned long st_ino; | |
458 | unsigned long st_nlink; | |
459 | unsigned int st_mode; | |
460 | unsigned int st_uid; | |
461 | ||
462 | unsigned int st_gid; | |
463 | unsigned int __pad0; | |
464 | unsigned long st_rdev; | |
465 | long st_size; | |
466 | long st_blksize; | |
467 | ||
468 | long st_blocks; | |
469 | unsigned long st_atime; | |
470 | unsigned long st_atime_nsec; | |
471 | unsigned long st_mtime; | |
472 | ||
473 | unsigned long st_mtime_nsec; | |
474 | unsigned long st_ctime; | |
475 | unsigned long st_ctime_nsec; | |
476 | long __unused[3]; | |
477 | }; | |
478 | ||
479 | #elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) | |
480 | /* Syscalls for i386 : | |
481 | * - mostly similar to x86_64 | |
482 | * - registers are 32-bit | |
483 | * - syscall number is passed in eax | |
484 | * - arguments are in ebx, ecx, edx, esi, edi, ebp respectively | |
485 | * - all registers are preserved (except eax of course) | |
486 | * - the system call is performed by calling int $0x80 | |
487 | * - syscall return comes in eax | |
488 | * - the arguments are cast to long and assigned into the target registers | |
489 | * which are then simply passed as registers to the asm code, so that we | |
490 | * don't have to experience issues with register constraints. | |
491 | * - the syscall number is always specified last in order to allow to force | |
492 | * some registers before (gcc refuses a %-register at the last position). | |
493 | * | |
494 | * Also, i386 supports the old_select syscall if newselect is not available | |
495 | */ | |
496 | #define __ARCH_WANT_SYS_OLD_SELECT | |
497 | ||
498 | #define my_syscall0(num) \ | |
499 | ({ \ | |
500 | long _ret; \ | |
501 | register long _num asm("eax") = (num); \ | |
502 | \ | |
503 | asm volatile ( \ | |
504 | "int $0x80\n" \ | |
505 | : "=a" (_ret) \ | |
506 | : "0"(_num) \ | |
507 | : "memory", "cc" \ | |
508 | ); \ | |
509 | _ret; \ | |
510 | }) | |
511 | ||
512 | #define my_syscall1(num, arg1) \ | |
513 | ({ \ | |
514 | long _ret; \ | |
515 | register long _num asm("eax") = (num); \ | |
516 | register long _arg1 asm("ebx") = (long)(arg1); \ | |
517 | \ | |
518 | asm volatile ( \ | |
519 | "int $0x80\n" \ | |
520 | : "=a" (_ret) \ | |
521 | : "r"(_arg1), \ | |
522 | "0"(_num) \ | |
523 | : "memory", "cc" \ | |
524 | ); \ | |
525 | _ret; \ | |
526 | }) | |
527 | ||
528 | #define my_syscall2(num, arg1, arg2) \ | |
529 | ({ \ | |
530 | long _ret; \ | |
531 | register long _num asm("eax") = (num); \ | |
532 | register long _arg1 asm("ebx") = (long)(arg1); \ | |
533 | register long _arg2 asm("ecx") = (long)(arg2); \ | |
534 | \ | |
535 | asm volatile ( \ | |
536 | "int $0x80\n" \ | |
537 | : "=a" (_ret) \ | |
538 | : "r"(_arg1), "r"(_arg2), \ | |
539 | "0"(_num) \ | |
540 | : "memory", "cc" \ | |
541 | ); \ | |
542 | _ret; \ | |
543 | }) | |
544 | ||
545 | #define my_syscall3(num, arg1, arg2, arg3) \ | |
546 | ({ \ | |
547 | long _ret; \ | |
548 | register long _num asm("eax") = (num); \ | |
549 | register long _arg1 asm("ebx") = (long)(arg1); \ | |
550 | register long _arg2 asm("ecx") = (long)(arg2); \ | |
551 | register long _arg3 asm("edx") = (long)(arg3); \ | |
552 | \ | |
553 | asm volatile ( \ | |
554 | "int $0x80\n" \ | |
555 | : "=a" (_ret) \ | |
556 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ | |
557 | "0"(_num) \ | |
558 | : "memory", "cc" \ | |
559 | ); \ | |
560 | _ret; \ | |
561 | }) | |
562 | ||
563 | #define my_syscall4(num, arg1, arg2, arg3, arg4) \ | |
564 | ({ \ | |
565 | long _ret; \ | |
566 | register long _num asm("eax") = (num); \ | |
567 | register long _arg1 asm("ebx") = (long)(arg1); \ | |
568 | register long _arg2 asm("ecx") = (long)(arg2); \ | |
569 | register long _arg3 asm("edx") = (long)(arg3); \ | |
570 | register long _arg4 asm("esi") = (long)(arg4); \ | |
571 | \ | |
572 | asm volatile ( \ | |
573 | "int $0x80\n" \ | |
574 | : "=a" (_ret) \ | |
575 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ | |
576 | "0"(_num) \ | |
577 | : "memory", "cc" \ | |
578 | ); \ | |
579 | _ret; \ | |
580 | }) | |
581 | ||
582 | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ | |
583 | ({ \ | |
584 | long _ret; \ | |
585 | register long _num asm("eax") = (num); \ | |
586 | register long _arg1 asm("ebx") = (long)(arg1); \ | |
587 | register long _arg2 asm("ecx") = (long)(arg2); \ | |
588 | register long _arg3 asm("edx") = (long)(arg3); \ | |
589 | register long _arg4 asm("esi") = (long)(arg4); \ | |
590 | register long _arg5 asm("edi") = (long)(arg5); \ | |
591 | \ | |
592 | asm volatile ( \ | |
593 | "int $0x80\n" \ | |
594 | : "=a" (_ret) \ | |
595 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | |
596 | "0"(_num) \ | |
597 | : "memory", "cc" \ | |
598 | ); \ | |
599 | _ret; \ | |
600 | }) | |
601 | ||
602 | /* startup code */ | |
603 | asm(".section .text\n" | |
604 | ".global _start\n" | |
605 | "_start:\n" | |
606 | "pop %eax\n" // argc (first arg, %eax) | |
607 | "mov %esp, %ebx\n" // argv[] (second arg, %ebx) | |
608 | "lea 4(%ebx,%eax,4),%ecx\n" // then a NULL then envp (third arg, %ecx) | |
609 | "and $-16, %esp\n" // x86 ABI : esp must be 16-byte aligned when | |
610 | "push %ecx\n" // push all registers on the stack so that we | |
611 | "push %ebx\n" // support both regparm and plain stack modes | |
612 | "push %eax\n" | |
613 | "call main\n" // main() returns the status code in %eax | |
614 | "movzbl %al, %ebx\n" // retrieve exit code from lower 8 bits | |
615 | "movl $1, %eax\n" // NR_exit == 1 | |
616 | "int $0x80\n" // exit now | |
617 | "hlt\n" // ensure it does not | |
618 | ""); | |
619 | ||
620 | /* fcntl / open */ | |
621 | #define O_RDONLY 0 | |
622 | #define O_WRONLY 1 | |
623 | #define O_RDWR 2 | |
624 | #define O_CREAT 0x40 | |
625 | #define O_EXCL 0x80 | |
626 | #define O_NOCTTY 0x100 | |
627 | #define O_TRUNC 0x200 | |
628 | #define O_APPEND 0x400 | |
629 | #define O_NONBLOCK 0x800 | |
630 | #define O_DIRECTORY 0x10000 | |
631 | ||
632 | /* The struct returned by the stat() syscall, 32-bit only, the syscall returns | |
633 | * exactly 56 bytes (stops before the unused array). | |
634 | */ | |
635 | struct sys_stat_struct { | |
636 | unsigned long st_dev; | |
637 | unsigned long st_ino; | |
638 | unsigned short st_mode; | |
639 | unsigned short st_nlink; | |
640 | unsigned short st_uid; | |
641 | unsigned short st_gid; | |
642 | ||
643 | unsigned long st_rdev; | |
644 | unsigned long st_size; | |
645 | unsigned long st_blksize; | |
646 | unsigned long st_blocks; | |
647 | ||
648 | unsigned long st_atime; | |
649 | unsigned long st_atime_nsec; | |
650 | unsigned long st_mtime; | |
651 | unsigned long st_mtime_nsec; | |
652 | ||
653 | unsigned long st_ctime; | |
654 | unsigned long st_ctime_nsec; | |
655 | unsigned long __unused[2]; | |
656 | }; | |
657 | ||
658 | #elif defined(__ARM_EABI__) | |
659 | /* Syscalls for ARM in ARM or Thumb modes : | |
660 | * - registers are 32-bit | |
661 | * - stack is 8-byte aligned | |
662 | * ( http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html) | |
663 | * - syscall number is passed in r7 | |
664 | * - arguments are in r0, r1, r2, r3, r4, r5 | |
665 | * - the system call is performed by calling svc #0 | |
666 | * - syscall return comes in r0. | |
667 | * - only lr is clobbered. | |
668 | * - the arguments are cast to long and assigned into the target registers | |
669 | * which are then simply passed as registers to the asm code, so that we | |
670 | * don't have to experience issues with register constraints. | |
671 | * - the syscall number is always specified last in order to allow to force | |
672 | * some registers before (gcc refuses a %-register at the last position). | |
673 | * | |
674 | * Also, ARM supports the old_select syscall if newselect is not available | |
675 | */ | |
676 | #define __ARCH_WANT_SYS_OLD_SELECT | |
677 | ||
678 | #define my_syscall0(num) \ | |
679 | ({ \ | |
680 | register long _num asm("r7") = (num); \ | |
681 | register long _arg1 asm("r0"); \ | |
682 | \ | |
683 | asm volatile ( \ | |
684 | "svc #0\n" \ | |
685 | : "=r"(_arg1) \ | |
686 | : "r"(_num) \ | |
687 | : "memory", "cc", "lr" \ | |
688 | ); \ | |
689 | _arg1; \ | |
690 | }) | |
691 | ||
692 | #define my_syscall1(num, arg1) \ | |
693 | ({ \ | |
694 | register long _num asm("r7") = (num); \ | |
695 | register long _arg1 asm("r0") = (long)(arg1); \ | |
696 | \ | |
697 | asm volatile ( \ | |
698 | "svc #0\n" \ | |
699 | : "=r"(_arg1) \ | |
700 | : "r"(_arg1), \ | |
701 | "r"(_num) \ | |
702 | : "memory", "cc", "lr" \ | |
703 | ); \ | |
704 | _arg1; \ | |
705 | }) | |
706 | ||
707 | #define my_syscall2(num, arg1, arg2) \ | |
708 | ({ \ | |
709 | register long _num asm("r7") = (num); \ | |
710 | register long _arg1 asm("r0") = (long)(arg1); \ | |
711 | register long _arg2 asm("r1") = (long)(arg2); \ | |
712 | \ | |
713 | asm volatile ( \ | |
714 | "svc #0\n" \ | |
715 | : "=r"(_arg1) \ | |
716 | : "r"(_arg1), "r"(_arg2), \ | |
717 | "r"(_num) \ | |
718 | : "memory", "cc", "lr" \ | |
719 | ); \ | |
720 | _arg1; \ | |
721 | }) | |
722 | ||
723 | #define my_syscall3(num, arg1, arg2, arg3) \ | |
724 | ({ \ | |
725 | register long _num asm("r7") = (num); \ | |
726 | register long _arg1 asm("r0") = (long)(arg1); \ | |
727 | register long _arg2 asm("r1") = (long)(arg2); \ | |
728 | register long _arg3 asm("r2") = (long)(arg3); \ | |
729 | \ | |
730 | asm volatile ( \ | |
731 | "svc #0\n" \ | |
732 | : "=r"(_arg1) \ | |
733 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ | |
734 | "r"(_num) \ | |
735 | : "memory", "cc", "lr" \ | |
736 | ); \ | |
737 | _arg1; \ | |
738 | }) | |
739 | ||
740 | #define my_syscall4(num, arg1, arg2, arg3, arg4) \ | |
741 | ({ \ | |
742 | register long _num asm("r7") = (num); \ | |
743 | register long _arg1 asm("r0") = (long)(arg1); \ | |
744 | register long _arg2 asm("r1") = (long)(arg2); \ | |
745 | register long _arg3 asm("r2") = (long)(arg3); \ | |
746 | register long _arg4 asm("r3") = (long)(arg4); \ | |
747 | \ | |
748 | asm volatile ( \ | |
749 | "svc #0\n" \ | |
750 | : "=r"(_arg1) \ | |
751 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ | |
752 | "r"(_num) \ | |
753 | : "memory", "cc", "lr" \ | |
754 | ); \ | |
755 | _arg1; \ | |
756 | }) | |
757 | ||
758 | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ | |
759 | ({ \ | |
760 | register long _num asm("r7") = (num); \ | |
761 | register long _arg1 asm("r0") = (long)(arg1); \ | |
762 | register long _arg2 asm("r1") = (long)(arg2); \ | |
763 | register long _arg3 asm("r2") = (long)(arg3); \ | |
764 | register long _arg4 asm("r3") = (long)(arg4); \ | |
765 | register long _arg5 asm("r4") = (long)(arg5); \ | |
766 | \ | |
767 | asm volatile ( \ | |
768 | "svc #0\n" \ | |
769 | : "=r" (_arg1) \ | |
770 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | |
771 | "r"(_num) \ | |
772 | : "memory", "cc", "lr" \ | |
773 | ); \ | |
774 | _arg1; \ | |
775 | }) | |
776 | ||
777 | /* startup code */ | |
778 | asm(".section .text\n" | |
779 | ".global _start\n" | |
780 | "_start:\n" | |
781 | #if defined(__THUMBEB__) || defined(__THUMBEL__) | |
782 | /* We enter here in 32-bit mode but if some previous functions were in | |
783 | * 16-bit mode, the assembler cannot know, so we need to tell it we're in | |
784 | * 32-bit now, then switch to 16-bit (is there a better way to do it than | |
785 | * adding 1 by hand ?) and tell the asm we're now in 16-bit mode so that | |
786 | * it generates correct instructions. Note that we do not support thumb1. | |
787 | */ | |
788 | ".code 32\n" | |
789 | "add r0, pc, #1\n" | |
790 | "bx r0\n" | |
791 | ".code 16\n" | |
792 | #endif | |
793 | "pop {%r0}\n" // argc was in the stack | |
794 | "mov %r1, %sp\n" // argv = sp | |
795 | "add %r2, %r1, %r0, lsl #2\n" // envp = argv + 4*argc ... | |
796 | "add %r2, %r2, $4\n" // ... + 4 | |
797 | "and %r3, %r1, $-8\n" // AAPCS : sp must be 8-byte aligned in the | |
798 | "mov %sp, %r3\n" // callee, an bl doesn't push (lr=pc) | |
799 | "bl main\n" // main() returns the status code, we'll exit with it. | |
800 | "and %r0, %r0, $0xff\n" // limit exit code to 8 bits | |
801 | "movs r7, $1\n" // NR_exit == 1 | |
802 | "svc $0x00\n" | |
803 | ""); | |
804 | ||
805 | /* fcntl / open */ | |
806 | #define O_RDONLY 0 | |
807 | #define O_WRONLY 1 | |
808 | #define O_RDWR 2 | |
809 | #define O_CREAT 0x40 | |
810 | #define O_EXCL 0x80 | |
811 | #define O_NOCTTY 0x100 | |
812 | #define O_TRUNC 0x200 | |
813 | #define O_APPEND 0x400 | |
814 | #define O_NONBLOCK 0x800 | |
815 | #define O_DIRECTORY 0x4000 | |
816 | ||
817 | /* The struct returned by the stat() syscall, 32-bit only, the syscall returns | |
818 | * exactly 56 bytes (stops before the unused array). In big endian, the format | |
819 | * differs as devices are returned as short only. | |
820 | */ | |
821 | struct sys_stat_struct { | |
822 | #if defined(__ARMEB__) | |
823 | unsigned short st_dev; | |
824 | unsigned short __pad1; | |
825 | #else | |
826 | unsigned long st_dev; | |
827 | #endif | |
828 | unsigned long st_ino; | |
829 | unsigned short st_mode; | |
830 | unsigned short st_nlink; | |
831 | unsigned short st_uid; | |
832 | unsigned short st_gid; | |
833 | #if defined(__ARMEB__) | |
834 | unsigned short st_rdev; | |
835 | unsigned short __pad2; | |
836 | #else | |
837 | unsigned long st_rdev; | |
838 | #endif | |
839 | unsigned long st_size; | |
840 | unsigned long st_blksize; | |
841 | unsigned long st_blocks; | |
842 | unsigned long st_atime; | |
843 | unsigned long st_atime_nsec; | |
844 | unsigned long st_mtime; | |
845 | unsigned long st_mtime_nsec; | |
846 | unsigned long st_ctime; | |
847 | unsigned long st_ctime_nsec; | |
848 | unsigned long __unused[2]; | |
849 | }; | |
850 | ||
851 | #elif defined(__aarch64__) | |
852 | /* Syscalls for AARCH64 : | |
853 | * - registers are 64-bit | |
854 | * - stack is 16-byte aligned | |
855 | * - syscall number is passed in x8 | |
856 | * - arguments are in x0, x1, x2, x3, x4, x5 | |
857 | * - the system call is performed by calling svc 0 | |
858 | * - syscall return comes in x0. | |
859 | * - the arguments are cast to long and assigned into the target registers | |
860 | * which are then simply passed as registers to the asm code, so that we | |
861 | * don't have to experience issues with register constraints. | |
862 | * | |
863 | * On aarch64, select() is not implemented so we have to use pselect6(). | |
864 | */ | |
865 | #define __ARCH_WANT_SYS_PSELECT6 | |
866 | ||
867 | #define my_syscall0(num) \ | |
868 | ({ \ | |
869 | register long _num asm("x8") = (num); \ | |
870 | register long _arg1 asm("x0"); \ | |
871 | \ | |
872 | asm volatile ( \ | |
873 | "svc #0\n" \ | |
874 | : "=r"(_arg1) \ | |
875 | : "r"(_num) \ | |
876 | : "memory", "cc" \ | |
877 | ); \ | |
878 | _arg1; \ | |
879 | }) | |
880 | ||
881 | #define my_syscall1(num, arg1) \ | |
882 | ({ \ | |
883 | register long _num asm("x8") = (num); \ | |
884 | register long _arg1 asm("x0") = (long)(arg1); \ | |
885 | \ | |
886 | asm volatile ( \ | |
887 | "svc #0\n" \ | |
888 | : "=r"(_arg1) \ | |
889 | : "r"(_arg1), \ | |
890 | "r"(_num) \ | |
891 | : "memory", "cc" \ | |
892 | ); \ | |
893 | _arg1; \ | |
894 | }) | |
895 | ||
896 | #define my_syscall2(num, arg1, arg2) \ | |
897 | ({ \ | |
898 | register long _num asm("x8") = (num); \ | |
899 | register long _arg1 asm("x0") = (long)(arg1); \ | |
900 | register long _arg2 asm("x1") = (long)(arg2); \ | |
901 | \ | |
902 | asm volatile ( \ | |
903 | "svc #0\n" \ | |
904 | : "=r"(_arg1) \ | |
905 | : "r"(_arg1), "r"(_arg2), \ | |
906 | "r"(_num) \ | |
907 | : "memory", "cc" \ | |
908 | ); \ | |
909 | _arg1; \ | |
910 | }) | |
911 | ||
912 | #define my_syscall3(num, arg1, arg2, arg3) \ | |
913 | ({ \ | |
914 | register long _num asm("x8") = (num); \ | |
915 | register long _arg1 asm("x0") = (long)(arg1); \ | |
916 | register long _arg2 asm("x1") = (long)(arg2); \ | |
917 | register long _arg3 asm("x2") = (long)(arg3); \ | |
918 | \ | |
919 | asm volatile ( \ | |
920 | "svc #0\n" \ | |
921 | : "=r"(_arg1) \ | |
922 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), \ | |
923 | "r"(_num) \ | |
924 | : "memory", "cc" \ | |
925 | ); \ | |
926 | _arg1; \ | |
927 | }) | |
928 | ||
929 | #define my_syscall4(num, arg1, arg2, arg3, arg4) \ | |
930 | ({ \ | |
931 | register long _num asm("x8") = (num); \ | |
932 | register long _arg1 asm("x0") = (long)(arg1); \ | |
933 | register long _arg2 asm("x1") = (long)(arg2); \ | |
934 | register long _arg3 asm("x2") = (long)(arg3); \ | |
935 | register long _arg4 asm("x3") = (long)(arg4); \ | |
936 | \ | |
937 | asm volatile ( \ | |
938 | "svc #0\n" \ | |
939 | : "=r"(_arg1) \ | |
940 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ | |
941 | "r"(_num) \ | |
942 | : "memory", "cc" \ | |
943 | ); \ | |
944 | _arg1; \ | |
945 | }) | |
946 | ||
947 | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ | |
948 | ({ \ | |
949 | register long _num asm("x8") = (num); \ | |
950 | register long _arg1 asm("x0") = (long)(arg1); \ | |
951 | register long _arg2 asm("x1") = (long)(arg2); \ | |
952 | register long _arg3 asm("x2") = (long)(arg3); \ | |
953 | register long _arg4 asm("x3") = (long)(arg4); \ | |
954 | register long _arg5 asm("x4") = (long)(arg5); \ | |
955 | \ | |
956 | asm volatile ( \ | |
957 | "svc #0\n" \ | |
958 | : "=r" (_arg1) \ | |
959 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | |
960 | "r"(_num) \ | |
961 | : "memory", "cc" \ | |
962 | ); \ | |
963 | _arg1; \ | |
964 | }) | |
965 | ||
966 | #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ | |
967 | ({ \ | |
968 | register long _num asm("x8") = (num); \ | |
969 | register long _arg1 asm("x0") = (long)(arg1); \ | |
970 | register long _arg2 asm("x1") = (long)(arg2); \ | |
971 | register long _arg3 asm("x2") = (long)(arg3); \ | |
972 | register long _arg4 asm("x3") = (long)(arg4); \ | |
973 | register long _arg5 asm("x4") = (long)(arg5); \ | |
974 | register long _arg6 asm("x5") = (long)(arg6); \ | |
975 | \ | |
976 | asm volatile ( \ | |
977 | "svc #0\n" \ | |
978 | : "=r" (_arg1) \ | |
979 | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | |
980 | "r"(_arg6), "r"(_num) \ | |
981 | : "memory", "cc" \ | |
982 | ); \ | |
983 | _arg1; \ | |
984 | }) | |
985 | ||
986 | /* startup code */ | |
987 | asm(".section .text\n" | |
988 | ".global _start\n" | |
989 | "_start:\n" | |
990 | "ldr x0, [sp]\n" // argc (x0) was in the stack | |
991 | "add x1, sp, 8\n" // argv (x1) = sp | |
992 | "lsl x2, x0, 3\n" // envp (x2) = 8*argc ... | |
993 | "add x2, x2, 8\n" // + 8 (skip null) | |
994 | "add x2, x2, x1\n" // + argv | |
995 | "and sp, x1, -16\n" // sp must be 16-byte aligned in the callee | |
996 | "bl main\n" // main() returns the status code, we'll exit with it. | |
997 | "and x0, x0, 0xff\n" // limit exit code to 8 bits | |
998 | "mov x8, 93\n" // NR_exit == 93 | |
999 | "svc #0\n" | |
1000 | ""); | |
1001 | ||
1002 | /* fcntl / open */ | |
1003 | #define O_RDONLY 0 | |
1004 | #define O_WRONLY 1 | |
1005 | #define O_RDWR 2 | |
1006 | #define O_CREAT 0x40 | |
1007 | #define O_EXCL 0x80 | |
1008 | #define O_NOCTTY 0x100 | |
1009 | #define O_TRUNC 0x200 | |
1010 | #define O_APPEND 0x400 | |
1011 | #define O_NONBLOCK 0x800 | |
1012 | #define O_DIRECTORY 0x4000 | |
1013 | ||
1014 | /* The struct returned by the newfstatat() syscall. Differs slightly from the | |
1015 | * x86_64's stat one by field ordering, so be careful. | |
1016 | */ | |
1017 | struct sys_stat_struct { | |
1018 | unsigned long st_dev; | |
1019 | unsigned long st_ino; | |
1020 | unsigned int st_mode; | |
1021 | unsigned int st_nlink; | |
1022 | unsigned int st_uid; | |
1023 | unsigned int st_gid; | |
1024 | ||
1025 | unsigned long st_rdev; | |
1026 | unsigned long __pad1; | |
1027 | long st_size; | |
1028 | int st_blksize; | |
1029 | int __pad2; | |
1030 | ||
1031 | long st_blocks; | |
1032 | long st_atime; | |
1033 | unsigned long st_atime_nsec; | |
1034 | long st_mtime; | |
1035 | ||
1036 | unsigned long st_mtime_nsec; | |
1037 | long st_ctime; | |
1038 | unsigned long st_ctime_nsec; | |
1039 | unsigned int __unused[2]; | |
1040 | }; | |
1041 | ||
1042 | #elif defined(__mips__) && defined(_ABIO32) | |
1043 | /* Syscalls for MIPS ABI O32 : | |
1044 | * - WARNING! there's always a delayed slot! | |
1045 | * - WARNING again, the syntax is different, registers take a '$' and numbers | |
1046 | * do not. | |
1047 | * - registers are 32-bit | |
1048 | * - stack is 8-byte aligned | |
1049 | * - syscall number is passed in v0 (starts at 0xfa0). | |
1050 | * - arguments are in a0, a1, a2, a3, then the stack. The caller needs to | |
1051 | * leave some room in the stack for the callee to save a0..a3 if needed. | |
1052 | * - Many registers are clobbered, in fact only a0..a2 and s0..s8 are | |
1053 | * preserved. See: https://www.linux-mips.org/wiki/Syscall as well as | |
1054 | * scall32-o32.S in the kernel sources. | |
1055 | * - the system call is performed by calling "syscall" | |
1056 | * - syscall return comes in v0, and register a3 needs to be checked to know | |
1057 | * if an error occured, in which case errno is in v0. | |
1058 | * - the arguments are cast to long and assigned into the target registers | |
1059 | * which are then simply passed as registers to the asm code, so that we | |
1060 | * don't have to experience issues with register constraints. | |
1061 | */ | |
1062 | ||
1063 | #define my_syscall0(num) \ | |
1064 | ({ \ | |
1065 | register long _num asm("v0") = (num); \ | |
1066 | register long _arg4 asm("a3"); \ | |
1067 | \ | |
1068 | asm volatile ( \ | |
1069 | "addiu $sp, $sp, -32\n" \ | |
1070 | "syscall\n" \ | |
1071 | "addiu $sp, $sp, 32\n" \ | |
1072 | : "=r"(_num), "=r"(_arg4) \ | |
1073 | : "r"(_num) \ | |
1074 | : "memory", "cc", "at", "v1", "hi", "lo", \ | |
f90a66d6 | 1075 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ |
66b6f755 WT |
1076 | ); \ |
1077 | _arg4 ? -_num : _num; \ | |
1078 | }) | |
1079 | ||
1080 | #define my_syscall1(num, arg1) \ | |
1081 | ({ \ | |
1082 | register long _num asm("v0") = (num); \ | |
1083 | register long _arg1 asm("a0") = (long)(arg1); \ | |
1084 | register long _arg4 asm("a3"); \ | |
1085 | \ | |
1086 | asm volatile ( \ | |
1087 | "addiu $sp, $sp, -32\n" \ | |
1088 | "syscall\n" \ | |
1089 | "addiu $sp, $sp, 32\n" \ | |
1090 | : "=r"(_num), "=r"(_arg4) \ | |
1091 | : "0"(_num), \ | |
1092 | "r"(_arg1) \ | |
1093 | : "memory", "cc", "at", "v1", "hi", "lo", \ | |
f90a66d6 | 1094 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ |
66b6f755 WT |
1095 | ); \ |
1096 | _arg4 ? -_num : _num; \ | |
1097 | }) | |
1098 | ||
1099 | #define my_syscall2(num, arg1, arg2) \ | |
1100 | ({ \ | |
1101 | register long _num asm("v0") = (num); \ | |
1102 | register long _arg1 asm("a0") = (long)(arg1); \ | |
1103 | register long _arg2 asm("a1") = (long)(arg2); \ | |
1104 | register long _arg4 asm("a3"); \ | |
1105 | \ | |
1106 | asm volatile ( \ | |
1107 | "addiu $sp, $sp, -32\n" \ | |
1108 | "syscall\n" \ | |
1109 | "addiu $sp, $sp, 32\n" \ | |
1110 | : "=r"(_num), "=r"(_arg4) \ | |
1111 | : "0"(_num), \ | |
1112 | "r"(_arg1), "r"(_arg2) \ | |
1113 | : "memory", "cc", "at", "v1", "hi", "lo", \ | |
f90a66d6 | 1114 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ |
66b6f755 WT |
1115 | ); \ |
1116 | _arg4 ? -_num : _num; \ | |
1117 | }) | |
1118 | ||
1119 | #define my_syscall3(num, arg1, arg2, arg3) \ | |
1120 | ({ \ | |
1121 | register long _num asm("v0") = (num); \ | |
1122 | register long _arg1 asm("a0") = (long)(arg1); \ | |
1123 | register long _arg2 asm("a1") = (long)(arg2); \ | |
1124 | register long _arg3 asm("a2") = (long)(arg3); \ | |
1125 | register long _arg4 asm("a3"); \ | |
1126 | \ | |
1127 | asm volatile ( \ | |
1128 | "addiu $sp, $sp, -32\n" \ | |
1129 | "syscall\n" \ | |
1130 | "addiu $sp, $sp, 32\n" \ | |
1131 | : "=r"(_num), "=r"(_arg4) \ | |
1132 | : "0"(_num), \ | |
1133 | "r"(_arg1), "r"(_arg2), "r"(_arg3) \ | |
1134 | : "memory", "cc", "at", "v1", "hi", "lo", \ | |
f90a66d6 | 1135 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ |
66b6f755 WT |
1136 | ); \ |
1137 | _arg4 ? -_num : _num; \ | |
1138 | }) | |
1139 | ||
1140 | #define my_syscall4(num, arg1, arg2, arg3, arg4) \ | |
1141 | ({ \ | |
1142 | register long _num asm("v0") = (num); \ | |
1143 | register long _arg1 asm("a0") = (long)(arg1); \ | |
1144 | register long _arg2 asm("a1") = (long)(arg2); \ | |
1145 | register long _arg3 asm("a2") = (long)(arg3); \ | |
1146 | register long _arg4 asm("a3") = (long)(arg4); \ | |
1147 | \ | |
1148 | asm volatile ( \ | |
1149 | "addiu $sp, $sp, -32\n" \ | |
1150 | "syscall\n" \ | |
1151 | "addiu $sp, $sp, 32\n" \ | |
1152 | : "=r" (_num), "=r"(_arg4) \ | |
1153 | : "0"(_num), \ | |
1154 | "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \ | |
1155 | : "memory", "cc", "at", "v1", "hi", "lo", \ | |
f90a66d6 | 1156 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ |
66b6f755 WT |
1157 | ); \ |
1158 | _arg4 ? -_num : _num; \ | |
1159 | }) | |
1160 | ||
1161 | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ | |
1162 | ({ \ | |
1163 | register long _num asm("v0") = (num); \ | |
1164 | register long _arg1 asm("a0") = (long)(arg1); \ | |
1165 | register long _arg2 asm("a1") = (long)(arg2); \ | |
1166 | register long _arg3 asm("a2") = (long)(arg3); \ | |
1167 | register long _arg4 asm("a3") = (long)(arg4); \ | |
1168 | register long _arg5 = (long)(arg5); \ | |
1169 | \ | |
1170 | asm volatile ( \ | |
1171 | "addiu $sp, $sp, -32\n" \ | |
1172 | "sw %7, 16($sp)\n" \ | |
1173 | "syscall\n " \ | |
1174 | "addiu $sp, $sp, 32\n" \ | |
1175 | : "=r" (_num), "=r"(_arg4) \ | |
1176 | : "0"(_num), \ | |
1177 | "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \ | |
1178 | : "memory", "cc", "at", "v1", "hi", "lo", \ | |
f90a66d6 | 1179 | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \ |
66b6f755 WT |
1180 | ); \ |
1181 | _arg4 ? -_num : _num; \ | |
1182 | }) | |
1183 | ||
1184 | /* startup code, note that it's called __start on MIPS */ | |
1185 | asm(".section .text\n" | |
1186 | ".set nomips16\n" | |
1187 | ".global __start\n" | |
1188 | ".set noreorder\n" | |
1189 | ".option pic0\n" | |
1190 | ".ent __start\n" | |
1191 | "__start:\n" | |
1192 | "lw $a0,($sp)\n" // argc was in the stack | |
1193 | "addiu $a1, $sp, 4\n" // argv = sp + 4 | |
1194 | "sll $a2, $a0, 2\n" // a2 = argc * 4 | |
1195 | "add $a2, $a2, $a1\n" // envp = argv + 4*argc ... | |
1196 | "addiu $a2, $a2, 4\n" // ... + 4 | |
1197 | "li $t0, -8\n" | |
1198 | "and $sp, $sp, $t0\n" // sp must be 8-byte aligned | |
1199 | "addiu $sp,$sp,-16\n" // the callee expects to save a0..a3 there! | |
1200 | "jal main\n" // main() returns the status code, we'll exit with it. | |
1201 | "nop\n" // delayed slot | |
1202 | "and $a0, $v0, 0xff\n" // limit exit code to 8 bits | |
1203 | "li $v0, 4001\n" // NR_exit == 4001 | |
1204 | "syscall\n" | |
1205 | ".end __start\n" | |
1206 | ""); | |
1207 | ||
1208 | /* fcntl / open */ | |
1209 | #define O_RDONLY 0 | |
1210 | #define O_WRONLY 1 | |
1211 | #define O_RDWR 2 | |
1212 | #define O_APPEND 0x0008 | |
1213 | #define O_NONBLOCK 0x0080 | |
1214 | #define O_CREAT 0x0100 | |
1215 | #define O_TRUNC 0x0200 | |
1216 | #define O_EXCL 0x0400 | |
1217 | #define O_NOCTTY 0x0800 | |
1218 | #define O_DIRECTORY 0x10000 | |
1219 | ||
1220 | /* The struct returned by the stat() syscall. 88 bytes are returned by the | |
1221 | * syscall. | |
1222 | */ | |
1223 | struct sys_stat_struct { | |
1224 | unsigned int st_dev; | |
1225 | long st_pad1[3]; | |
1226 | unsigned long st_ino; | |
1227 | unsigned int st_mode; | |
1228 | unsigned int st_nlink; | |
1229 | unsigned int st_uid; | |
1230 | unsigned int st_gid; | |
1231 | unsigned int st_rdev; | |
1232 | long st_pad2[2]; | |
1233 | long st_size; | |
1234 | long st_pad3; | |
1235 | long st_atime; | |
1236 | long st_atime_nsec; | |
1237 | long st_mtime; | |
1238 | long st_mtime_nsec; | |
1239 | long st_ctime; | |
1240 | long st_ctime_nsec; | |
1241 | long st_blksize; | |
1242 | long st_blocks; | |
1243 | long st_pad4[14]; | |
1244 | }; | |
1245 | ||
582e84f7 PK |
1246 | #elif defined(__riscv) |
1247 | ||
1248 | #if __riscv_xlen == 64 | |
1249 | #define PTRLOG "3" | |
1250 | #define SZREG "8" | |
1251 | #elif __riscv_xlen == 32 | |
1252 | #define PTRLOG "2" | |
1253 | #define SZREG "4" | |
1254 | #endif | |
1255 | ||
1256 | /* Syscalls for RISCV : | |
1257 | * - stack is 16-byte aligned | |
1258 | * - syscall number is passed in a7 | |
1259 | * - arguments are in a0, a1, a2, a3, a4, a5 | |
1260 | * - the system call is performed by calling ecall | |
1261 | * - syscall return comes in a0 | |
1262 | * - the arguments are cast to long and assigned into the target | |
1263 | * registers which are then simply passed as registers to the asm code, | |
1264 | * so that we don't have to experience issues with register constraints. | |
1265 | */ | |
1266 | ||
1267 | #define my_syscall0(num) \ | |
1268 | ({ \ | |
1269 | register long _num asm("a7") = (num); \ | |
1270 | register long _arg1 asm("a0"); \ | |
1271 | \ | |
1272 | asm volatile ( \ | |
1273 | "ecall\n\t" \ | |
1274 | : "=r"(_arg1) \ | |
1275 | : "r"(_num) \ | |
1276 | : "memory", "cc" \ | |
1277 | ); \ | |
1278 | _arg1; \ | |
1279 | }) | |
1280 | ||
1281 | #define my_syscall1(num, arg1) \ | |
1282 | ({ \ | |
1283 | register long _num asm("a7") = (num); \ | |
1284 | register long _arg1 asm("a0") = (long)(arg1); \ | |
1285 | \ | |
1286 | asm volatile ( \ | |
1287 | "ecall\n" \ | |
1288 | : "+r"(_arg1) \ | |
1289 | : "r"(_num) \ | |
1290 | : "memory", "cc" \ | |
1291 | ); \ | |
1292 | _arg1; \ | |
1293 | }) | |
1294 | ||
1295 | #define my_syscall2(num, arg1, arg2) \ | |
1296 | ({ \ | |
1297 | register long _num asm("a7") = (num); \ | |
1298 | register long _arg1 asm("a0") = (long)(arg1); \ | |
1299 | register long _arg2 asm("a1") = (long)(arg2); \ | |
1300 | \ | |
1301 | asm volatile ( \ | |
1302 | "ecall\n" \ | |
1303 | : "+r"(_arg1) \ | |
1304 | : "r"(_arg2), \ | |
1305 | "r"(_num) \ | |
1306 | : "memory", "cc" \ | |
1307 | ); \ | |
1308 | _arg1; \ | |
1309 | }) | |
1310 | ||
1311 | #define my_syscall3(num, arg1, arg2, arg3) \ | |
1312 | ({ \ | |
1313 | register long _num asm("a7") = (num); \ | |
1314 | register long _arg1 asm("a0") = (long)(arg1); \ | |
1315 | register long _arg2 asm("a1") = (long)(arg2); \ | |
1316 | register long _arg3 asm("a2") = (long)(arg3); \ | |
1317 | \ | |
1318 | asm volatile ( \ | |
1319 | "ecall\n\t" \ | |
1320 | : "+r"(_arg1) \ | |
1321 | : "r"(_arg2), "r"(_arg3), \ | |
1322 | "r"(_num) \ | |
1323 | : "memory", "cc" \ | |
1324 | ); \ | |
1325 | _arg1; \ | |
1326 | }) | |
1327 | ||
1328 | #define my_syscall4(num, arg1, arg2, arg3, arg4) \ | |
1329 | ({ \ | |
1330 | register long _num asm("a7") = (num); \ | |
1331 | register long _arg1 asm("a0") = (long)(arg1); \ | |
1332 | register long _arg2 asm("a1") = (long)(arg2); \ | |
1333 | register long _arg3 asm("a2") = (long)(arg3); \ | |
1334 | register long _arg4 asm("a3") = (long)(arg4); \ | |
1335 | \ | |
1336 | asm volatile ( \ | |
1337 | "ecall\n" \ | |
1338 | : "+r"(_arg1) \ | |
1339 | : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ | |
1340 | "r"(_num) \ | |
1341 | : "memory", "cc" \ | |
1342 | ); \ | |
1343 | _arg1; \ | |
1344 | }) | |
1345 | ||
1346 | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ | |
1347 | ({ \ | |
1348 | register long _num asm("a7") = (num); \ | |
1349 | register long _arg1 asm("a0") = (long)(arg1); \ | |
1350 | register long _arg2 asm("a1") = (long)(arg2); \ | |
1351 | register long _arg3 asm("a2") = (long)(arg3); \ | |
1352 | register long _arg4 asm("a3") = (long)(arg4); \ | |
1353 | register long _arg5 asm("a4") = (long)(arg5); \ | |
1354 | \ | |
1355 | asm volatile ( \ | |
1356 | "ecall\n" \ | |
1357 | : "+r"(_arg1) \ | |
1358 | : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | |
1359 | "r"(_num) \ | |
1360 | : "memory", "cc" \ | |
1361 | ); \ | |
1362 | _arg1; \ | |
1363 | }) | |
1364 | ||
1365 | #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ | |
1366 | ({ \ | |
1367 | register long _num asm("a7") = (num); \ | |
1368 | register long _arg1 asm("a0") = (long)(arg1); \ | |
1369 | register long _arg2 asm("a1") = (long)(arg2); \ | |
1370 | register long _arg3 asm("a2") = (long)(arg3); \ | |
1371 | register long _arg4 asm("a3") = (long)(arg4); \ | |
1372 | register long _arg5 asm("a4") = (long)(arg5); \ | |
1373 | register long _arg6 asm("a5") = (long)(arg6); \ | |
1374 | \ | |
1375 | asm volatile ( \ | |
1376 | "ecall\n" \ | |
1377 | : "+r"(_arg1) \ | |
1378 | : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ | |
1379 | "r"(_num) \ | |
1380 | : "memory", "cc" \ | |
1381 | ); \ | |
1382 | _arg1; \ | |
1383 | }) | |
1384 | ||
1385 | /* startup code */ | |
1386 | asm(".section .text\n" | |
1387 | ".global _start\n" | |
1388 | "_start:\n" | |
1389 | ".option push\n" | |
1390 | ".option norelax\n" | |
1391 | "lla gp, __global_pointer$\n" | |
1392 | ".option pop\n" | |
1393 | "ld a0, 0(sp)\n" // argc (a0) was in the stack | |
1394 | "add a1, sp, "SZREG"\n" // argv (a1) = sp | |
1395 | "slli a2, a0, "PTRLOG"\n" // envp (a2) = SZREG*argc ... | |
1396 | "add a2, a2, "SZREG"\n" // + SZREG (skip null) | |
1397 | "add a2,a2,a1\n" // + argv | |
1398 | "andi sp,a1,-16\n" // sp must be 16-byte aligned | |
1399 | "call main\n" // main() returns the status code, we'll exit with it. | |
1400 | "andi a0, a0, 0xff\n" // limit exit code to 8 bits | |
1401 | "li a7, 93\n" // NR_exit == 93 | |
1402 | "ecall\n" | |
1403 | ""); | |
1404 | ||
1405 | /* fcntl / open */ | |
1406 | #define O_RDONLY 0 | |
1407 | #define O_WRONLY 1 | |
1408 | #define O_RDWR 2 | |
1409 | #define O_CREAT 0x100 | |
1410 | #define O_EXCL 0x200 | |
1411 | #define O_NOCTTY 0x400 | |
1412 | #define O_TRUNC 0x1000 | |
1413 | #define O_APPEND 0x2000 | |
1414 | #define O_NONBLOCK 0x4000 | |
1415 | #define O_DIRECTORY 0x200000 | |
1416 | ||
1417 | struct sys_stat_struct { | |
1418 | unsigned long st_dev; /* Device. */ | |
1419 | unsigned long st_ino; /* File serial number. */ | |
1420 | unsigned int st_mode; /* File mode. */ | |
1421 | unsigned int st_nlink; /* Link count. */ | |
1422 | unsigned int st_uid; /* User ID of the file's owner. */ | |
1423 | unsigned int st_gid; /* Group ID of the file's group. */ | |
1424 | unsigned long st_rdev; /* Device number, if device. */ | |
1425 | unsigned long __pad1; | |
1426 | long st_size; /* Size of file, in bytes. */ | |
1427 | int st_blksize; /* Optimal block size for I/O. */ | |
1428 | int __pad2; | |
1429 | long st_blocks; /* Number 512-byte blocks allocated. */ | |
1430 | long st_atime; /* Time of last access. */ | |
1431 | unsigned long st_atime_nsec; | |
1432 | long st_mtime; /* Time of last modification. */ | |
1433 | unsigned long st_mtime_nsec; | |
1434 | long st_ctime; /* Time of last status change. */ | |
1435 | unsigned long st_ctime_nsec; | |
1436 | unsigned int __unused4; | |
1437 | unsigned int __unused5; | |
1438 | }; | |
1439 | ||
66b6f755 WT |
1440 | #endif |
1441 | ||
1442 | ||
1443 | /* Below are the C functions used to declare the raw syscalls. They try to be | |
1444 | * architecture-agnostic, and return either a success or -errno. Declaring them | |
1445 | * static will lead to them being inlined in most cases, but it's still possible | |
1446 | * to reference them by a pointer if needed. | |
1447 | */ | |
1448 | static __attribute__((unused)) | |
1449 | void *sys_brk(void *addr) | |
1450 | { | |
1451 | return (void *)my_syscall1(__NR_brk, addr); | |
1452 | } | |
1453 | ||
1454 | static __attribute__((noreturn,unused)) | |
1455 | void sys_exit(int status) | |
1456 | { | |
1457 | my_syscall1(__NR_exit, status & 255); | |
1458 | while(1); // shut the "noreturn" warnings. | |
1459 | } | |
1460 | ||
1461 | static __attribute__((unused)) | |
1462 | int sys_chdir(const char *path) | |
1463 | { | |
1464 | return my_syscall1(__NR_chdir, path); | |
1465 | } | |
1466 | ||
1467 | static __attribute__((unused)) | |
1468 | int sys_chmod(const char *path, mode_t mode) | |
1469 | { | |
1470 | #ifdef __NR_fchmodat | |
1471 | return my_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0); | |
1472 | #else | |
1473 | return my_syscall2(__NR_chmod, path, mode); | |
1474 | #endif | |
1475 | } | |
1476 | ||
1477 | static __attribute__((unused)) | |
1478 | int sys_chown(const char *path, uid_t owner, gid_t group) | |
1479 | { | |
1480 | #ifdef __NR_fchownat | |
1481 | return my_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0); | |
1482 | #else | |
1483 | return my_syscall3(__NR_chown, path, owner, group); | |
1484 | #endif | |
1485 | } | |
1486 | ||
1487 | static __attribute__((unused)) | |
1488 | int sys_chroot(const char *path) | |
1489 | { | |
1490 | return my_syscall1(__NR_chroot, path); | |
1491 | } | |
1492 | ||
1493 | static __attribute__((unused)) | |
1494 | int sys_close(int fd) | |
1495 | { | |
1496 | return my_syscall1(__NR_close, fd); | |
1497 | } | |
1498 | ||
1499 | static __attribute__((unused)) | |
1500 | int sys_dup(int fd) | |
1501 | { | |
1502 | return my_syscall1(__NR_dup, fd); | |
1503 | } | |
1504 | ||
79f220e5 WT |
1505 | #ifdef __NR_dup3 |
1506 | static __attribute__((unused)) | |
1507 | int sys_dup3(int old, int new, int flags) | |
1508 | { | |
1509 | return my_syscall3(__NR_dup3, old, new, flags); | |
1510 | } | |
1511 | #endif | |
1512 | ||
66b6f755 WT |
1513 | static __attribute__((unused)) |
1514 | int sys_dup2(int old, int new) | |
1515 | { | |
79f220e5 WT |
1516 | #ifdef __NR_dup3 |
1517 | return my_syscall3(__NR_dup3, old, new, 0); | |
1518 | #else | |
66b6f755 | 1519 | return my_syscall2(__NR_dup2, old, new); |
79f220e5 | 1520 | #endif |
66b6f755 WT |
1521 | } |
1522 | ||
1523 | static __attribute__((unused)) | |
1524 | int sys_execve(const char *filename, char *const argv[], char *const envp[]) | |
1525 | { | |
1526 | return my_syscall3(__NR_execve, filename, argv, envp); | |
1527 | } | |
1528 | ||
1529 | static __attribute__((unused)) | |
1530 | pid_t sys_fork(void) | |
1531 | { | |
1532 | return my_syscall0(__NR_fork); | |
1533 | } | |
1534 | ||
1535 | static __attribute__((unused)) | |
1536 | int sys_fsync(int fd) | |
1537 | { | |
1538 | return my_syscall1(__NR_fsync, fd); | |
1539 | } | |
1540 | ||
1541 | static __attribute__((unused)) | |
1542 | int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) | |
1543 | { | |
1544 | return my_syscall3(__NR_getdents64, fd, dirp, count); | |
1545 | } | |
1546 | ||
c0c7c103 WT |
1547 | static __attribute__((unused)) |
1548 | pid_t sys_getpgid(pid_t pid) | |
1549 | { | |
1550 | return my_syscall1(__NR_getpgid, pid); | |
1551 | } | |
1552 | ||
66b6f755 WT |
1553 | static __attribute__((unused)) |
1554 | pid_t sys_getpgrp(void) | |
1555 | { | |
c0c7c103 | 1556 | return sys_getpgid(0); |
66b6f755 WT |
1557 | } |
1558 | ||
1559 | static __attribute__((unused)) | |
1560 | pid_t sys_getpid(void) | |
1561 | { | |
1562 | return my_syscall0(__NR_getpid); | |
1563 | } | |
1564 | ||
1565 | static __attribute__((unused)) | |
1566 | int sys_gettimeofday(struct timeval *tv, struct timezone *tz) | |
1567 | { | |
1568 | return my_syscall2(__NR_gettimeofday, tv, tz); | |
1569 | } | |
1570 | ||
1571 | static __attribute__((unused)) | |
1572 | int sys_ioctl(int fd, unsigned long req, void *value) | |
1573 | { | |
1574 | return my_syscall3(__NR_ioctl, fd, req, value); | |
1575 | } | |
1576 | ||
1577 | static __attribute__((unused)) | |
1578 | int sys_kill(pid_t pid, int signal) | |
1579 | { | |
1580 | return my_syscall2(__NR_kill, pid, signal); | |
1581 | } | |
1582 | ||
1583 | static __attribute__((unused)) | |
1584 | int sys_link(const char *old, const char *new) | |
1585 | { | |
1586 | #ifdef __NR_linkat | |
1587 | return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); | |
1588 | #else | |
1589 | return my_syscall2(__NR_link, old, new); | |
1590 | #endif | |
1591 | } | |
1592 | ||
1593 | static __attribute__((unused)) | |
1594 | off_t sys_lseek(int fd, off_t offset, int whence) | |
1595 | { | |
1596 | return my_syscall3(__NR_lseek, fd, offset, whence); | |
1597 | } | |
1598 | ||
1599 | static __attribute__((unused)) | |
1600 | int sys_mkdir(const char *path, mode_t mode) | |
1601 | { | |
1602 | #ifdef __NR_mkdirat | |
1603 | return my_syscall3(__NR_mkdirat, AT_FDCWD, path, mode); | |
1604 | #else | |
1605 | return my_syscall2(__NR_mkdir, path, mode); | |
1606 | #endif | |
1607 | } | |
1608 | ||
1609 | static __attribute__((unused)) | |
1610 | long sys_mknod(const char *path, mode_t mode, dev_t dev) | |
1611 | { | |
1612 | #ifdef __NR_mknodat | |
1613 | return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev); | |
1614 | #else | |
1615 | return my_syscall3(__NR_mknod, path, mode, dev); | |
1616 | #endif | |
1617 | } | |
1618 | ||
1619 | static __attribute__((unused)) | |
1620 | int sys_mount(const char *src, const char *tgt, const char *fst, | |
1621 | unsigned long flags, const void *data) | |
1622 | { | |
1623 | return my_syscall5(__NR_mount, src, tgt, fst, flags, data); | |
1624 | } | |
1625 | ||
1626 | static __attribute__((unused)) | |
1627 | int sys_open(const char *path, int flags, mode_t mode) | |
1628 | { | |
1629 | #ifdef __NR_openat | |
1630 | return my_syscall4(__NR_openat, AT_FDCWD, path, flags, mode); | |
1631 | #else | |
1632 | return my_syscall3(__NR_open, path, flags, mode); | |
1633 | #endif | |
1634 | } | |
1635 | ||
1636 | static __attribute__((unused)) | |
1637 | int sys_pivot_root(const char *new, const char *old) | |
1638 | { | |
1639 | return my_syscall2(__NR_pivot_root, new, old); | |
1640 | } | |
1641 | ||
1642 | static __attribute__((unused)) | |
1643 | int sys_poll(struct pollfd *fds, int nfds, int timeout) | |
1644 | { | |
1645 | return my_syscall3(__NR_poll, fds, nfds, timeout); | |
1646 | } | |
1647 | ||
1648 | static __attribute__((unused)) | |
1649 | ssize_t sys_read(int fd, void *buf, size_t count) | |
1650 | { | |
1651 | return my_syscall3(__NR_read, fd, buf, count); | |
1652 | } | |
1653 | ||
1654 | static __attribute__((unused)) | |
1655 | ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) | |
1656 | { | |
1657 | return my_syscall4(__NR_reboot, magic1, magic2, cmd, arg); | |
1658 | } | |
1659 | ||
1660 | static __attribute__((unused)) | |
1661 | int sys_sched_yield(void) | |
1662 | { | |
1663 | return my_syscall0(__NR_sched_yield); | |
1664 | } | |
1665 | ||
1666 | static __attribute__((unused)) | |
1667 | int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) | |
1668 | { | |
1669 | #if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect) | |
1670 | struct sel_arg_struct { | |
1671 | unsigned long n; | |
1672 | fd_set *r, *w, *e; | |
1673 | struct timeval *t; | |
1674 | } arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout }; | |
1675 | return my_syscall1(__NR_select, &arg); | |
1676 | #elif defined(__ARCH_WANT_SYS_PSELECT6) && defined(__NR_pselect6) | |
1677 | struct timespec t; | |
1678 | ||
1679 | if (timeout) { | |
1680 | t.tv_sec = timeout->tv_sec; | |
1681 | t.tv_nsec = timeout->tv_usec * 1000; | |
1682 | } | |
1683 | return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); | |
1684 | #else | |
1685 | #ifndef __NR__newselect | |
1686 | #define __NR__newselect __NR_select | |
1687 | #endif | |
1688 | return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout); | |
1689 | #endif | |
1690 | } | |
1691 | ||
1692 | static __attribute__((unused)) | |
1693 | int sys_setpgid(pid_t pid, pid_t pgid) | |
1694 | { | |
1695 | return my_syscall2(__NR_setpgid, pid, pgid); | |
1696 | } | |
1697 | ||
1698 | static __attribute__((unused)) | |
1699 | pid_t sys_setsid(void) | |
1700 | { | |
1701 | return my_syscall0(__NR_setsid); | |
1702 | } | |
1703 | ||
1704 | static __attribute__((unused)) | |
1705 | int sys_stat(const char *path, struct stat *buf) | |
1706 | { | |
1707 | struct sys_stat_struct stat; | |
1708 | long ret; | |
1709 | ||
1710 | #ifdef __NR_newfstatat | |
1711 | /* only solution for arm64 */ | |
1712 | ret = my_syscall4(__NR_newfstatat, AT_FDCWD, path, &stat, 0); | |
1713 | #else | |
1714 | ret = my_syscall2(__NR_stat, path, &stat); | |
1715 | #endif | |
1716 | buf->st_dev = stat.st_dev; | |
1717 | buf->st_ino = stat.st_ino; | |
1718 | buf->st_mode = stat.st_mode; | |
1719 | buf->st_nlink = stat.st_nlink; | |
1720 | buf->st_uid = stat.st_uid; | |
1721 | buf->st_gid = stat.st_gid; | |
1722 | buf->st_rdev = stat.st_rdev; | |
1723 | buf->st_size = stat.st_size; | |
1724 | buf->st_blksize = stat.st_blksize; | |
1725 | buf->st_blocks = stat.st_blocks; | |
1726 | buf->st_atime = stat.st_atime; | |
1727 | buf->st_mtime = stat.st_mtime; | |
1728 | buf->st_ctime = stat.st_ctime; | |
1729 | return ret; | |
1730 | } | |
1731 | ||
1732 | ||
1733 | static __attribute__((unused)) | |
1734 | int sys_symlink(const char *old, const char *new) | |
1735 | { | |
1736 | #ifdef __NR_symlinkat | |
1737 | return my_syscall3(__NR_symlinkat, old, AT_FDCWD, new); | |
1738 | #else | |
1739 | return my_syscall2(__NR_symlink, old, new); | |
1740 | #endif | |
1741 | } | |
1742 | ||
1743 | static __attribute__((unused)) | |
1744 | mode_t sys_umask(mode_t mode) | |
1745 | { | |
1746 | return my_syscall1(__NR_umask, mode); | |
1747 | } | |
1748 | ||
1749 | static __attribute__((unused)) | |
1750 | int sys_umount2(const char *path, int flags) | |
1751 | { | |
1752 | return my_syscall2(__NR_umount2, path, flags); | |
1753 | } | |
1754 | ||
1755 | static __attribute__((unused)) | |
1756 | int sys_unlink(const char *path) | |
1757 | { | |
1758 | #ifdef __NR_unlinkat | |
1759 | return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); | |
1760 | #else | |
1761 | return my_syscall1(__NR_unlink, path); | |
1762 | #endif | |
1763 | } | |
1764 | ||
1765 | static __attribute__((unused)) | |
1766 | pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) | |
1767 | { | |
1768 | return my_syscall4(__NR_wait4, pid, status, options, rusage); | |
1769 | } | |
1770 | ||
1771 | static __attribute__((unused)) | |
1772 | pid_t sys_waitpid(pid_t pid, int *status, int options) | |
1773 | { | |
1774 | return sys_wait4(pid, status, options, 0); | |
1775 | } | |
1776 | ||
1777 | static __attribute__((unused)) | |
1778 | pid_t sys_wait(int *status) | |
1779 | { | |
1780 | return sys_waitpid(-1, status, 0); | |
1781 | } | |
1782 | ||
1783 | static __attribute__((unused)) | |
1784 | ssize_t sys_write(int fd, const void *buf, size_t count) | |
1785 | { | |
1786 | return my_syscall3(__NR_write, fd, buf, count); | |
1787 | } | |
1788 | ||
1789 | ||
1790 | /* Below are the libc-compatible syscalls which return x or -1 and set errno. | |
1791 | * They rely on the functions above. Similarly they're marked static so that it | |
1792 | * is possible to assign pointers to them if needed. | |
1793 | */ | |
1794 | ||
1795 | static __attribute__((unused)) | |
1796 | int brk(void *addr) | |
1797 | { | |
1798 | void *ret = sys_brk(addr); | |
1799 | ||
1800 | if (!ret) { | |
1801 | SET_ERRNO(ENOMEM); | |
1802 | return -1; | |
1803 | } | |
1804 | return 0; | |
1805 | } | |
1806 | ||
1807 | static __attribute__((noreturn,unused)) | |
1808 | void exit(int status) | |
1809 | { | |
1810 | sys_exit(status); | |
1811 | } | |
1812 | ||
1813 | static __attribute__((unused)) | |
1814 | int chdir(const char *path) | |
1815 | { | |
1816 | int ret = sys_chdir(path); | |
1817 | ||
1818 | if (ret < 0) { | |
1819 | SET_ERRNO(-ret); | |
1820 | ret = -1; | |
1821 | } | |
1822 | return ret; | |
1823 | } | |
1824 | ||
1825 | static __attribute__((unused)) | |
1826 | int chmod(const char *path, mode_t mode) | |
1827 | { | |
1828 | int ret = sys_chmod(path, mode); | |
1829 | ||
1830 | if (ret < 0) { | |
1831 | SET_ERRNO(-ret); | |
1832 | ret = -1; | |
1833 | } | |
1834 | return ret; | |
1835 | } | |
1836 | ||
1837 | static __attribute__((unused)) | |
1838 | int chown(const char *path, uid_t owner, gid_t group) | |
1839 | { | |
1840 | int ret = sys_chown(path, owner, group); | |
1841 | ||
1842 | if (ret < 0) { | |
1843 | SET_ERRNO(-ret); | |
1844 | ret = -1; | |
1845 | } | |
1846 | return ret; | |
1847 | } | |
1848 | ||
1849 | static __attribute__((unused)) | |
1850 | int chroot(const char *path) | |
1851 | { | |
1852 | int ret = sys_chroot(path); | |
1853 | ||
1854 | if (ret < 0) { | |
1855 | SET_ERRNO(-ret); | |
1856 | ret = -1; | |
1857 | } | |
1858 | return ret; | |
1859 | } | |
1860 | ||
1861 | static __attribute__((unused)) | |
1862 | int close(int fd) | |
1863 | { | |
1864 | int ret = sys_close(fd); | |
1865 | ||
1866 | if (ret < 0) { | |
1867 | SET_ERRNO(-ret); | |
1868 | ret = -1; | |
1869 | } | |
1870 | return ret; | |
1871 | } | |
1872 | ||
c261145a WT |
1873 | static __attribute__((unused)) |
1874 | int dup(int fd) | |
1875 | { | |
1876 | int ret = sys_dup(fd); | |
1877 | ||
1878 | if (ret < 0) { | |
1879 | SET_ERRNO(-ret); | |
1880 | ret = -1; | |
1881 | } | |
1882 | return ret; | |
1883 | } | |
1884 | ||
66b6f755 WT |
1885 | static __attribute__((unused)) |
1886 | int dup2(int old, int new) | |
1887 | { | |
1888 | int ret = sys_dup2(old, new); | |
1889 | ||
1890 | if (ret < 0) { | |
1891 | SET_ERRNO(-ret); | |
1892 | ret = -1; | |
1893 | } | |
1894 | return ret; | |
1895 | } | |
1896 | ||
79f220e5 WT |
1897 | #ifdef __NR_dup3 |
1898 | static __attribute__((unused)) | |
1899 | int dup3(int old, int new, int flags) | |
1900 | { | |
1901 | int ret = sys_dup3(old, new, flags); | |
1902 | ||
1903 | if (ret < 0) { | |
1904 | SET_ERRNO(-ret); | |
1905 | ret = -1; | |
1906 | } | |
1907 | return ret; | |
1908 | } | |
1909 | #endif | |
1910 | ||
66b6f755 WT |
1911 | static __attribute__((unused)) |
1912 | int execve(const char *filename, char *const argv[], char *const envp[]) | |
1913 | { | |
1914 | int ret = sys_execve(filename, argv, envp); | |
1915 | ||
1916 | if (ret < 0) { | |
1917 | SET_ERRNO(-ret); | |
1918 | ret = -1; | |
1919 | } | |
1920 | return ret; | |
1921 | } | |
1922 | ||
1923 | static __attribute__((unused)) | |
1924 | pid_t fork(void) | |
1925 | { | |
1926 | pid_t ret = sys_fork(); | |
1927 | ||
1928 | if (ret < 0) { | |
1929 | SET_ERRNO(-ret); | |
1930 | ret = -1; | |
1931 | } | |
1932 | return ret; | |
1933 | } | |
1934 | ||
1935 | static __attribute__((unused)) | |
1936 | int fsync(int fd) | |
1937 | { | |
1938 | int ret = sys_fsync(fd); | |
1939 | ||
1940 | if (ret < 0) { | |
1941 | SET_ERRNO(-ret); | |
1942 | ret = -1; | |
1943 | } | |
1944 | return ret; | |
1945 | } | |
1946 | ||
1947 | static __attribute__((unused)) | |
1948 | int getdents64(int fd, struct linux_dirent64 *dirp, int count) | |
1949 | { | |
1950 | int ret = sys_getdents64(fd, dirp, count); | |
1951 | ||
1952 | if (ret < 0) { | |
1953 | SET_ERRNO(-ret); | |
1954 | ret = -1; | |
1955 | } | |
1956 | return ret; | |
1957 | } | |
1958 | ||
c0c7c103 WT |
1959 | static __attribute__((unused)) |
1960 | pid_t getpgid(pid_t pid) | |
1961 | { | |
1962 | pid_t ret = sys_getpgid(pid); | |
1963 | ||
1964 | if (ret < 0) { | |
1965 | SET_ERRNO(-ret); | |
1966 | ret = -1; | |
1967 | } | |
1968 | return ret; | |
1969 | } | |
1970 | ||
66b6f755 WT |
1971 | static __attribute__((unused)) |
1972 | pid_t getpgrp(void) | |
1973 | { | |
1974 | pid_t ret = sys_getpgrp(); | |
1975 | ||
1976 | if (ret < 0) { | |
1977 | SET_ERRNO(-ret); | |
1978 | ret = -1; | |
1979 | } | |
1980 | return ret; | |
1981 | } | |
1982 | ||
1983 | static __attribute__((unused)) | |
1984 | pid_t getpid(void) | |
1985 | { | |
1986 | pid_t ret = sys_getpid(); | |
1987 | ||
1988 | if (ret < 0) { | |
1989 | SET_ERRNO(-ret); | |
1990 | ret = -1; | |
1991 | } | |
1992 | return ret; | |
1993 | } | |
1994 | ||
1995 | static __attribute__((unused)) | |
1996 | int gettimeofday(struct timeval *tv, struct timezone *tz) | |
1997 | { | |
1998 | int ret = sys_gettimeofday(tv, tz); | |
1999 | ||
2000 | if (ret < 0) { | |
2001 | SET_ERRNO(-ret); | |
2002 | ret = -1; | |
2003 | } | |
2004 | return ret; | |
2005 | } | |
2006 | ||
2007 | static __attribute__((unused)) | |
2008 | int ioctl(int fd, unsigned long req, void *value) | |
2009 | { | |
2010 | int ret = sys_ioctl(fd, req, value); | |
2011 | ||
2012 | if (ret < 0) { | |
2013 | SET_ERRNO(-ret); | |
2014 | ret = -1; | |
2015 | } | |
2016 | return ret; | |
2017 | } | |
2018 | ||
2019 | static __attribute__((unused)) | |
2020 | int kill(pid_t pid, int signal) | |
2021 | { | |
2022 | int ret = sys_kill(pid, signal); | |
2023 | ||
2024 | if (ret < 0) { | |
2025 | SET_ERRNO(-ret); | |
2026 | ret = -1; | |
2027 | } | |
2028 | return ret; | |
2029 | } | |
2030 | ||
2031 | static __attribute__((unused)) | |
2032 | int link(const char *old, const char *new) | |
2033 | { | |
2034 | int ret = sys_link(old, new); | |
2035 | ||
2036 | if (ret < 0) { | |
2037 | SET_ERRNO(-ret); | |
2038 | ret = -1; | |
2039 | } | |
2040 | return ret; | |
2041 | } | |
2042 | ||
2043 | static __attribute__((unused)) | |
2044 | off_t lseek(int fd, off_t offset, int whence) | |
2045 | { | |
2046 | off_t ret = sys_lseek(fd, offset, whence); | |
2047 | ||
2048 | if (ret < 0) { | |
2049 | SET_ERRNO(-ret); | |
2050 | ret = -1; | |
2051 | } | |
2052 | return ret; | |
2053 | } | |
2054 | ||
2055 | static __attribute__((unused)) | |
2056 | int mkdir(const char *path, mode_t mode) | |
2057 | { | |
2058 | int ret = sys_mkdir(path, mode); | |
2059 | ||
2060 | if (ret < 0) { | |
2061 | SET_ERRNO(-ret); | |
2062 | ret = -1; | |
2063 | } | |
2064 | return ret; | |
2065 | } | |
2066 | ||
2067 | static __attribute__((unused)) | |
2068 | int mknod(const char *path, mode_t mode, dev_t dev) | |
2069 | { | |
2070 | int ret = sys_mknod(path, mode, dev); | |
2071 | ||
2072 | if (ret < 0) { | |
2073 | SET_ERRNO(-ret); | |
2074 | ret = -1; | |
2075 | } | |
2076 | return ret; | |
2077 | } | |
2078 | ||
2079 | static __attribute__((unused)) | |
2080 | int mount(const char *src, const char *tgt, | |
2081 | const char *fst, unsigned long flags, | |
2082 | const void *data) | |
2083 | { | |
2084 | int ret = sys_mount(src, tgt, fst, flags, data); | |
2085 | ||
2086 | if (ret < 0) { | |
2087 | SET_ERRNO(-ret); | |
2088 | ret = -1; | |
2089 | } | |
2090 | return ret; | |
2091 | } | |
2092 | ||
2093 | static __attribute__((unused)) | |
2094 | int open(const char *path, int flags, mode_t mode) | |
2095 | { | |
2096 | int ret = sys_open(path, flags, mode); | |
2097 | ||
2098 | if (ret < 0) { | |
2099 | SET_ERRNO(-ret); | |
2100 | ret = -1; | |
2101 | } | |
2102 | return ret; | |
2103 | } | |
2104 | ||
2105 | static __attribute__((unused)) | |
2106 | int pivot_root(const char *new, const char *old) | |
2107 | { | |
2108 | int ret = sys_pivot_root(new, old); | |
2109 | ||
2110 | if (ret < 0) { | |
2111 | SET_ERRNO(-ret); | |
2112 | ret = -1; | |
2113 | } | |
2114 | return ret; | |
2115 | } | |
2116 | ||
2117 | static __attribute__((unused)) | |
2118 | int poll(struct pollfd *fds, int nfds, int timeout) | |
2119 | { | |
2120 | int ret = sys_poll(fds, nfds, timeout); | |
2121 | ||
2122 | if (ret < 0) { | |
2123 | SET_ERRNO(-ret); | |
2124 | ret = -1; | |
2125 | } | |
2126 | return ret; | |
2127 | } | |
2128 | ||
2129 | static __attribute__((unused)) | |
2130 | ssize_t read(int fd, void *buf, size_t count) | |
2131 | { | |
2132 | ssize_t ret = sys_read(fd, buf, count); | |
2133 | ||
2134 | if (ret < 0) { | |
2135 | SET_ERRNO(-ret); | |
2136 | ret = -1; | |
2137 | } | |
2138 | return ret; | |
2139 | } | |
2140 | ||
2141 | static __attribute__((unused)) | |
2142 | int reboot(int cmd) | |
2143 | { | |
2144 | int ret = sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0); | |
2145 | ||
2146 | if (ret < 0) { | |
2147 | SET_ERRNO(-ret); | |
2148 | ret = -1; | |
2149 | } | |
2150 | return ret; | |
2151 | } | |
2152 | ||
2153 | static __attribute__((unused)) | |
2154 | void *sbrk(intptr_t inc) | |
2155 | { | |
2156 | void *ret; | |
2157 | ||
2158 | /* first call to find current end */ | |
2159 | if ((ret = sys_brk(0)) && (sys_brk(ret + inc) == ret + inc)) | |
2160 | return ret + inc; | |
2161 | ||
2162 | SET_ERRNO(ENOMEM); | |
2163 | return (void *)-1; | |
2164 | } | |
2165 | ||
2166 | static __attribute__((unused)) | |
2167 | int sched_yield(void) | |
2168 | { | |
2169 | int ret = sys_sched_yield(); | |
2170 | ||
2171 | if (ret < 0) { | |
2172 | SET_ERRNO(-ret); | |
2173 | ret = -1; | |
2174 | } | |
2175 | return ret; | |
2176 | } | |
2177 | ||
2178 | static __attribute__((unused)) | |
2179 | int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) | |
2180 | { | |
2181 | int ret = sys_select(nfds, rfds, wfds, efds, timeout); | |
2182 | ||
2183 | if (ret < 0) { | |
2184 | SET_ERRNO(-ret); | |
2185 | ret = -1; | |
2186 | } | |
2187 | return ret; | |
2188 | } | |
2189 | ||
2190 | static __attribute__((unused)) | |
2191 | int setpgid(pid_t pid, pid_t pgid) | |
2192 | { | |
2193 | int ret = sys_setpgid(pid, pgid); | |
2194 | ||
2195 | if (ret < 0) { | |
2196 | SET_ERRNO(-ret); | |
2197 | ret = -1; | |
2198 | } | |
2199 | return ret; | |
2200 | } | |
2201 | ||
2202 | static __attribute__((unused)) | |
2203 | pid_t setsid(void) | |
2204 | { | |
2205 | pid_t ret = sys_setsid(); | |
2206 | ||
2207 | if (ret < 0) { | |
2208 | SET_ERRNO(-ret); | |
2209 | ret = -1; | |
2210 | } | |
2211 | return ret; | |
2212 | } | |
2213 | ||
2214 | static __attribute__((unused)) | |
2215 | unsigned int sleep(unsigned int seconds) | |
2216 | { | |
2217 | struct timeval my_timeval = { seconds, 0 }; | |
2218 | ||
2219 | if (sys_select(0, 0, 0, 0, &my_timeval) < 0) | |
2220 | return my_timeval.tv_sec + !!my_timeval.tv_usec; | |
2221 | else | |
2222 | return 0; | |
2223 | } | |
2224 | ||
2225 | static __attribute__((unused)) | |
2226 | int stat(const char *path, struct stat *buf) | |
2227 | { | |
2228 | int ret = sys_stat(path, buf); | |
2229 | ||
2230 | if (ret < 0) { | |
2231 | SET_ERRNO(-ret); | |
2232 | ret = -1; | |
2233 | } | |
2234 | return ret; | |
2235 | } | |
2236 | ||
2237 | static __attribute__((unused)) | |
2238 | int symlink(const char *old, const char *new) | |
2239 | { | |
2240 | int ret = sys_symlink(old, new); | |
2241 | ||
2242 | if (ret < 0) { | |
2243 | SET_ERRNO(-ret); | |
2244 | ret = -1; | |
2245 | } | |
2246 | return ret; | |
2247 | } | |
2248 | ||
2249 | static __attribute__((unused)) | |
2250 | int tcsetpgrp(int fd, pid_t pid) | |
2251 | { | |
2252 | return ioctl(fd, TIOCSPGRP, &pid); | |
2253 | } | |
2254 | ||
2255 | static __attribute__((unused)) | |
2256 | mode_t umask(mode_t mode) | |
2257 | { | |
2258 | return sys_umask(mode); | |
2259 | } | |
2260 | ||
2261 | static __attribute__((unused)) | |
2262 | int umount2(const char *path, int flags) | |
2263 | { | |
2264 | int ret = sys_umount2(path, flags); | |
2265 | ||
2266 | if (ret < 0) { | |
2267 | SET_ERRNO(-ret); | |
2268 | ret = -1; | |
2269 | } | |
2270 | return ret; | |
2271 | } | |
2272 | ||
2273 | static __attribute__((unused)) | |
2274 | int unlink(const char *path) | |
2275 | { | |
2276 | int ret = sys_unlink(path); | |
2277 | ||
2278 | if (ret < 0) { | |
2279 | SET_ERRNO(-ret); | |
2280 | ret = -1; | |
2281 | } | |
2282 | return ret; | |
2283 | } | |
2284 | ||
2285 | static __attribute__((unused)) | |
2286 | pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) | |
2287 | { | |
2288 | pid_t ret = sys_wait4(pid, status, options, rusage); | |
2289 | ||
2290 | if (ret < 0) { | |
2291 | SET_ERRNO(-ret); | |
2292 | ret = -1; | |
2293 | } | |
2294 | return ret; | |
2295 | } | |
2296 | ||
2297 | static __attribute__((unused)) | |
2298 | pid_t waitpid(pid_t pid, int *status, int options) | |
2299 | { | |
2300 | pid_t ret = sys_waitpid(pid, status, options); | |
2301 | ||
2302 | if (ret < 0) { | |
2303 | SET_ERRNO(-ret); | |
2304 | ret = -1; | |
2305 | } | |
2306 | return ret; | |
2307 | } | |
2308 | ||
2309 | static __attribute__((unused)) | |
2310 | pid_t wait(int *status) | |
2311 | { | |
2312 | pid_t ret = sys_wait(status); | |
2313 | ||
2314 | if (ret < 0) { | |
2315 | SET_ERRNO(-ret); | |
2316 | ret = -1; | |
2317 | } | |
2318 | return ret; | |
2319 | } | |
2320 | ||
2321 | static __attribute__((unused)) | |
2322 | ssize_t write(int fd, const void *buf, size_t count) | |
2323 | { | |
2324 | ssize_t ret = sys_write(fd, buf, count); | |
2325 | ||
2326 | if (ret < 0) { | |
2327 | SET_ERRNO(-ret); | |
2328 | ret = -1; | |
2329 | } | |
2330 | return ret; | |
2331 | } | |
2332 | ||
2333 | /* some size-optimized reimplementations of a few common str* and mem* | |
2334 | * functions. They're marked static, except memcpy() and raise() which are used | |
2335 | * by libgcc on ARM, so they are marked weak instead in order not to cause an | |
2336 | * error when building a program made of multiple files (not recommended). | |
2337 | */ | |
2338 | ||
2339 | static __attribute__((unused)) | |
2340 | void *memmove(void *dst, const void *src, size_t len) | |
2341 | { | |
2342 | ssize_t pos = (dst <= src) ? -1 : (long)len; | |
2343 | void *ret = dst; | |
2344 | ||
2345 | while (len--) { | |
2346 | pos += (dst <= src) ? 1 : -1; | |
2347 | ((char *)dst)[pos] = ((char *)src)[pos]; | |
2348 | } | |
2349 | return ret; | |
2350 | } | |
2351 | ||
2352 | static __attribute__((unused)) | |
2353 | void *memset(void *dst, int b, size_t len) | |
2354 | { | |
2355 | char *p = dst; | |
2356 | ||
2357 | while (len--) | |
2358 | *(p++) = b; | |
2359 | return dst; | |
2360 | } | |
2361 | ||
2362 | static __attribute__((unused)) | |
2363 | int memcmp(const void *s1, const void *s2, size_t n) | |
2364 | { | |
2365 | size_t ofs = 0; | |
2366 | char c1 = 0; | |
2367 | ||
2368 | while (ofs < n && !(c1 = ((char *)s1)[ofs] - ((char *)s2)[ofs])) { | |
2369 | ofs++; | |
2370 | } | |
2371 | return c1; | |
2372 | } | |
2373 | ||
2374 | static __attribute__((unused)) | |
2375 | char *strcpy(char *dst, const char *src) | |
2376 | { | |
2377 | char *ret = dst; | |
2378 | ||
2379 | while ((*dst++ = *src++)); | |
2380 | return ret; | |
2381 | } | |
2382 | ||
2383 | static __attribute__((unused)) | |
2384 | char *strchr(const char *s, int c) | |
2385 | { | |
2386 | while (*s) { | |
2387 | if (*s == (char)c) | |
2388 | return (char *)s; | |
2389 | s++; | |
2390 | } | |
2391 | return NULL; | |
2392 | } | |
2393 | ||
2394 | static __attribute__((unused)) | |
2395 | char *strrchr(const char *s, int c) | |
2396 | { | |
2397 | const char *ret = NULL; | |
2398 | ||
2399 | while (*s) { | |
2400 | if (*s == (char)c) | |
2401 | ret = s; | |
2402 | s++; | |
2403 | } | |
2404 | return (char *)ret; | |
2405 | } | |
2406 | ||
2407 | static __attribute__((unused)) | |
2408 | size_t nolibc_strlen(const char *str) | |
2409 | { | |
2410 | size_t len; | |
2411 | ||
2412 | for (len = 0; str[len]; len++); | |
2413 | return len; | |
2414 | } | |
2415 | ||
2416 | #define strlen(str) ({ \ | |
2417 | __builtin_constant_p((str)) ? \ | |
2418 | __builtin_strlen((str)) : \ | |
2419 | nolibc_strlen((str)); \ | |
2420 | }) | |
2421 | ||
2422 | static __attribute__((unused)) | |
2423 | int isdigit(int c) | |
2424 | { | |
2425 | return (unsigned int)(c - '0') <= 9; | |
2426 | } | |
2427 | ||
2428 | static __attribute__((unused)) | |
2429 | long atol(const char *s) | |
2430 | { | |
2431 | unsigned long ret = 0; | |
2432 | unsigned long d; | |
2433 | int neg = 0; | |
2434 | ||
2435 | if (*s == '-') { | |
2436 | neg = 1; | |
2437 | s++; | |
2438 | } | |
2439 | ||
2440 | while (1) { | |
2441 | d = (*s++) - '0'; | |
2442 | if (d > 9) | |
2443 | break; | |
2444 | ret *= 10; | |
2445 | ret += d; | |
2446 | } | |
2447 | ||
2448 | return neg ? -ret : ret; | |
2449 | } | |
2450 | ||
2451 | static __attribute__((unused)) | |
2452 | int atoi(const char *s) | |
2453 | { | |
2454 | return atol(s); | |
2455 | } | |
2456 | ||
2457 | static __attribute__((unused)) | |
2458 | const char *ltoa(long in) | |
2459 | { | |
2460 | /* large enough for -9223372036854775808 */ | |
2461 | static char buffer[21]; | |
2462 | char *pos = buffer + sizeof(buffer) - 1; | |
2463 | int neg = in < 0; | |
2464 | unsigned long n = neg ? -in : in; | |
2465 | ||
2466 | *pos-- = '\0'; | |
2467 | do { | |
2468 | *pos-- = '0' + n % 10; | |
2469 | n /= 10; | |
2470 | if (pos < buffer) | |
2471 | return pos + 1; | |
2472 | } while (n); | |
2473 | ||
2474 | if (neg) | |
2475 | *pos-- = '-'; | |
2476 | return pos + 1; | |
2477 | } | |
2478 | ||
2479 | __attribute__((weak,unused)) | |
2480 | void *memcpy(void *dst, const void *src, size_t len) | |
2481 | { | |
2482 | return memmove(dst, src, len); | |
2483 | } | |
2484 | ||
2485 | /* needed by libgcc for divide by zero */ | |
2486 | __attribute__((weak,unused)) | |
2487 | int raise(int signal) | |
2488 | { | |
2489 | return kill(getpid(), signal); | |
2490 | } | |
2491 | ||
2492 | /* Here come a few helper functions */ | |
2493 | ||
2494 | static __attribute__((unused)) | |
2495 | void FD_ZERO(fd_set *set) | |
2496 | { | |
2497 | memset(set, 0, sizeof(*set)); | |
2498 | } | |
2499 | ||
2500 | static __attribute__((unused)) | |
2501 | void FD_SET(int fd, fd_set *set) | |
2502 | { | |
2503 | if (fd < 0 || fd >= FD_SETSIZE) | |
2504 | return; | |
2505 | set->fd32[fd / 32] |= 1 << (fd & 31); | |
2506 | } | |
2507 | ||
2508 | /* WARNING, it only deals with the 4096 first majors and 256 first minors */ | |
2509 | static __attribute__((unused)) | |
2510 | dev_t makedev(unsigned int major, unsigned int minor) | |
2511 | { | |
2512 | return ((major & 0xfff) << 8) | (minor & 0xff); | |
2513 | } |