|  | /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ | 
|  | /* nolibc.h | 
|  | * Copyright (C) 2017-2018 Willy Tarreau <w@1wt.eu> | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * This file is designed to be used as a libc alternative for minimal programs | 
|  | * with very limited requirements. It consists of a small number of syscall and | 
|  | * type definitions, and the minimal startup code needed to call main(). | 
|  | * All syscalls are declared as static functions so that they can be optimized | 
|  | * away by the compiler when not used. | 
|  | * | 
|  | * Syscalls are split into 3 levels: | 
|  | *   - The lower level is the arch-specific syscall() definition, consisting in | 
|  | *     assembly code in compound expressions. These are called my_syscall0() to | 
|  | *     my_syscall6() depending on the number of arguments. The MIPS | 
|  | *     implementation is limited to 5 arguments. All input arguments are cast | 
|  | *     to a long stored in a register. These expressions always return the | 
|  | *     syscall's return value as a signed long value which is often either a | 
|  | *     pointer or the negated errno value. | 
|  | * | 
|  | *   - The second level is mostly architecture-independent. It is made of | 
|  | *     static functions called sys_<name>() which rely on my_syscallN() | 
|  | *     depending on the syscall definition. These functions are responsible | 
|  | *     for exposing the appropriate types for the syscall arguments (int, | 
|  | *     pointers, etc) and for setting the appropriate return type (often int). | 
|  | *     A few of them are architecture-specific because the syscalls are not all | 
|  | *     mapped exactly the same among architectures. For example, some archs do | 
|  | *     not implement select() and need pselect6() instead, so the sys_select() | 
|  | *     function will have to abstract this. | 
|  | * | 
|  | *   - The third level is the libc call definition. It exposes the lower raw | 
|  | *     sys_<name>() calls in a way that looks like what a libc usually does, | 
|  | *     takes care of specific input values, and of setting errno upon error. | 
|  | *     There can be minor variations compared to standard libc calls. For | 
|  | *     example the open() call always takes 3 args here. | 
|  | * | 
|  | * The errno variable is declared static and unused. This way it can be | 
|  | * optimized away if not used. However this means that a program made of | 
|  | * multiple C files may observe different errno values (one per C file). For | 
|  | * the type of programs this project targets it usually is not a problem. The | 
|  | * resulting program may even be reduced by defining the NOLIBC_IGNORE_ERRNO | 
|  | * macro, in which case the errno value will never be assigned. | 
|  | * | 
|  | * Some stdint-like integer types are defined. These are valid on all currently | 
|  | * supported architectures, because signs are enforced, ints are assumed to be | 
|  | * 32 bits, longs the size of a pointer and long long 64 bits. If more | 
|  | * architectures have to be supported, this may need to be adapted. | 
|  | * | 
|  | * Some macro definitions like the O_* values passed to open(), and some | 
|  | * structures like the sys_stat struct depend on the architecture. | 
|  | * | 
|  | * The definitions start with the architecture-specific parts, which are picked | 
|  | * based on what the compiler knows about the target architecture, and are | 
|  | * completed with the generic code. Since it is the compiler which sets the | 
|  | * target architecture, cross-compiling normally works out of the box without | 
|  | * having to specify anything. | 
|  | * | 
|  | * Finally some very common libc-level functions are provided. It is the case | 
|  | * for a few functions usually found in string.h, ctype.h, or stdlib.h. Nothing | 
|  | * is currently provided regarding stdio emulation. | 
|  | * | 
|  | * The macro NOLIBC is always defined, so that it is possible for a program to | 
|  | * check this macro to know if it is being built against and decide to disable | 
|  | * some features or simply not to include some standard libc files. | 
|  | * | 
|  | * Ideally this file should be split in multiple files for easier long term | 
|  | * maintenance, but provided as a single file as it is now, it's quite | 
|  | * convenient to use. Maybe some variations involving a set of includes at the | 
|  | * top could work. | 
|  | * | 
|  | * A simple static executable may be built this way : | 
|  | *      $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \ | 
|  | *            -static -include nolibc.h -lgcc -o hello hello.c | 
|  | * | 
|  | * A very useful calling convention table may be found here : | 
|  | *      http://man7.org/linux/man-pages/man2/syscall.2.html | 
|  | * | 
|  | * This doc is quite convenient though not necessarily up to date : | 
|  | *      https://w3challs.com/syscalls/ | 
|  | * | 
|  | */ | 
|  |  | 
|  | /* Some archs (at least aarch64) don't expose the regular syscalls anymore by | 
|  | * default, either because they have an "_at" replacement, or because there are | 
|  | * more modern alternatives. For now we'd rather still use them. | 
|  | */ | 
|  | #define __ARCH_WANT_SYSCALL_NO_AT | 
|  | #define __ARCH_WANT_SYSCALL_NO_FLAGS | 
|  | #define __ARCH_WANT_SYSCALL_DEPRECATED | 
|  |  | 
|  | #include <asm/unistd.h> | 
|  | #include <asm/ioctls.h> | 
|  | #include <asm/errno.h> | 
|  | #include <linux/fs.h> | 
|  | #include <linux/loop.h> | 
|  |  | 
|  | #define NOLIBC | 
|  |  | 
|  | /* this way it will be removed if unused */ | 
|  | static int errno; | 
|  |  | 
|  | #ifndef NOLIBC_IGNORE_ERRNO | 
|  | #define SET_ERRNO(v) do { errno = (v); } while (0) | 
|  | #else | 
|  | #define SET_ERRNO(v) do { } while (0) | 
|  | #endif | 
|  |  | 
|  | /* errno codes all ensure that they will not conflict with a valid pointer | 
|  | * because they all correspond to the highest addressable memry page. | 
|  | */ | 
|  | #define MAX_ERRNO 4095 | 
|  |  | 
|  | /* Declare a few quite common macros and types that usually are in stdlib.h, | 
|  | * stdint.h, ctype.h, unistd.h and a few other common locations. | 
|  | */ | 
|  |  | 
|  | #define NULL ((void *)0) | 
|  |  | 
|  | /* stdint types */ | 
|  | typedef unsigned char       uint8_t; | 
|  | typedef   signed char        int8_t; | 
|  | typedef unsigned short     uint16_t; | 
|  | typedef   signed short      int16_t; | 
|  | typedef unsigned int       uint32_t; | 
|  | typedef   signed int        int32_t; | 
|  | typedef unsigned long long uint64_t; | 
|  | typedef   signed long long  int64_t; | 
|  | typedef unsigned long        size_t; | 
|  | typedef   signed long       ssize_t; | 
|  | typedef unsigned long     uintptr_t; | 
|  | typedef   signed long      intptr_t; | 
|  | typedef   signed long     ptrdiff_t; | 
|  |  | 
|  | /* for stat() */ | 
|  | typedef unsigned int          dev_t; | 
|  | typedef unsigned long         ino_t; | 
|  | typedef unsigned int         mode_t; | 
|  | typedef   signed int          pid_t; | 
|  | typedef unsigned int          uid_t; | 
|  | typedef unsigned int          gid_t; | 
|  | typedef unsigned long       nlink_t; | 
|  | typedef   signed long         off_t; | 
|  | typedef   signed long     blksize_t; | 
|  | typedef   signed long      blkcnt_t; | 
|  | typedef   signed long        time_t; | 
|  |  | 
|  | /* for poll() */ | 
|  | struct pollfd { | 
|  | int fd; | 
|  | short int events; | 
|  | short int revents; | 
|  | }; | 
|  |  | 
|  | /* for select() */ | 
|  | struct timeval { | 
|  | long    tv_sec; | 
|  | long    tv_usec; | 
|  | }; | 
|  |  | 
|  | /* for pselect() */ | 
|  | struct timespec { | 
|  | long    tv_sec; | 
|  | long    tv_nsec; | 
|  | }; | 
|  |  | 
|  | /* for gettimeofday() */ | 
|  | struct timezone { | 
|  | int tz_minuteswest; | 
|  | int tz_dsttime; | 
|  | }; | 
|  |  | 
|  | /* for getdents64() */ | 
|  | struct linux_dirent64 { | 
|  | uint64_t       d_ino; | 
|  | int64_t        d_off; | 
|  | unsigned short d_reclen; | 
|  | unsigned char  d_type; | 
|  | char           d_name[]; | 
|  | }; | 
|  |  | 
|  | /* commonly an fd_set represents 256 FDs */ | 
|  | #define FD_SETSIZE 256 | 
|  | typedef struct { uint32_t fd32[FD_SETSIZE/32]; } fd_set; | 
|  |  | 
|  | /* needed by wait4() */ | 
|  | struct rusage { | 
|  | struct timeval ru_utime; | 
|  | struct timeval ru_stime; | 
|  | long   ru_maxrss; | 
|  | long   ru_ixrss; | 
|  | long   ru_idrss; | 
|  | long   ru_isrss; | 
|  | long   ru_minflt; | 
|  | long   ru_majflt; | 
|  | long   ru_nswap; | 
|  | long   ru_inblock; | 
|  | long   ru_oublock; | 
|  | long   ru_msgsnd; | 
|  | long   ru_msgrcv; | 
|  | long   ru_nsignals; | 
|  | long   ru_nvcsw; | 
|  | long   ru_nivcsw; | 
|  | }; | 
|  |  | 
|  | /* stat flags (WARNING, octal here) */ | 
|  | #define S_IFDIR       0040000 | 
|  | #define S_IFCHR       0020000 | 
|  | #define S_IFBLK       0060000 | 
|  | #define S_IFREG       0100000 | 
|  | #define S_IFIFO       0010000 | 
|  | #define S_IFLNK       0120000 | 
|  | #define S_IFSOCK      0140000 | 
|  | #define S_IFMT        0170000 | 
|  |  | 
|  | #define S_ISDIR(mode)  (((mode) & S_IFDIR) == S_IFDIR) | 
|  | #define S_ISCHR(mode)  (((mode) & S_IFCHR) == S_IFCHR) | 
|  | #define S_ISBLK(mode)  (((mode) & S_IFBLK) == S_IFBLK) | 
|  | #define S_ISREG(mode)  (((mode) & S_IFREG) == S_IFREG) | 
|  | #define S_ISFIFO(mode) (((mode) & S_IFIFO) == S_IFIFO) | 
|  | #define S_ISLNK(mode)  (((mode) & S_IFLNK) == S_IFLNK) | 
|  | #define S_ISSOCK(mode) (((mode) & S_IFSOCK) == S_IFSOCK) | 
|  |  | 
|  | #define DT_UNKNOWN 0 | 
|  | #define DT_FIFO    1 | 
|  | #define DT_CHR     2 | 
|  | #define DT_DIR     4 | 
|  | #define DT_BLK     6 | 
|  | #define DT_REG     8 | 
|  | #define DT_LNK    10 | 
|  | #define DT_SOCK   12 | 
|  |  | 
|  | /* all the *at functions */ | 
|  | #ifndef AT_FDWCD | 
|  | #define AT_FDCWD             -100 | 
|  | #endif | 
|  |  | 
|  | /* lseek */ | 
|  | #define SEEK_SET        0 | 
|  | #define SEEK_CUR        1 | 
|  | #define SEEK_END        2 | 
|  |  | 
|  | /* reboot */ | 
|  | #define LINUX_REBOOT_MAGIC1         0xfee1dead | 
|  | #define LINUX_REBOOT_MAGIC2         0x28121969 | 
|  | #define LINUX_REBOOT_CMD_HALT       0xcdef0123 | 
|  | #define LINUX_REBOOT_CMD_POWER_OFF  0x4321fedc | 
|  | #define LINUX_REBOOT_CMD_RESTART    0x01234567 | 
|  | #define LINUX_REBOOT_CMD_SW_SUSPEND 0xd000fce2 | 
|  |  | 
|  |  | 
|  | /* The format of the struct as returned by the libc to the application, which | 
|  | * significantly differs from the format returned by the stat() syscall flavours. | 
|  | */ | 
|  | struct stat { | 
|  | dev_t     st_dev;     /* ID of device containing file */ | 
|  | ino_t     st_ino;     /* inode number */ | 
|  | mode_t    st_mode;    /* protection */ | 
|  | nlink_t   st_nlink;   /* number of hard links */ | 
|  | uid_t     st_uid;     /* user ID of owner */ | 
|  | gid_t     st_gid;     /* group ID of owner */ | 
|  | dev_t     st_rdev;    /* device ID (if special file) */ | 
|  | off_t     st_size;    /* total size, in bytes */ | 
|  | blksize_t st_blksize; /* blocksize for file system I/O */ | 
|  | blkcnt_t  st_blocks;  /* number of 512B blocks allocated */ | 
|  | time_t    st_atime;   /* time of last access */ | 
|  | time_t    st_mtime;   /* time of last modification */ | 
|  | time_t    st_ctime;   /* time of last status change */ | 
|  | }; | 
|  |  | 
|  | #define WEXITSTATUS(status)   (((status) & 0xff00) >> 8) | 
|  | #define WIFEXITED(status)     (((status) & 0x7f) == 0) | 
|  |  | 
|  |  | 
|  | /* Below comes the architecture-specific code. For each architecture, we have | 
|  | * the syscall declarations and the _start code definition. This is the only | 
|  | * global part. On all architectures the kernel puts everything in the stack | 
|  | * before jumping to _start just above us, without any return address (_start | 
|  | * is not a function but an entry pint). So at the stack pointer we find argc. | 
|  | * Then argv[] begins, and ends at the first NULL. Then we have envp which | 
|  | * starts and ends with a NULL as well. So envp=argv+argc+1. | 
|  | */ | 
|  |  | 
|  | #if defined(__x86_64__) | 
|  | /* Syscalls for x86_64 : | 
|  | *   - registers are 64-bit | 
|  | *   - syscall number is passed in rax | 
|  | *   - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively | 
|  | *   - the system call is performed by calling the syscall instruction | 
|  | *   - syscall return comes in rax | 
|  | *   - rcx and r8..r11 may be clobbered, others are preserved. | 
|  | *   - the arguments are cast to long and assigned into the target registers | 
|  | *     which are then simply passed as registers to the asm code, so that we | 
|  | *     don't have to experience issues with register constraints. | 
|  | *   - the syscall number is always specified last in order to allow to force | 
|  | *     some registers before (gcc refuses a %-register at the last position). | 
|  | */ | 
|  |  | 
|  | #define my_syscall0(num)                                                      \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num  asm("rax") = (num);                               \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "syscall\n"                                                   \ | 
|  | : "=a" (_ret)                                                 \ | 
|  | : "0"(_num)                                                   \ | 
|  | : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"             \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall1(num, arg1)                                                \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num  asm("rax") = (num);                               \ | 
|  | register long _arg1 asm("rdi") = (long)(arg1);                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "syscall\n"                                                   \ | 
|  | : "=a" (_ret)                                                 \ | 
|  | : "r"(_arg1),                                                 \ | 
|  | "0"(_num)                                                   \ | 
|  | : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"             \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall2(num, arg1, arg2)                                          \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num  asm("rax") = (num);                               \ | 
|  | register long _arg1 asm("rdi") = (long)(arg1);                        \ | 
|  | register long _arg2 asm("rsi") = (long)(arg2);                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "syscall\n"                                                   \ | 
|  | : "=a" (_ret)                                                 \ | 
|  | : "r"(_arg1), "r"(_arg2),                                     \ | 
|  | "0"(_num)                                                   \ | 
|  | : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"             \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall3(num, arg1, arg2, arg3)                                    \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num  asm("rax") = (num);                               \ | 
|  | register long _arg1 asm("rdi") = (long)(arg1);                        \ | 
|  | register long _arg2 asm("rsi") = (long)(arg2);                        \ | 
|  | register long _arg3 asm("rdx") = (long)(arg3);                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "syscall\n"                                                   \ | 
|  | : "=a" (_ret)                                                 \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \ | 
|  | "0"(_num)                                                   \ | 
|  | : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"             \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num  asm("rax") = (num);                               \ | 
|  | register long _arg1 asm("rdi") = (long)(arg1);                        \ | 
|  | register long _arg2 asm("rsi") = (long)(arg2);                        \ | 
|  | register long _arg3 asm("rdx") = (long)(arg3);                        \ | 
|  | register long _arg4 asm("r10") = (long)(arg4);                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "syscall\n"                                                   \ | 
|  | : "=a" (_ret), "=r"(_arg4)                                    \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \ | 
|  | "0"(_num)                                                   \ | 
|  | : "rcx", "r8", "r9", "r11", "memory", "cc"                    \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num  asm("rax") = (num);                               \ | 
|  | register long _arg1 asm("rdi") = (long)(arg1);                        \ | 
|  | register long _arg2 asm("rsi") = (long)(arg2);                        \ | 
|  | register long _arg3 asm("rdx") = (long)(arg3);                        \ | 
|  | register long _arg4 asm("r10") = (long)(arg4);                        \ | 
|  | register long _arg5 asm("r8")  = (long)(arg5);                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "syscall\n"                                                   \ | 
|  | : "=a" (_ret), "=r"(_arg4), "=r"(_arg5)                       \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | 
|  | "0"(_num)                                                   \ | 
|  | : "rcx", "r9", "r11", "memory", "cc"                          \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num  asm("rax") = (num);                               \ | 
|  | register long _arg1 asm("rdi") = (long)(arg1);                        \ | 
|  | register long _arg2 asm("rsi") = (long)(arg2);                        \ | 
|  | register long _arg3 asm("rdx") = (long)(arg3);                        \ | 
|  | register long _arg4 asm("r10") = (long)(arg4);                        \ | 
|  | register long _arg5 asm("r8")  = (long)(arg5);                        \ | 
|  | register long _arg6 asm("r9")  = (long)(arg6);                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "syscall\n"                                                   \ | 
|  | : "=a" (_ret), "=r"(_arg4), "=r"(_arg5)                       \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | 
|  | "r"(_arg6), "0"(_num)                                       \ | 
|  | : "rcx", "r11", "memory", "cc"                                \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | /* startup code */ | 
|  | asm(".section .text\n" | 
|  | ".global _start\n" | 
|  | "_start:\n" | 
|  | "pop %rdi\n"                // argc   (first arg, %rdi) | 
|  | "mov %rsp, %rsi\n"          // argv[] (second arg, %rsi) | 
|  | "lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx) | 
|  | "and $-16, %rsp\n"          // x86 ABI : esp must be 16-byte aligned when | 
|  | "sub $8, %rsp\n"            // entering the callee | 
|  | "call main\n"               // main() returns the status code, we'll exit with it. | 
|  | "movzb %al, %rdi\n"         // retrieve exit code from 8 lower bits | 
|  | "mov $60, %rax\n"           // NR_exit == 60 | 
|  | "syscall\n"                 // really exit | 
|  | "hlt\n"                     // ensure it does not return | 
|  | ""); | 
|  |  | 
|  | /* fcntl / open */ | 
|  | #define O_RDONLY            0 | 
|  | #define O_WRONLY            1 | 
|  | #define O_RDWR              2 | 
|  | #define O_CREAT          0x40 | 
|  | #define O_EXCL           0x80 | 
|  | #define O_NOCTTY        0x100 | 
|  | #define O_TRUNC         0x200 | 
|  | #define O_APPEND        0x400 | 
|  | #define O_NONBLOCK      0x800 | 
|  | #define O_DIRECTORY   0x10000 | 
|  |  | 
|  | /* The struct returned by the stat() syscall, equivalent to stat64(). The | 
|  | * syscall returns 116 bytes and stops in the middle of __unused. | 
|  | */ | 
|  | struct sys_stat_struct { | 
|  | unsigned long st_dev; | 
|  | unsigned long st_ino; | 
|  | unsigned long st_nlink; | 
|  | unsigned int  st_mode; | 
|  | unsigned int  st_uid; | 
|  |  | 
|  | unsigned int  st_gid; | 
|  | unsigned int  __pad0; | 
|  | unsigned long st_rdev; | 
|  | long          st_size; | 
|  | long          st_blksize; | 
|  |  | 
|  | long          st_blocks; | 
|  | unsigned long st_atime; | 
|  | unsigned long st_atime_nsec; | 
|  | unsigned long st_mtime; | 
|  |  | 
|  | unsigned long st_mtime_nsec; | 
|  | unsigned long st_ctime; | 
|  | unsigned long st_ctime_nsec; | 
|  | long          __unused[3]; | 
|  | }; | 
|  |  | 
|  | #elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) | 
|  | /* Syscalls for i386 : | 
|  | *   - mostly similar to x86_64 | 
|  | *   - registers are 32-bit | 
|  | *   - syscall number is passed in eax | 
|  | *   - arguments are in ebx, ecx, edx, esi, edi, ebp respectively | 
|  | *   - all registers are preserved (except eax of course) | 
|  | *   - the system call is performed by calling int $0x80 | 
|  | *   - syscall return comes in eax | 
|  | *   - the arguments are cast to long and assigned into the target registers | 
|  | *     which are then simply passed as registers to the asm code, so that we | 
|  | *     don't have to experience issues with register constraints. | 
|  | *   - the syscall number is always specified last in order to allow to force | 
|  | *     some registers before (gcc refuses a %-register at the last position). | 
|  | * | 
|  | * Also, i386 supports the old_select syscall if newselect is not available | 
|  | */ | 
|  | #define __ARCH_WANT_SYS_OLD_SELECT | 
|  |  | 
|  | #define my_syscall0(num)                                                      \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num asm("eax") = (num);                                \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "int $0x80\n"                                                 \ | 
|  | : "=a" (_ret)                                                 \ | 
|  | : "0"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall1(num, arg1)                                                \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num asm("eax") = (num);                                \ | 
|  | register long _arg1 asm("ebx") = (long)(arg1);                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "int $0x80\n"                                                 \ | 
|  | : "=a" (_ret)                                                 \ | 
|  | : "r"(_arg1),                                                 \ | 
|  | "0"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall2(num, arg1, arg2)                                          \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num asm("eax") = (num);                                \ | 
|  | register long _arg1 asm("ebx") = (long)(arg1);                        \ | 
|  | register long _arg2 asm("ecx") = (long)(arg2);                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "int $0x80\n"                                                 \ | 
|  | : "=a" (_ret)                                                 \ | 
|  | : "r"(_arg1), "r"(_arg2),                                     \ | 
|  | "0"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall3(num, arg1, arg2, arg3)                                    \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num asm("eax") = (num);                                \ | 
|  | register long _arg1 asm("ebx") = (long)(arg1);                        \ | 
|  | register long _arg2 asm("ecx") = (long)(arg2);                        \ | 
|  | register long _arg3 asm("edx") = (long)(arg3);                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "int $0x80\n"                                                 \ | 
|  | : "=a" (_ret)                                                 \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \ | 
|  | "0"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num asm("eax") = (num);                                \ | 
|  | register long _arg1 asm("ebx") = (long)(arg1);                        \ | 
|  | register long _arg2 asm("ecx") = (long)(arg2);                        \ | 
|  | register long _arg3 asm("edx") = (long)(arg3);                        \ | 
|  | register long _arg4 asm("esi") = (long)(arg4);                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "int $0x80\n"                                                 \ | 
|  | : "=a" (_ret)                                                 \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \ | 
|  | "0"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \ | 
|  | ({                                                                            \ | 
|  | long _ret;                                                            \ | 
|  | register long _num asm("eax") = (num);                                \ | 
|  | register long _arg1 asm("ebx") = (long)(arg1);                        \ | 
|  | register long _arg2 asm("ecx") = (long)(arg2);                        \ | 
|  | register long _arg3 asm("edx") = (long)(arg3);                        \ | 
|  | register long _arg4 asm("esi") = (long)(arg4);                        \ | 
|  | register long _arg5 asm("edi") = (long)(arg5);                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "int $0x80\n"                                                 \ | 
|  | : "=a" (_ret)                                                 \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | 
|  | "0"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _ret;                                                                 \ | 
|  | }) | 
|  |  | 
|  | /* startup code */ | 
|  | asm(".section .text\n" | 
|  | ".global _start\n" | 
|  | "_start:\n" | 
|  | "pop %eax\n"                // argc   (first arg, %eax) | 
|  | "mov %esp, %ebx\n"          // argv[] (second arg, %ebx) | 
|  | "lea 4(%ebx,%eax,4),%ecx\n" // then a NULL then envp (third arg, %ecx) | 
|  | "and $-16, %esp\n"          // x86 ABI : esp must be 16-byte aligned when | 
|  | "push %ecx\n"               // push all registers on the stack so that we | 
|  | "push %ebx\n"               // support both regparm and plain stack modes | 
|  | "push %eax\n" | 
|  | "call main\n"               // main() returns the status code in %eax | 
|  | "movzbl %al, %ebx\n"        // retrieve exit code from lower 8 bits | 
|  | "movl   $1, %eax\n"         // NR_exit == 1 | 
|  | "int    $0x80\n"            // exit now | 
|  | "hlt\n"                     // ensure it does not | 
|  | ""); | 
|  |  | 
|  | /* fcntl / open */ | 
|  | #define O_RDONLY            0 | 
|  | #define O_WRONLY            1 | 
|  | #define O_RDWR              2 | 
|  | #define O_CREAT          0x40 | 
|  | #define O_EXCL           0x80 | 
|  | #define O_NOCTTY        0x100 | 
|  | #define O_TRUNC         0x200 | 
|  | #define O_APPEND        0x400 | 
|  | #define O_NONBLOCK      0x800 | 
|  | #define O_DIRECTORY   0x10000 | 
|  |  | 
|  | /* The struct returned by the stat() syscall, 32-bit only, the syscall returns | 
|  | * exactly 56 bytes (stops before the unused array). | 
|  | */ | 
|  | struct sys_stat_struct { | 
|  | unsigned long  st_dev; | 
|  | unsigned long  st_ino; | 
|  | unsigned short st_mode; | 
|  | unsigned short st_nlink; | 
|  | unsigned short st_uid; | 
|  | unsigned short st_gid; | 
|  |  | 
|  | unsigned long  st_rdev; | 
|  | unsigned long  st_size; | 
|  | unsigned long  st_blksize; | 
|  | unsigned long  st_blocks; | 
|  |  | 
|  | unsigned long  st_atime; | 
|  | unsigned long  st_atime_nsec; | 
|  | unsigned long  st_mtime; | 
|  | unsigned long  st_mtime_nsec; | 
|  |  | 
|  | unsigned long  st_ctime; | 
|  | unsigned long  st_ctime_nsec; | 
|  | unsigned long  __unused[2]; | 
|  | }; | 
|  |  | 
|  | #elif defined(__ARM_EABI__) | 
|  | /* Syscalls for ARM in ARM or Thumb modes : | 
|  | *   - registers are 32-bit | 
|  | *   - stack is 8-byte aligned | 
|  | *     ( http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html) | 
|  | *   - syscall number is passed in r7 | 
|  | *   - arguments are in r0, r1, r2, r3, r4, r5 | 
|  | *   - the system call is performed by calling svc #0 | 
|  | *   - syscall return comes in r0. | 
|  | *   - only lr is clobbered. | 
|  | *   - the arguments are cast to long and assigned into the target registers | 
|  | *     which are then simply passed as registers to the asm code, so that we | 
|  | *     don't have to experience issues with register constraints. | 
|  | *   - the syscall number is always specified last in order to allow to force | 
|  | *     some registers before (gcc refuses a %-register at the last position). | 
|  | * | 
|  | * Also, ARM supports the old_select syscall if newselect is not available | 
|  | */ | 
|  | #define __ARCH_WANT_SYS_OLD_SELECT | 
|  |  | 
|  | #define my_syscall0(num)                                                      \ | 
|  | ({                                                                            \ | 
|  | register long _num asm("r7") = (num);                                 \ | 
|  | register long _arg1 asm("r0");                                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r"(_arg1)                                                 \ | 
|  | : "r"(_num)                                                   \ | 
|  | : "memory", "cc", "lr"                                        \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall1(num, arg1)                                                \ | 
|  | ({                                                                            \ | 
|  | register long _num asm("r7") = (num);                                 \ | 
|  | register long _arg1 asm("r0") = (long)(arg1);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r"(_arg1)                                                 \ | 
|  | : "r"(_arg1),                                                 \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc", "lr"                                        \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall2(num, arg1, arg2)                                          \ | 
|  | ({                                                                            \ | 
|  | register long _num asm("r7") = (num);                                 \ | 
|  | register long _arg1 asm("r0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("r1") = (long)(arg2);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r"(_arg1)                                                 \ | 
|  | : "r"(_arg1), "r"(_arg2),                                     \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc", "lr"                                        \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall3(num, arg1, arg2, arg3)                                    \ | 
|  | ({                                                                            \ | 
|  | register long _num asm("r7") = (num);                                 \ | 
|  | register long _arg1 asm("r0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("r1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("r2") = (long)(arg3);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r"(_arg1)                                                 \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc", "lr"                                        \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \ | 
|  | ({                                                                            \ | 
|  | register long _num asm("r7") = (num);                                 \ | 
|  | register long _arg1 asm("r0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("r1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("r2") = (long)(arg3);                         \ | 
|  | register long _arg4 asm("r3") = (long)(arg4);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r"(_arg1)                                                 \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc", "lr"                                        \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \ | 
|  | ({                                                                            \ | 
|  | register long _num asm("r7") = (num);                                 \ | 
|  | register long _arg1 asm("r0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("r1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("r2") = (long)(arg3);                         \ | 
|  | register long _arg4 asm("r3") = (long)(arg4);                         \ | 
|  | register long _arg5 asm("r4") = (long)(arg5);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r" (_arg1)                                                \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc", "lr"                                        \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | /* startup code */ | 
|  | asm(".section .text\n" | 
|  | ".global _start\n" | 
|  | "_start:\n" | 
|  | #if defined(__THUMBEB__) || defined(__THUMBEL__) | 
|  | /* We enter here in 32-bit mode but if some previous functions were in | 
|  | * 16-bit mode, the assembler cannot know, so we need to tell it we're in | 
|  | * 32-bit now, then switch to 16-bit (is there a better way to do it than | 
|  | * adding 1 by hand ?) and tell the asm we're now in 16-bit mode so that | 
|  | * it generates correct instructions. Note that we do not support thumb1. | 
|  | */ | 
|  | ".code 32\n" | 
|  | "add     r0, pc, #1\n" | 
|  | "bx      r0\n" | 
|  | ".code 16\n" | 
|  | #endif | 
|  | "pop {%r0}\n"                 // argc was in the stack | 
|  | "mov %r1, %sp\n"              // argv = sp | 
|  | "add %r2, %r1, %r0, lsl #2\n" // envp = argv + 4*argc ... | 
|  | "add %r2, %r2, $4\n"          //        ... + 4 | 
|  | "and %r3, %r1, $-8\n"         // AAPCS : sp must be 8-byte aligned in the | 
|  | "mov %sp, %r3\n"              //         callee, an bl doesn't push (lr=pc) | 
|  | "bl main\n"                   // main() returns the status code, we'll exit with it. | 
|  | "and %r0, %r0, $0xff\n"       // limit exit code to 8 bits | 
|  | "movs r7, $1\n"               // NR_exit == 1 | 
|  | "svc $0x00\n" | 
|  | ""); | 
|  |  | 
|  | /* fcntl / open */ | 
|  | #define O_RDONLY            0 | 
|  | #define O_WRONLY            1 | 
|  | #define O_RDWR              2 | 
|  | #define O_CREAT          0x40 | 
|  | #define O_EXCL           0x80 | 
|  | #define O_NOCTTY        0x100 | 
|  | #define O_TRUNC         0x200 | 
|  | #define O_APPEND        0x400 | 
|  | #define O_NONBLOCK      0x800 | 
|  | #define O_DIRECTORY    0x4000 | 
|  |  | 
|  | /* The struct returned by the stat() syscall, 32-bit only, the syscall returns | 
|  | * exactly 56 bytes (stops before the unused array). In big endian, the format | 
|  | * differs as devices are returned as short only. | 
|  | */ | 
|  | struct sys_stat_struct { | 
|  | #if defined(__ARMEB__) | 
|  | unsigned short st_dev; | 
|  | unsigned short __pad1; | 
|  | #else | 
|  | unsigned long  st_dev; | 
|  | #endif | 
|  | unsigned long  st_ino; | 
|  | unsigned short st_mode; | 
|  | unsigned short st_nlink; | 
|  | unsigned short st_uid; | 
|  | unsigned short st_gid; | 
|  | #if defined(__ARMEB__) | 
|  | unsigned short st_rdev; | 
|  | unsigned short __pad2; | 
|  | #else | 
|  | unsigned long  st_rdev; | 
|  | #endif | 
|  | unsigned long  st_size; | 
|  | unsigned long  st_blksize; | 
|  | unsigned long  st_blocks; | 
|  | unsigned long  st_atime; | 
|  | unsigned long  st_atime_nsec; | 
|  | unsigned long  st_mtime; | 
|  | unsigned long  st_mtime_nsec; | 
|  | unsigned long  st_ctime; | 
|  | unsigned long  st_ctime_nsec; | 
|  | unsigned long  __unused[2]; | 
|  | }; | 
|  |  | 
|  | #elif defined(__aarch64__) | 
|  | /* Syscalls for AARCH64 : | 
|  | *   - registers are 64-bit | 
|  | *   - stack is 16-byte aligned | 
|  | *   - syscall number is passed in x8 | 
|  | *   - arguments are in x0, x1, x2, x3, x4, x5 | 
|  | *   - the system call is performed by calling svc 0 | 
|  | *   - syscall return comes in x0. | 
|  | *   - the arguments are cast to long and assigned into the target registers | 
|  | *     which are then simply passed as registers to the asm code, so that we | 
|  | *     don't have to experience issues with register constraints. | 
|  | * | 
|  | * On aarch64, select() is not implemented so we have to use pselect6(). | 
|  | */ | 
|  | #define __ARCH_WANT_SYS_PSELECT6 | 
|  |  | 
|  | #define my_syscall0(num)                                                      \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("x8") = (num);                                \ | 
|  | register long _arg1 asm("x0");                                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r"(_arg1)                                                 \ | 
|  | : "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall1(num, arg1)                                                \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("x8") = (num);                                \ | 
|  | register long _arg1 asm("x0") = (long)(arg1);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r"(_arg1)                                                 \ | 
|  | : "r"(_arg1),                                                 \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall2(num, arg1, arg2)                                          \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("x8") = (num);                                \ | 
|  | register long _arg1 asm("x0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("x1") = (long)(arg2);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r"(_arg1)                                                 \ | 
|  | : "r"(_arg1), "r"(_arg2),                                     \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall3(num, arg1, arg2, arg3)                                    \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("x8") = (num);                                \ | 
|  | register long _arg1 asm("x0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("x1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("x2") = (long)(arg3);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r"(_arg1)                                                 \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("x8") = (num);                                \ | 
|  | register long _arg1 asm("x0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("x1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("x2") = (long)(arg3);                         \ | 
|  | register long _arg4 asm("x3") = (long)(arg4);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r"(_arg1)                                                 \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("x8") = (num);                                \ | 
|  | register long _arg1 asm("x0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("x1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("x2") = (long)(arg3);                         \ | 
|  | register long _arg4 asm("x3") = (long)(arg4);                         \ | 
|  | register long _arg5 asm("x4") = (long)(arg5);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r" (_arg1)                                                \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("x8") = (num);                                \ | 
|  | register long _arg1 asm("x0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("x1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("x2") = (long)(arg3);                         \ | 
|  | register long _arg4 asm("x3") = (long)(arg4);                         \ | 
|  | register long _arg5 asm("x4") = (long)(arg5);                         \ | 
|  | register long _arg6 asm("x5") = (long)(arg6);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "svc #0\n"                                                    \ | 
|  | : "=r" (_arg1)                                                \ | 
|  | : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ | 
|  | "r"(_arg6), "r"(_num)                                       \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | /* startup code */ | 
|  | asm(".section .text\n" | 
|  | ".global _start\n" | 
|  | "_start:\n" | 
|  | "ldr x0, [sp]\n"              // argc (x0) was in the stack | 
|  | "add x1, sp, 8\n"             // argv (x1) = sp | 
|  | "lsl x2, x0, 3\n"             // envp (x2) = 8*argc ... | 
|  | "add x2, x2, 8\n"             //           + 8 (skip null) | 
|  | "add x2, x2, x1\n"            //           + argv | 
|  | "and sp, x1, -16\n"           // sp must be 16-byte aligned in the callee | 
|  | "bl main\n"                   // main() returns the status code, we'll exit with it. | 
|  | "and x0, x0, 0xff\n"          // limit exit code to 8 bits | 
|  | "mov x8, 93\n"                // NR_exit == 93 | 
|  | "svc #0\n" | 
|  | ""); | 
|  |  | 
|  | /* fcntl / open */ | 
|  | #define O_RDONLY            0 | 
|  | #define O_WRONLY            1 | 
|  | #define O_RDWR              2 | 
|  | #define O_CREAT          0x40 | 
|  | #define O_EXCL           0x80 | 
|  | #define O_NOCTTY        0x100 | 
|  | #define O_TRUNC         0x200 | 
|  | #define O_APPEND        0x400 | 
|  | #define O_NONBLOCK      0x800 | 
|  | #define O_DIRECTORY    0x4000 | 
|  |  | 
|  | /* The struct returned by the newfstatat() syscall. Differs slightly from the | 
|  | * x86_64's stat one by field ordering, so be careful. | 
|  | */ | 
|  | struct sys_stat_struct { | 
|  | unsigned long   st_dev; | 
|  | unsigned long   st_ino; | 
|  | unsigned int    st_mode; | 
|  | unsigned int    st_nlink; | 
|  | unsigned int    st_uid; | 
|  | unsigned int    st_gid; | 
|  |  | 
|  | unsigned long   st_rdev; | 
|  | unsigned long   __pad1; | 
|  | long            st_size; | 
|  | int             st_blksize; | 
|  | int             __pad2; | 
|  |  | 
|  | long            st_blocks; | 
|  | long            st_atime; | 
|  | unsigned long   st_atime_nsec; | 
|  | long            st_mtime; | 
|  |  | 
|  | unsigned long   st_mtime_nsec; | 
|  | long            st_ctime; | 
|  | unsigned long   st_ctime_nsec; | 
|  | unsigned int    __unused[2]; | 
|  | }; | 
|  |  | 
|  | #elif defined(__mips__) && defined(_ABIO32) | 
|  | /* Syscalls for MIPS ABI O32 : | 
|  | *   - WARNING! there's always a delayed slot! | 
|  | *   - WARNING again, the syntax is different, registers take a '$' and numbers | 
|  | *     do not. | 
|  | *   - registers are 32-bit | 
|  | *   - stack is 8-byte aligned | 
|  | *   - syscall number is passed in v0 (starts at 0xfa0). | 
|  | *   - arguments are in a0, a1, a2, a3, then the stack. The caller needs to | 
|  | *     leave some room in the stack for the callee to save a0..a3 if needed. | 
|  | *   - Many registers are clobbered, in fact only a0..a2 and s0..s8 are | 
|  | *     preserved. See: https://www.linux-mips.org/wiki/Syscall as well as | 
|  | *     scall32-o32.S in the kernel sources. | 
|  | *   - the system call is performed by calling "syscall" | 
|  | *   - syscall return comes in v0, and register a3 needs to be checked to know | 
|  | *     if an error occured, in which case errno is in v0. | 
|  | *   - the arguments are cast to long and assigned into the target registers | 
|  | *     which are then simply passed as registers to the asm code, so that we | 
|  | *     don't have to experience issues with register constraints. | 
|  | */ | 
|  |  | 
|  | #define my_syscall0(num)                                                      \ | 
|  | ({                                                                            \ | 
|  | register long _num asm("v0") = (num);                                 \ | 
|  | register long _arg4 asm("a3");                                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "addiu $sp, $sp, -32\n"                                       \ | 
|  | "syscall\n"                                                   \ | 
|  | "addiu $sp, $sp, 32\n"                                        \ | 
|  | : "=r"(_num), "=r"(_arg4)                                     \ | 
|  | : "r"(_num)                                                   \ | 
|  | : "memory", "cc", "at", "v1", "hi", "lo",                     \ | 
|  | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"  \ | 
|  | );                                                                    \ | 
|  | _arg4 ? -_num : _num;                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall1(num, arg1)                                                \ | 
|  | ({                                                                            \ | 
|  | register long _num asm("v0") = (num);                                 \ | 
|  | register long _arg1 asm("a0") = (long)(arg1);                         \ | 
|  | register long _arg4 asm("a3");                                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "addiu $sp, $sp, -32\n"                                       \ | 
|  | "syscall\n"                                                   \ | 
|  | "addiu $sp, $sp, 32\n"                                        \ | 
|  | : "=r"(_num), "=r"(_arg4)                                     \ | 
|  | : "0"(_num),                                                  \ | 
|  | "r"(_arg1)                                                  \ | 
|  | : "memory", "cc", "at", "v1", "hi", "lo",                     \ | 
|  | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"  \ | 
|  | );                                                                    \ | 
|  | _arg4 ? -_num : _num;                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall2(num, arg1, arg2)                                          \ | 
|  | ({                                                                            \ | 
|  | register long _num asm("v0") = (num);                                 \ | 
|  | register long _arg1 asm("a0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("a1") = (long)(arg2);                         \ | 
|  | register long _arg4 asm("a3");                                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "addiu $sp, $sp, -32\n"                                       \ | 
|  | "syscall\n"                                                   \ | 
|  | "addiu $sp, $sp, 32\n"                                        \ | 
|  | : "=r"(_num), "=r"(_arg4)                                     \ | 
|  | : "0"(_num),                                                  \ | 
|  | "r"(_arg1), "r"(_arg2)                                      \ | 
|  | : "memory", "cc", "at", "v1", "hi", "lo",                     \ | 
|  | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"  \ | 
|  | );                                                                    \ | 
|  | _arg4 ? -_num : _num;                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall3(num, arg1, arg2, arg3)                                    \ | 
|  | ({                                                                            \ | 
|  | register long _num asm("v0")  = (num);                                \ | 
|  | register long _arg1 asm("a0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("a1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("a2") = (long)(arg3);                         \ | 
|  | register long _arg4 asm("a3");                                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "addiu $sp, $sp, -32\n"                                       \ | 
|  | "syscall\n"                                                   \ | 
|  | "addiu $sp, $sp, 32\n"                                        \ | 
|  | : "=r"(_num), "=r"(_arg4)                                     \ | 
|  | : "0"(_num),                                                  \ | 
|  | "r"(_arg1), "r"(_arg2), "r"(_arg3)                          \ | 
|  | : "memory", "cc", "at", "v1", "hi", "lo",                     \ | 
|  | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"  \ | 
|  | );                                                                    \ | 
|  | _arg4 ? -_num : _num;                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \ | 
|  | ({                                                                            \ | 
|  | register long _num asm("v0") = (num);                                 \ | 
|  | register long _arg1 asm("a0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("a1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("a2") = (long)(arg3);                         \ | 
|  | register long _arg4 asm("a3") = (long)(arg4);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "addiu $sp, $sp, -32\n"                                       \ | 
|  | "syscall\n"                                                   \ | 
|  | "addiu $sp, $sp, 32\n"                                        \ | 
|  | : "=r" (_num), "=r"(_arg4)                                    \ | 
|  | : "0"(_num),                                                  \ | 
|  | "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4)              \ | 
|  | : "memory", "cc", "at", "v1", "hi", "lo",                     \ | 
|  | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"  \ | 
|  | );                                                                    \ | 
|  | _arg4 ? -_num : _num;                                                 \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \ | 
|  | ({                                                                            \ | 
|  | register long _num asm("v0") = (num);                                 \ | 
|  | register long _arg1 asm("a0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("a1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("a2") = (long)(arg3);                         \ | 
|  | register long _arg4 asm("a3") = (long)(arg4);                         \ | 
|  | register long _arg5 = (long)(arg5);				      \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "addiu $sp, $sp, -32\n"                                       \ | 
|  | "sw %7, 16($sp)\n"                                            \ | 
|  | "syscall\n  "                                                 \ | 
|  | "addiu $sp, $sp, 32\n"                                        \ | 
|  | : "=r" (_num), "=r"(_arg4)                                    \ | 
|  | : "0"(_num),                                                  \ | 
|  | "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5)  \ | 
|  | : "memory", "cc", "at", "v1", "hi", "lo",                     \ | 
|  | "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"  \ | 
|  | );                                                                    \ | 
|  | _arg4 ? -_num : _num;                                                 \ | 
|  | }) | 
|  |  | 
|  | /* startup code, note that it's called __start on MIPS */ | 
|  | asm(".section .text\n" | 
|  | ".set nomips16\n" | 
|  | ".global __start\n" | 
|  | ".set    noreorder\n" | 
|  | ".option pic0\n" | 
|  | ".ent __start\n" | 
|  | "__start:\n" | 
|  | "lw $a0,($sp)\n"              // argc was in the stack | 
|  | "addiu  $a1, $sp, 4\n"        // argv = sp + 4 | 
|  | "sll $a2, $a0, 2\n"           // a2 = argc * 4 | 
|  | "add   $a2, $a2, $a1\n"       // envp = argv + 4*argc ... | 
|  | "addiu $a2, $a2, 4\n"         //        ... + 4 | 
|  | "li $t0, -8\n" | 
|  | "and $sp, $sp, $t0\n"         // sp must be 8-byte aligned | 
|  | "addiu $sp,$sp,-16\n"         // the callee expects to save a0..a3 there! | 
|  | "jal main\n"                  // main() returns the status code, we'll exit with it. | 
|  | "nop\n"                       // delayed slot | 
|  | "and $a0, $v0, 0xff\n"        // limit exit code to 8 bits | 
|  | "li $v0, 4001\n"              // NR_exit == 4001 | 
|  | "syscall\n" | 
|  | ".end __start\n" | 
|  | ""); | 
|  |  | 
|  | /* fcntl / open */ | 
|  | #define O_RDONLY            0 | 
|  | #define O_WRONLY            1 | 
|  | #define O_RDWR              2 | 
|  | #define O_APPEND       0x0008 | 
|  | #define O_NONBLOCK     0x0080 | 
|  | #define O_CREAT        0x0100 | 
|  | #define O_TRUNC        0x0200 | 
|  | #define O_EXCL         0x0400 | 
|  | #define O_NOCTTY       0x0800 | 
|  | #define O_DIRECTORY   0x10000 | 
|  |  | 
|  | /* The struct returned by the stat() syscall. 88 bytes are returned by the | 
|  | * syscall. | 
|  | */ | 
|  | struct sys_stat_struct { | 
|  | unsigned int  st_dev; | 
|  | long          st_pad1[3]; | 
|  | unsigned long st_ino; | 
|  | unsigned int  st_mode; | 
|  | unsigned int  st_nlink; | 
|  | unsigned int  st_uid; | 
|  | unsigned int  st_gid; | 
|  | unsigned int  st_rdev; | 
|  | long          st_pad2[2]; | 
|  | long          st_size; | 
|  | long          st_pad3; | 
|  | long          st_atime; | 
|  | long          st_atime_nsec; | 
|  | long          st_mtime; | 
|  | long          st_mtime_nsec; | 
|  | long          st_ctime; | 
|  | long          st_ctime_nsec; | 
|  | long          st_blksize; | 
|  | long          st_blocks; | 
|  | long          st_pad4[14]; | 
|  | }; | 
|  |  | 
|  | #elif defined(__riscv) | 
|  |  | 
|  | #if   __riscv_xlen == 64 | 
|  | #define PTRLOG "3" | 
|  | #define SZREG  "8" | 
|  | #elif __riscv_xlen == 32 | 
|  | #define PTRLOG "2" | 
|  | #define SZREG  "4" | 
|  | #endif | 
|  |  | 
|  | /* Syscalls for RISCV : | 
|  | *   - stack is 16-byte aligned | 
|  | *   - syscall number is passed in a7 | 
|  | *   - arguments are in a0, a1, a2, a3, a4, a5 | 
|  | *   - the system call is performed by calling ecall | 
|  | *   - syscall return comes in a0 | 
|  | *   - the arguments are cast to long and assigned into the target | 
|  | *     registers which are then simply passed as registers to the asm code, | 
|  | *     so that we don't have to experience issues with register constraints. | 
|  | */ | 
|  |  | 
|  | #define my_syscall0(num)                                                      \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("a7") = (num);                                \ | 
|  | register long _arg1 asm("a0");                                        \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "ecall\n\t"                                                   \ | 
|  | : "=r"(_arg1)                                                 \ | 
|  | : "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall1(num, arg1)                                                \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("a7") = (num);                                \ | 
|  | register long _arg1 asm("a0") = (long)(arg1);		              \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "ecall\n"                                                     \ | 
|  | : "+r"(_arg1)                                                 \ | 
|  | : "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall2(num, arg1, arg2)                                          \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("a7") = (num);                                \ | 
|  | register long _arg1 asm("a0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("a1") = (long)(arg2);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "ecall\n"                                                     \ | 
|  | : "+r"(_arg1)                                                 \ | 
|  | : "r"(_arg2),                                                 \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall3(num, arg1, arg2, arg3)                                    \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("a7") = (num);                                \ | 
|  | register long _arg1 asm("a0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("a1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("a2") = (long)(arg3);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "ecall\n\t"                                                   \ | 
|  | : "+r"(_arg1)                                                 \ | 
|  | : "r"(_arg2), "r"(_arg3),                                     \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("a7") = (num);                                \ | 
|  | register long _arg1 asm("a0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("a1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("a2") = (long)(arg3);                         \ | 
|  | register long _arg4 asm("a3") = (long)(arg4);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "ecall\n"                                                     \ | 
|  | : "+r"(_arg1)                                                 \ | 
|  | : "r"(_arg2), "r"(_arg3), "r"(_arg4),                         \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("a7") = (num);                                \ | 
|  | register long _arg1 asm("a0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("a1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("a2") = (long)(arg3);                         \ | 
|  | register long _arg4 asm("a3") = (long)(arg4);                         \ | 
|  | register long _arg5 asm("a4") = (long)(arg5);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "ecall\n"                                                     \ | 
|  | : "+r"(_arg1)                                                 \ | 
|  | : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5),             \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \ | 
|  | ({                                                                            \ | 
|  | register long _num  asm("a7") = (num);                                \ | 
|  | register long _arg1 asm("a0") = (long)(arg1);                         \ | 
|  | register long _arg2 asm("a1") = (long)(arg2);                         \ | 
|  | register long _arg3 asm("a2") = (long)(arg3);                         \ | 
|  | register long _arg4 asm("a3") = (long)(arg4);                         \ | 
|  | register long _arg5 asm("a4") = (long)(arg5);                         \ | 
|  | register long _arg6 asm("a5") = (long)(arg6);                         \ | 
|  | \ | 
|  | asm volatile (                                                        \ | 
|  | "ecall\n"                                                     \ | 
|  | : "+r"(_arg1)                                                 \ | 
|  | : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ | 
|  | "r"(_num)                                                   \ | 
|  | : "memory", "cc"                                              \ | 
|  | );                                                                    \ | 
|  | _arg1;                                                                \ | 
|  | }) | 
|  |  | 
|  | /* startup code */ | 
|  | asm(".section .text\n" | 
|  | ".global _start\n" | 
|  | "_start:\n" | 
|  | ".option push\n" | 
|  | ".option norelax\n" | 
|  | "lla   gp, __global_pointer$\n" | 
|  | ".option pop\n" | 
|  | "ld    a0, 0(sp)\n"          // argc (a0) was in the stack | 
|  | "add   a1, sp, "SZREG"\n"    // argv (a1) = sp | 
|  | "slli  a2, a0, "PTRLOG"\n"   // envp (a2) = SZREG*argc ... | 
|  | "add   a2, a2, "SZREG"\n"    //             + SZREG (skip null) | 
|  | "add   a2,a2,a1\n"           //             + argv | 
|  | "andi  sp,a1,-16\n"          // sp must be 16-byte aligned | 
|  | "call  main\n"               // main() returns the status code, we'll exit with it. | 
|  | "andi  a0, a0, 0xff\n"       // limit exit code to 8 bits | 
|  | "li a7, 93\n"                // NR_exit == 93 | 
|  | "ecall\n" | 
|  | ""); | 
|  |  | 
|  | /* fcntl / open */ | 
|  | #define O_RDONLY            0 | 
|  | #define O_WRONLY            1 | 
|  | #define O_RDWR              2 | 
|  | #define O_CREAT         0x100 | 
|  | #define O_EXCL          0x200 | 
|  | #define O_NOCTTY        0x400 | 
|  | #define O_TRUNC        0x1000 | 
|  | #define O_APPEND       0x2000 | 
|  | #define O_NONBLOCK     0x4000 | 
|  | #define O_DIRECTORY  0x200000 | 
|  |  | 
|  | struct sys_stat_struct { | 
|  | unsigned long	st_dev;		/* Device.  */ | 
|  | unsigned long	st_ino;		/* File serial number.  */ | 
|  | unsigned int	st_mode;	/* File mode.  */ | 
|  | unsigned int	st_nlink;	/* Link count.  */ | 
|  | unsigned int	st_uid;		/* User ID of the file's owner.  */ | 
|  | unsigned int	st_gid;		/* Group ID of the file's group. */ | 
|  | unsigned long	st_rdev;	/* Device number, if device.  */ | 
|  | unsigned long	__pad1; | 
|  | long		st_size;	/* Size of file, in bytes.  */ | 
|  | int		st_blksize;	/* Optimal block size for I/O.  */ | 
|  | int		__pad2; | 
|  | long		st_blocks;	/* Number 512-byte blocks allocated. */ | 
|  | long		st_atime;	/* Time of last access.  */ | 
|  | unsigned long	st_atime_nsec; | 
|  | long		st_mtime;	/* Time of last modification.  */ | 
|  | unsigned long	st_mtime_nsec; | 
|  | long		st_ctime;	/* Time of last status change.  */ | 
|  | unsigned long	st_ctime_nsec; | 
|  | unsigned int	__unused4; | 
|  | unsigned int	__unused5; | 
|  | }; | 
|  |  | 
|  | #endif | 
|  |  | 
|  |  | 
|  | /* Below are the C functions used to declare the raw syscalls. They try to be | 
|  | * architecture-agnostic, and return either a success or -errno. Declaring them | 
|  | * static will lead to them being inlined in most cases, but it's still possible | 
|  | * to reference them by a pointer if needed. | 
|  | */ | 
|  | static __attribute__((unused)) | 
|  | void *sys_brk(void *addr) | 
|  | { | 
|  | return (void *)my_syscall1(__NR_brk, addr); | 
|  | } | 
|  |  | 
|  | static __attribute__((noreturn,unused)) | 
|  | void sys_exit(int status) | 
|  | { | 
|  | my_syscall1(__NR_exit, status & 255); | 
|  | while(1); // shut the "noreturn" warnings. | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_chdir(const char *path) | 
|  | { | 
|  | return my_syscall1(__NR_chdir, path); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_chmod(const char *path, mode_t mode) | 
|  | { | 
|  | #ifdef __NR_fchmodat | 
|  | return my_syscall4(__NR_fchmodat, AT_FDCWD, path, mode, 0); | 
|  | #else | 
|  | return my_syscall2(__NR_chmod, path, mode); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_chown(const char *path, uid_t owner, gid_t group) | 
|  | { | 
|  | #ifdef __NR_fchownat | 
|  | return my_syscall5(__NR_fchownat, AT_FDCWD, path, owner, group, 0); | 
|  | #else | 
|  | return my_syscall3(__NR_chown, path, owner, group); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_chroot(const char *path) | 
|  | { | 
|  | return my_syscall1(__NR_chroot, path); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_close(int fd) | 
|  | { | 
|  | return my_syscall1(__NR_close, fd); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_dup(int fd) | 
|  | { | 
|  | return my_syscall1(__NR_dup, fd); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_dup2(int old, int new) | 
|  | { | 
|  | return my_syscall2(__NR_dup2, old, new); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_execve(const char *filename, char *const argv[], char *const envp[]) | 
|  | { | 
|  | return my_syscall3(__NR_execve, filename, argv, envp); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t sys_fork(void) | 
|  | { | 
|  | return my_syscall0(__NR_fork); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_fsync(int fd) | 
|  | { | 
|  | return my_syscall1(__NR_fsync, fd); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_getdents64(int fd, struct linux_dirent64 *dirp, int count) | 
|  | { | 
|  | return my_syscall3(__NR_getdents64, fd, dirp, count); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t sys_getpgrp(void) | 
|  | { | 
|  | return my_syscall0(__NR_getpgrp); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t sys_getpid(void) | 
|  | { | 
|  | return my_syscall0(__NR_getpid); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_gettimeofday(struct timeval *tv, struct timezone *tz) | 
|  | { | 
|  | return my_syscall2(__NR_gettimeofday, tv, tz); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_ioctl(int fd, unsigned long req, void *value) | 
|  | { | 
|  | return my_syscall3(__NR_ioctl, fd, req, value); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_kill(pid_t pid, int signal) | 
|  | { | 
|  | return my_syscall2(__NR_kill, pid, signal); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_link(const char *old, const char *new) | 
|  | { | 
|  | #ifdef __NR_linkat | 
|  | return my_syscall5(__NR_linkat, AT_FDCWD, old, AT_FDCWD, new, 0); | 
|  | #else | 
|  | return my_syscall2(__NR_link, old, new); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | off_t sys_lseek(int fd, off_t offset, int whence) | 
|  | { | 
|  | return my_syscall3(__NR_lseek, fd, offset, whence); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_mkdir(const char *path, mode_t mode) | 
|  | { | 
|  | #ifdef __NR_mkdirat | 
|  | return my_syscall3(__NR_mkdirat, AT_FDCWD, path, mode); | 
|  | #else | 
|  | return my_syscall2(__NR_mkdir, path, mode); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | long sys_mknod(const char *path, mode_t mode, dev_t dev) | 
|  | { | 
|  | #ifdef __NR_mknodat | 
|  | return my_syscall4(__NR_mknodat, AT_FDCWD, path, mode, dev); | 
|  | #else | 
|  | return my_syscall3(__NR_mknod, path, mode, dev); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_mount(const char *src, const char *tgt, const char *fst, | 
|  | unsigned long flags, const void *data) | 
|  | { | 
|  | return my_syscall5(__NR_mount, src, tgt, fst, flags, data); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_open(const char *path, int flags, mode_t mode) | 
|  | { | 
|  | #ifdef __NR_openat | 
|  | return my_syscall4(__NR_openat, AT_FDCWD, path, flags, mode); | 
|  | #else | 
|  | return my_syscall3(__NR_open, path, flags, mode); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_pivot_root(const char *new, const char *old) | 
|  | { | 
|  | return my_syscall2(__NR_pivot_root, new, old); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_poll(struct pollfd *fds, int nfds, int timeout) | 
|  | { | 
|  | return my_syscall3(__NR_poll, fds, nfds, timeout); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | ssize_t sys_read(int fd, void *buf, size_t count) | 
|  | { | 
|  | return my_syscall3(__NR_read, fd, buf, count); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | ssize_t sys_reboot(int magic1, int magic2, int cmd, void *arg) | 
|  | { | 
|  | return my_syscall4(__NR_reboot, magic1, magic2, cmd, arg); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_sched_yield(void) | 
|  | { | 
|  | return my_syscall0(__NR_sched_yield); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) | 
|  | { | 
|  | #if defined(__ARCH_WANT_SYS_OLD_SELECT) && !defined(__NR__newselect) | 
|  | struct sel_arg_struct { | 
|  | unsigned long n; | 
|  | fd_set *r, *w, *e; | 
|  | struct timeval *t; | 
|  | } arg = { .n = nfds, .r = rfds, .w = wfds, .e = efds, .t = timeout }; | 
|  | return my_syscall1(__NR_select, &arg); | 
|  | #elif defined(__ARCH_WANT_SYS_PSELECT6) && defined(__NR_pselect6) | 
|  | struct timespec t; | 
|  |  | 
|  | if (timeout) { | 
|  | t.tv_sec  = timeout->tv_sec; | 
|  | t.tv_nsec = timeout->tv_usec * 1000; | 
|  | } | 
|  | return my_syscall6(__NR_pselect6, nfds, rfds, wfds, efds, timeout ? &t : NULL, NULL); | 
|  | #else | 
|  | #ifndef __NR__newselect | 
|  | #define __NR__newselect __NR_select | 
|  | #endif | 
|  | return my_syscall5(__NR__newselect, nfds, rfds, wfds, efds, timeout); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_setpgid(pid_t pid, pid_t pgid) | 
|  | { | 
|  | return my_syscall2(__NR_setpgid, pid, pgid); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t sys_setsid(void) | 
|  | { | 
|  | return my_syscall0(__NR_setsid); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_stat(const char *path, struct stat *buf) | 
|  | { | 
|  | struct sys_stat_struct stat; | 
|  | long ret; | 
|  |  | 
|  | #ifdef __NR_newfstatat | 
|  | /* only solution for arm64 */ | 
|  | ret = my_syscall4(__NR_newfstatat, AT_FDCWD, path, &stat, 0); | 
|  | #else | 
|  | ret = my_syscall2(__NR_stat, path, &stat); | 
|  | #endif | 
|  | buf->st_dev     = stat.st_dev; | 
|  | buf->st_ino     = stat.st_ino; | 
|  | buf->st_mode    = stat.st_mode; | 
|  | buf->st_nlink   = stat.st_nlink; | 
|  | buf->st_uid     = stat.st_uid; | 
|  | buf->st_gid     = stat.st_gid; | 
|  | buf->st_rdev    = stat.st_rdev; | 
|  | buf->st_size    = stat.st_size; | 
|  | buf->st_blksize = stat.st_blksize; | 
|  | buf->st_blocks  = stat.st_blocks; | 
|  | buf->st_atime   = stat.st_atime; | 
|  | buf->st_mtime   = stat.st_mtime; | 
|  | buf->st_ctime   = stat.st_ctime; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_symlink(const char *old, const char *new) | 
|  | { | 
|  | #ifdef __NR_symlinkat | 
|  | return my_syscall3(__NR_symlinkat, old, AT_FDCWD, new); | 
|  | #else | 
|  | return my_syscall2(__NR_symlink, old, new); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | mode_t sys_umask(mode_t mode) | 
|  | { | 
|  | return my_syscall1(__NR_umask, mode); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_umount2(const char *path, int flags) | 
|  | { | 
|  | return my_syscall2(__NR_umount2, path, flags); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sys_unlink(const char *path) | 
|  | { | 
|  | #ifdef __NR_unlinkat | 
|  | return my_syscall3(__NR_unlinkat, AT_FDCWD, path, 0); | 
|  | #else | 
|  | return my_syscall1(__NR_unlink, path); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t sys_wait4(pid_t pid, int *status, int options, struct rusage *rusage) | 
|  | { | 
|  | return my_syscall4(__NR_wait4, pid, status, options, rusage); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t sys_waitpid(pid_t pid, int *status, int options) | 
|  | { | 
|  | return sys_wait4(pid, status, options, 0); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t sys_wait(int *status) | 
|  | { | 
|  | return sys_waitpid(-1, status, 0); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | ssize_t sys_write(int fd, const void *buf, size_t count) | 
|  | { | 
|  | return my_syscall3(__NR_write, fd, buf, count); | 
|  | } | 
|  |  | 
|  |  | 
|  | /* Below are the libc-compatible syscalls which return x or -1 and set errno. | 
|  | * They rely on the functions above. Similarly they're marked static so that it | 
|  | * is possible to assign pointers to them if needed. | 
|  | */ | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int brk(void *addr) | 
|  | { | 
|  | void *ret = sys_brk(addr); | 
|  |  | 
|  | if (!ret) { | 
|  | SET_ERRNO(ENOMEM); | 
|  | return -1; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static __attribute__((noreturn,unused)) | 
|  | void exit(int status) | 
|  | { | 
|  | sys_exit(status); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int chdir(const char *path) | 
|  | { | 
|  | int ret = sys_chdir(path); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int chmod(const char *path, mode_t mode) | 
|  | { | 
|  | int ret = sys_chmod(path, mode); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int chown(const char *path, uid_t owner, gid_t group) | 
|  | { | 
|  | int ret = sys_chown(path, owner, group); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int chroot(const char *path) | 
|  | { | 
|  | int ret = sys_chroot(path); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int close(int fd) | 
|  | { | 
|  | int ret = sys_close(fd); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int dup2(int old, int new) | 
|  | { | 
|  | int ret = sys_dup2(old, new); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int execve(const char *filename, char *const argv[], char *const envp[]) | 
|  | { | 
|  | int ret = sys_execve(filename, argv, envp); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t fork(void) | 
|  | { | 
|  | pid_t ret = sys_fork(); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int fsync(int fd) | 
|  | { | 
|  | int ret = sys_fsync(fd); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int getdents64(int fd, struct linux_dirent64 *dirp, int count) | 
|  | { | 
|  | int ret = sys_getdents64(fd, dirp, count); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t getpgrp(void) | 
|  | { | 
|  | pid_t ret = sys_getpgrp(); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t getpid(void) | 
|  | { | 
|  | pid_t ret = sys_getpid(); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int gettimeofday(struct timeval *tv, struct timezone *tz) | 
|  | { | 
|  | int ret = sys_gettimeofday(tv, tz); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int ioctl(int fd, unsigned long req, void *value) | 
|  | { | 
|  | int ret = sys_ioctl(fd, req, value); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int kill(pid_t pid, int signal) | 
|  | { | 
|  | int ret = sys_kill(pid, signal); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int link(const char *old, const char *new) | 
|  | { | 
|  | int ret = sys_link(old, new); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | off_t lseek(int fd, off_t offset, int whence) | 
|  | { | 
|  | off_t ret = sys_lseek(fd, offset, whence); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int mkdir(const char *path, mode_t mode) | 
|  | { | 
|  | int ret = sys_mkdir(path, mode); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int mknod(const char *path, mode_t mode, dev_t dev) | 
|  | { | 
|  | int ret = sys_mknod(path, mode, dev); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int mount(const char *src, const char *tgt, | 
|  | const char *fst, unsigned long flags, | 
|  | const void *data) | 
|  | { | 
|  | int ret = sys_mount(src, tgt, fst, flags, data); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int open(const char *path, int flags, mode_t mode) | 
|  | { | 
|  | int ret = sys_open(path, flags, mode); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int pivot_root(const char *new, const char *old) | 
|  | { | 
|  | int ret = sys_pivot_root(new, old); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int poll(struct pollfd *fds, int nfds, int timeout) | 
|  | { | 
|  | int ret = sys_poll(fds, nfds, timeout); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | ssize_t read(int fd, void *buf, size_t count) | 
|  | { | 
|  | ssize_t ret = sys_read(fd, buf, count); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int reboot(int cmd) | 
|  | { | 
|  | int ret = sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, 0); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | void *sbrk(intptr_t inc) | 
|  | { | 
|  | void *ret; | 
|  |  | 
|  | /* first call to find current end */ | 
|  | if ((ret = sys_brk(0)) && (sys_brk(ret + inc) == ret + inc)) | 
|  | return ret + inc; | 
|  |  | 
|  | SET_ERRNO(ENOMEM); | 
|  | return (void *)-1; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int sched_yield(void) | 
|  | { | 
|  | int ret = sys_sched_yield(); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *timeout) | 
|  | { | 
|  | int ret = sys_select(nfds, rfds, wfds, efds, timeout); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int setpgid(pid_t pid, pid_t pgid) | 
|  | { | 
|  | int ret = sys_setpgid(pid, pgid); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t setsid(void) | 
|  | { | 
|  | pid_t ret = sys_setsid(); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | unsigned int sleep(unsigned int seconds) | 
|  | { | 
|  | struct timeval my_timeval = { seconds, 0 }; | 
|  |  | 
|  | if (sys_select(0, 0, 0, 0, &my_timeval) < 0) | 
|  | return my_timeval.tv_sec + !!my_timeval.tv_usec; | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int stat(const char *path, struct stat *buf) | 
|  | { | 
|  | int ret = sys_stat(path, buf); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int symlink(const char *old, const char *new) | 
|  | { | 
|  | int ret = sys_symlink(old, new); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int tcsetpgrp(int fd, pid_t pid) | 
|  | { | 
|  | return ioctl(fd, TIOCSPGRP, &pid); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | mode_t umask(mode_t mode) | 
|  | { | 
|  | return sys_umask(mode); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int umount2(const char *path, int flags) | 
|  | { | 
|  | int ret = sys_umount2(path, flags); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int unlink(const char *path) | 
|  | { | 
|  | int ret = sys_unlink(path); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage) | 
|  | { | 
|  | pid_t ret = sys_wait4(pid, status, options, rusage); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t waitpid(pid_t pid, int *status, int options) | 
|  | { | 
|  | pid_t ret = sys_waitpid(pid, status, options); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | pid_t wait(int *status) | 
|  | { | 
|  | pid_t ret = sys_wait(status); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | ssize_t write(int fd, const void *buf, size_t count) | 
|  | { | 
|  | ssize_t ret = sys_write(fd, buf, count); | 
|  |  | 
|  | if (ret < 0) { | 
|  | SET_ERRNO(-ret); | 
|  | ret = -1; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* some size-optimized reimplementations of a few common str* and mem* | 
|  | * functions. They're marked static, except memcpy() and raise() which are used | 
|  | * by libgcc on ARM, so they are marked weak instead in order not to cause an | 
|  | * error when building a program made of multiple files (not recommended). | 
|  | */ | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | void *memmove(void *dst, const void *src, size_t len) | 
|  | { | 
|  | ssize_t pos = (dst <= src) ? -1 : (long)len; | 
|  | void *ret = dst; | 
|  |  | 
|  | while (len--) { | 
|  | pos += (dst <= src) ? 1 : -1; | 
|  | ((char *)dst)[pos] = ((char *)src)[pos]; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | void *memset(void *dst, int b, size_t len) | 
|  | { | 
|  | char *p = dst; | 
|  |  | 
|  | while (len--) | 
|  | *(p++) = b; | 
|  | return dst; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int memcmp(const void *s1, const void *s2, size_t n) | 
|  | { | 
|  | size_t ofs = 0; | 
|  | char c1 = 0; | 
|  |  | 
|  | while (ofs < n && !(c1 = ((char *)s1)[ofs] - ((char *)s2)[ofs])) { | 
|  | ofs++; | 
|  | } | 
|  | return c1; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | char *strcpy(char *dst, const char *src) | 
|  | { | 
|  | char *ret = dst; | 
|  |  | 
|  | while ((*dst++ = *src++)); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | char *strchr(const char *s, int c) | 
|  | { | 
|  | while (*s) { | 
|  | if (*s == (char)c) | 
|  | return (char *)s; | 
|  | s++; | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | char *strrchr(const char *s, int c) | 
|  | { | 
|  | const char *ret = NULL; | 
|  |  | 
|  | while (*s) { | 
|  | if (*s == (char)c) | 
|  | ret = s; | 
|  | s++; | 
|  | } | 
|  | return (char *)ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | size_t nolibc_strlen(const char *str) | 
|  | { | 
|  | size_t len; | 
|  |  | 
|  | for (len = 0; str[len]; len++); | 
|  | return len; | 
|  | } | 
|  |  | 
|  | #define strlen(str) ({                          \ | 
|  | __builtin_constant_p((str)) ?           \ | 
|  | __builtin_strlen((str)) :       \ | 
|  | nolibc_strlen((str));           \ | 
|  | }) | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int isdigit(int c) | 
|  | { | 
|  | return (unsigned int)(c - '0') <= 9; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | long atol(const char *s) | 
|  | { | 
|  | unsigned long ret = 0; | 
|  | unsigned long d; | 
|  | int neg = 0; | 
|  |  | 
|  | if (*s == '-') { | 
|  | neg = 1; | 
|  | s++; | 
|  | } | 
|  |  | 
|  | while (1) { | 
|  | d = (*s++) - '0'; | 
|  | if (d > 9) | 
|  | break; | 
|  | ret *= 10; | 
|  | ret += d; | 
|  | } | 
|  |  | 
|  | return neg ? -ret : ret; | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | int atoi(const char *s) | 
|  | { | 
|  | return atol(s); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | const char *ltoa(long in) | 
|  | { | 
|  | /* large enough for -9223372036854775808 */ | 
|  | static char buffer[21]; | 
|  | char       *pos = buffer + sizeof(buffer) - 1; | 
|  | int         neg = in < 0; | 
|  | unsigned long n = neg ? -in : in; | 
|  |  | 
|  | *pos-- = '\0'; | 
|  | do { | 
|  | *pos-- = '0' + n % 10; | 
|  | n /= 10; | 
|  | if (pos < buffer) | 
|  | return pos + 1; | 
|  | } while (n); | 
|  |  | 
|  | if (neg) | 
|  | *pos-- = '-'; | 
|  | return pos + 1; | 
|  | } | 
|  |  | 
|  | __attribute__((weak,unused)) | 
|  | void *memcpy(void *dst, const void *src, size_t len) | 
|  | { | 
|  | return memmove(dst, src, len); | 
|  | } | 
|  |  | 
|  | /* needed by libgcc for divide by zero */ | 
|  | __attribute__((weak,unused)) | 
|  | int raise(int signal) | 
|  | { | 
|  | return kill(getpid(), signal); | 
|  | } | 
|  |  | 
|  | /* Here come a few helper functions */ | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | void FD_ZERO(fd_set *set) | 
|  | { | 
|  | memset(set, 0, sizeof(*set)); | 
|  | } | 
|  |  | 
|  | static __attribute__((unused)) | 
|  | void FD_SET(int fd, fd_set *set) | 
|  | { | 
|  | if (fd < 0 || fd >= FD_SETSIZE) | 
|  | return; | 
|  | set->fd32[fd / 32] |= 1 << (fd & 31); | 
|  | } | 
|  |  | 
|  | /* WARNING, it only deals with the 4096 first majors and 256 first minors */ | 
|  | static __attribute__((unused)) | 
|  | dev_t makedev(unsigned int major, unsigned int minor) | 
|  | { | 
|  | return ((major & 0xfff) << 8) | (minor & 0xff); | 
|  | } |