2018-09-09 13:26:04 +02:00
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
/* nolibc.h
* Copyright ( C ) 2017 - 2018 Willy Tarreau < w @ 1 wt . eu >
*/
2018-12-29 19:02:18 +01:00
/*
* 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 \
2021-01-21 08:20:31 +01:00
* - static - include nolibc . h - o hello hello . c - lgcc
2018-12-29 19:02:18 +01:00
*
* 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/
*
*/
2018-09-09 13:26:04 +02:00
# include <asm/unistd.h>
# include <asm/ioctls.h>
# include <asm/errno.h>
# include <linux/fs.h>
# include <linux/loop.h>
2021-01-21 08:20:28 +01:00
# include <linux/time.h>
2018-09-09 13:26:04 +02:00
# 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
2020-10-20 21:22:56 +02:00
* because they all correspond to the highest addressable memory page .
2018-09-09 13:26:04 +02:00
*/
# 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 {
2018-12-29 19:02:17 +01:00
int fd ;
short int events ;
short int revents ;
2018-09-09 13:26:04 +02:00
} ;
/* 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 */
2020-10-11 14:22:31 -04:00
# ifndef AT_FDCWD
2018-09-09 13:26:04 +02:00
# 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)
2021-01-21 08:20:26 +01:00
/* for SIGCHLD */
# include <asm/signal.h>
2018-09-09 13:26:04 +02:00
/* 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 ) \
2018-12-29 19:02:17 +01:00
: " rcx " , " r8 " , " r9 " , " r10 " , " r11 " , " memory " , " cc " \
2018-09-09 13:26:04 +02:00
) ; \
_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 ) \
2018-12-29 19:02:17 +01:00
: " rcx " , " r8 " , " r9 " , " r10 " , " r11 " , " memory " , " cc " \
2018-09-09 13:26:04 +02:00
) ; \
_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 ) \
2018-12-29 19:02:17 +01:00
: " rcx " , " r8 " , " r9 " , " r10 " , " r11 " , " memory " , " cc " \
2018-09-09 13:26:04 +02:00
) ; \
_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 ) \
2018-12-29 19:02:17 +01:00
: " rcx " , " r8 " , " r9 " , " r10 " , " r11 " , " memory " , " cc " \
2018-09-09 13:26:04 +02:00
) ; \
_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 " , \
2018-12-29 19:02:16 +01:00
" t0 " , " t1 " , " t2 " , " t3 " , " t4 " , " t5 " , " t6 " , " t7 " , " t8 " , " t9 " \
2018-09-09 13:26:04 +02:00
) ; \
_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 " , \
2018-12-29 19:02:16 +01:00
" t0 " , " t1 " , " t2 " , " t3 " , " t4 " , " t5 " , " t6 " , " t7 " , " t8 " , " t9 " \
2018-09-09 13:26:04 +02:00
) ; \
_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 " , \
2018-12-29 19:02:16 +01:00
" t0 " , " t1 " , " t2 " , " t3 " , " t4 " , " t5 " , " t6 " , " t7 " , " t8 " , " t9 " \
2018-09-09 13:26:04 +02:00
) ; \
_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 " , \
2018-12-29 19:02:16 +01:00
" t0 " , " t1 " , " t2 " , " t3 " , " t4 " , " t5 " , " t6 " , " t7 " , " t8 " , " t9 " \
2018-09-09 13:26:04 +02:00
) ; \
_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 " , \
2018-12-29 19:02:16 +01:00
" t0 " , " t1 " , " t2 " , " t3 " , " t4 " , " t5 " , " t6 " , " t7 " , " t8 " , " t9 " \
2018-09-09 13:26:04 +02:00
) ; \
_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 " , \
2018-12-29 19:02:16 +01:00
" t0 " , " t1 " , " t2 " , " t3 " , " t4 " , " t5 " , " t6 " , " t7 " , " t8 " , " t9 " \
2018-09-09 13:26:04 +02:00
) ; \
_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 ] ;
} ;
2019-03-04 11:11:44 -08:00
# 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 ;
} ;
2018-09-09 13:26:04 +02:00
# 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 ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR_chmod)
2018-09-09 13:26:04 +02:00
return my_syscall2 ( __NR_chmod , path , mode ) ;
2021-01-21 08:20:30 +01:00
# else
# error Neither __NR_fchmodat nor __NR_chmod defined, cannot implement sys_chmod()
2018-09-09 13:26:04 +02:00
# 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 ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR_chown)
2018-09-09 13:26:04 +02:00
return my_syscall3 ( __NR_chown , path , owner , group ) ;
2021-01-21 08:20:30 +01:00
# else
# error Neither __NR_fchownat nor __NR_chown defined, cannot implement sys_chown()
2018-09-09 13:26:04 +02:00
# 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 ) ;
}
2021-01-21 08:20:24 +01:00
# ifdef __NR_dup3
static __attribute__ ( ( unused ) )
int sys_dup3 ( int old , int new , int flags )
{
return my_syscall3 ( __NR_dup3 , old , new , flags ) ;
}
# endif
2018-09-09 13:26:04 +02:00
static __attribute__ ( ( unused ) )
int sys_dup2 ( int old , int new )
{
2021-01-21 08:20:24 +01:00
# ifdef __NR_dup3
return my_syscall3 ( __NR_dup3 , old , new , 0 ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR_dup2)
2018-09-09 13:26:04 +02:00
return my_syscall2 ( __NR_dup2 , old , new ) ;
2021-01-21 08:20:30 +01:00
# else
# error Neither __NR_dup3 nor __NR_dup2 defined, cannot implement sys_dup2()
2021-01-21 08:20:24 +01:00
# endif
2018-09-09 13:26:04 +02:00
}
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 )
{
2021-01-21 08:20:26 +01:00
# ifdef __NR_clone
/* note: some archs only have clone() and not fork(). Different archs
* have a different API , but most archs have the flags on first arg and
* will not use the rest with no other flag .
*/
return my_syscall5 ( __NR_clone , SIGCHLD , 0 , 0 , 0 , 0 ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR_fork)
2018-09-09 13:26:04 +02:00
return my_syscall0 ( __NR_fork ) ;
2021-01-21 08:20:30 +01:00
# else
# error Neither __NR_clone nor __NR_fork defined, cannot implement sys_fork()
2021-01-21 08:20:26 +01:00
# endif
2018-09-09 13:26:04 +02:00
}
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 ) ;
}
2021-01-21 08:20:25 +01:00
static __attribute__ ( ( unused ) )
pid_t sys_getpgid ( pid_t pid )
{
return my_syscall1 ( __NR_getpgid , pid ) ;
}
2018-09-09 13:26:04 +02:00
static __attribute__ ( ( unused ) )
pid_t sys_getpgrp ( void )
{
2021-01-21 08:20:25 +01:00
return sys_getpgid ( 0 ) ;
2018-09-09 13:26:04 +02:00
}
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 ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR_link)
2018-09-09 13:26:04 +02:00
return my_syscall2 ( __NR_link , old , new ) ;
2021-01-21 08:20:30 +01:00
# else
# error Neither __NR_linkat nor __NR_link defined, cannot implement sys_link()
2018-09-09 13:26:04 +02:00
# 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 ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR_mkdir)
2018-09-09 13:26:04 +02:00
return my_syscall2 ( __NR_mkdir , path , mode ) ;
2021-01-21 08:20:30 +01:00
# else
# error Neither __NR_mkdirat nor __NR_mkdir defined, cannot implement sys_mkdir()
2018-09-09 13:26:04 +02:00
# 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 ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR_mknod)
2018-09-09 13:26:04 +02:00
return my_syscall3 ( __NR_mknod , path , mode , dev ) ;
2021-01-21 08:20:30 +01:00
# else
# error Neither __NR_mknodat nor __NR_mknod defined, cannot implement sys_mknod()
2018-09-09 13:26:04 +02:00
# 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 ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR_open)
2018-09-09 13:26:04 +02:00
return my_syscall3 ( __NR_open , path , flags , mode ) ;
2021-01-21 08:20:30 +01:00
# else
# error Neither __NR_openat nor __NR_open defined, cannot implement sys_open()
2018-09-09 13:26:04 +02:00
# 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 )
{
2021-01-21 08:20:27 +01:00
# if defined(__NR_ppoll)
struct timespec t ;
if ( timeout > = 0 ) {
t . tv_sec = timeout / 1000 ;
t . tv_nsec = ( timeout % 1000 ) * 1000000 ;
}
return my_syscall4 ( __NR_ppoll , fds , nfds , ( timeout > = 0 ) ? & t : NULL , NULL ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR_poll)
2018-09-09 13:26:04 +02:00
return my_syscall3 ( __NR_poll , fds , nfds , timeout ) ;
2021-01-21 08:20:30 +01:00
# else
# error Neither __NR_ppoll nor __NR_poll defined, cannot implement sys_poll()
2021-01-21 08:20:27 +01:00
# endif
2018-09-09 13:26:04 +02:00
}
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 ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR__newselect) || defined(__NR_select)
2018-09-09 13:26:04 +02:00
# ifndef __NR__newselect
# define __NR__newselect __NR_select
# endif
return my_syscall5 ( __NR__newselect , nfds , rfds , wfds , efds , timeout ) ;
2021-01-21 08:20:30 +01:00
# else
# error None of __NR_select, __NR_pselect6, nor __NR__newselect defined, cannot implement sys_select()
2018-09-09 13:26:04 +02:00
# 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 ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR_stat)
2018-09-09 13:26:04 +02:00
ret = my_syscall2 ( __NR_stat , path , & stat ) ;
2021-01-21 08:20:30 +01:00
# else
# error Neither __NR_newfstatat nor __NR_stat defined, cannot implement sys_stat()
2018-09-09 13:26:04 +02:00
# 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 ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR_symlink)
2018-09-09 13:26:04 +02:00
return my_syscall2 ( __NR_symlink , old , new ) ;
2021-01-21 08:20:30 +01:00
# else
# error Neither __NR_symlinkat nor __NR_symlink defined, cannot implement sys_symlink()
2018-09-09 13:26:04 +02:00
# 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 ) ;
2021-01-21 08:20:30 +01:00
# elif defined(__NR_unlink)
2018-09-09 13:26:04 +02:00
return my_syscall1 ( __NR_unlink , path ) ;
2021-01-21 08:20:30 +01:00
# else
# error Neither __NR_unlinkat nor __NR_unlink defined, cannot implement sys_unlink()
2018-09-09 13:26:04 +02:00
# 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 ;
}
2021-01-21 08:20:23 +01:00
static __attribute__ ( ( unused ) )
int dup ( int fd )
{
int ret = sys_dup ( fd ) ;
if ( ret < 0 ) {
SET_ERRNO ( - ret ) ;
ret = - 1 ;
}
return ret ;
}
2018-09-09 13:26:04 +02:00
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 ;
}
2021-01-21 08:20:24 +01:00
# ifdef __NR_dup3
static __attribute__ ( ( unused ) )
int dup3 ( int old , int new , int flags )
{
int ret = sys_dup3 ( old , new , flags ) ;
if ( ret < 0 ) {
SET_ERRNO ( - ret ) ;
ret = - 1 ;
}
return ret ;
}
# endif
2018-09-09 13:26:04 +02:00
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 ;
}
2021-01-21 08:20:25 +01:00
static __attribute__ ( ( unused ) )
pid_t getpgid ( pid_t pid )
{
pid_t ret = sys_getpgid ( pid ) ;
if ( ret < 0 ) {
SET_ERRNO ( - ret ) ;
ret = - 1 ;
}
return ret ;
}
2018-09-09 13:26:04 +02:00
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 ) ;
}