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