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