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
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
* - rcx and r11 are clobbered , others are preserved .
2018-09-09 13:26:04 +02:00
* - 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 ) .
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
* - see also x86 - 64 ABI section A .2 AMD64 Linux Kernel Conventions , A .2 .1
* Calling Conventions .
*
* Link x86 - 64 ABI : https : //gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI
*
2018-09-09 13:26:04 +02:00
*/
# define my_syscall0(num) \
( { \
long _ret ; \
register long _num asm ( " rax " ) = ( num ) ; \
\
asm volatile ( \
" syscall \n " \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " =a " ( _ret ) \
2018-09-09 13:26:04 +02:00
: " 0 " ( _num ) \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " rcx " , " 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 " \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " =a " ( _ret ) \
2018-09-09 13:26:04 +02:00
: " r " ( _arg1 ) , \
" 0 " ( _num ) \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " rcx " , " 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 " \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " =a " ( _ret ) \
2018-09-09 13:26:04 +02:00
: " r " ( _arg1 ) , " r " ( _arg2 ) , \
" 0 " ( _num ) \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " rcx " , " 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 " \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " =a " ( _ret ) \
2018-09-09 13:26:04 +02:00
: " r " ( _arg1 ) , " r " ( _arg2 ) , " r " ( _arg3 ) , \
" 0 " ( _num ) \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " rcx " , " 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 " \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " =a " ( _ret ) \
2018-09-09 13:26:04 +02:00
: " r " ( _arg1 ) , " r " ( _arg2 ) , " r " ( _arg3 ) , " r " ( _arg4 ) , \
" 0 " ( _num ) \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " rcx " , " r11 " , " memory " , " cc " \
2018-09-09 13:26:04 +02:00
) ; \
_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 " \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " =a " ( _ret ) \
2018-09-09 13:26:04 +02:00
: " r " ( _arg1 ) , " r " ( _arg2 ) , " r " ( _arg3 ) , " r " ( _arg4 ) , " r " ( _arg5 ) , \
" 0 " ( _num ) \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " rcx " , " r11 " , " memory " , " cc " \
2018-09-09 13:26:04 +02:00
) ; \
_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 " \
tools/nolibc: x86: Remove `r8`, `r9` and `r10` from the clobber list
Linux x86-64 syscall only clobbers rax, rcx and r11 (and "memory").
- rax for the return value.
- rcx to save the return address.
- r11 to save the rflags.
Other registers are preserved.
Having r8, r9 and r10 in the syscall clobber list is harmless, but this
results in a missed-optimization.
As the syscall doesn't clobber r8-r10, GCC should be allowed to reuse
their value after the syscall returns to userspace. But since they are
in the clobber list, GCC will always miss this opportunity.
Remove them from the x86-64 syscall clobber list to help GCC generate
better code and fix the comment.
See also the x86-64 ABI, section A.2 AMD64 Linux Kernel Conventions,
A.2.1 Calling Conventions [1].
Extra note:
Some people may think it does not really give a benefit to remove r8,
r9 and r10 from the syscall clobber list because the impression of
syscall is a C function call, and function call always clobbers those 3.
However, that is not the case for nolibc.h, because we have a potential
to inline the "syscall" instruction (which its opcode is "0f 05") to the
user functions.
All syscalls in the nolibc.h are written as a static function with inline
ASM and are likely always inline if we use optimization flag, so this is
a profit not to have r8, r9 and r10 in the clobber list.
Here is the example where this matters.
Consider the following C code:
```
#include "tools/include/nolibc/nolibc.h"
#define read_abc(a, b, c) __asm__ volatile("nop"::"r"(a),"r"(b),"r"(c))
int main(void)
{
int a = 0xaa;
int b = 0xbb;
int c = 0xcc;
read_abc(a, b, c);
write(1, "test\n", 5);
read_abc(a, b, c);
return 0;
}
```
Compile with:
gcc -Os test.c -o test -nostdlib
With r8, r9, r10 in the clobber list, GCC generates this:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 54 push %r12
1006: 41 bc cc 00 00 00 mov $0xcc,%r12d
100c: 55 push %rbp
100d: bd bb 00 00 00 mov $0xbb,%ebp
1012: 53 push %rbx
1013: bb aa 00 00 00 mov $0xaa,%ebx
1018: 90 nop
1019: b8 01 00 00 00 mov $0x1,%eax
101e: bf 01 00 00 00 mov $0x1,%edi
1023: ba 05 00 00 00 mov $0x5,%edx
1028: 48 8d 35 d1 0f 00 00 lea 0xfd1(%rip),%rsi
102f: 0f 05 syscall
1031: 90 nop
1032: 31 c0 xor %eax,%eax
1034: 5b pop %rbx
1035: 5d pop %rbp
1036: 41 5c pop %r12
1038: c3 ret
GCC thinks that syscall will clobber r8, r9, r10. So it spills 0xaa,
0xbb and 0xcc to callee saved registers (r12, rbp and rbx). This is
clearly extra memory access and extra stack size for preserving them.
But syscall does not actually clobber them, so this is a missed
optimization.
Now without r8, r9, r10 in the clobber list, GCC generates better code:
0000000000001000 <main>:
1000: f3 0f 1e fa endbr64
1004: 41 b8 aa 00 00 00 mov $0xaa,%r8d
100a: 41 b9 bb 00 00 00 mov $0xbb,%r9d
1010: 41 ba cc 00 00 00 mov $0xcc,%r10d
1016: 90 nop
1017: b8 01 00 00 00 mov $0x1,%eax
101c: bf 01 00 00 00 mov $0x1,%edi
1021: ba 05 00 00 00 mov $0x5,%edx
1026: 48 8d 35 d3 0f 00 00 lea 0xfd3(%rip),%rsi
102d: 0f 05 syscall
102f: 90 nop
1030: 31 c0 xor %eax,%eax
1032: c3 ret
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: x86@kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: David Laight <David.Laight@ACULAB.COM>
Acked-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
Link: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI [1]
Link: https://lore.kernel.org/lkml/20211011040344.437264-1-ammar.faizi@students.amikom.ac.id/
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:43:21 +02:00
: " =a " ( _ret ) \
2018-09-09 13:26:04 +02:00
: " r " ( _arg1 ) , " r " ( _arg2 ) , " r " ( _arg3 ) , " r " ( _arg4 ) , " r " ( _arg5 ) , \
" r " ( _arg6 ) , " 0 " ( _num ) \
: " rcx " , " r11 " , " memory " , " cc " \
) ; \
_ret ; \
} )
/* startup code */
tools/nolibc: x86-64: Fix startup code bug
Before this patch, the `_start` function looks like this:
```
0000000000001170 <_start>:
1170: pop %rdi
1171: mov %rsp,%rsi
1174: lea 0x8(%rsi,%rdi,8),%rdx
1179: and $0xfffffffffffffff0,%rsp
117d: sub $0x8,%rsp
1181: call 1000 <main>
1186: movzbq %al,%rdi
118a: mov $0x3c,%rax
1191: syscall
1193: hlt
1194: data16 cs nopw 0x0(%rax,%rax,1)
119f: nop
```
Note the "and" to %rsp with $-16, it makes the %rsp be 16-byte aligned,
but then there is a "sub" with $0x8 which makes the %rsp no longer
16-byte aligned, then it calls main. That's the bug!
What actually the x86-64 System V ABI mandates is that right before the
"call", the %rsp must be 16-byte aligned, not after the "call". So the
"sub" with $0x8 here breaks the alignment. Remove it.
An example where this rule matters is when the callee needs to align
its stack at 16-byte for aligned move instruction, like `movdqa` and
`movaps`. If the callee can't align its stack properly, it will result
in segmentation fault.
x86-64 System V ABI also mandates the deepest stack frame should be
zero. Just to be safe, let's zero the %rbp on startup as the content
of %rbp may be unspecified when the program starts. Now it looks like
this:
```
0000000000001170 <_start>:
1170: pop %rdi
1171: mov %rsp,%rsi
1174: lea 0x8(%rsi,%rdi,8),%rdx
1179: xor %ebp,%ebp # zero the %rbp
117b: and $0xfffffffffffffff0,%rsp # align the %rsp
117f: call 1000 <main>
1184: movzbq %al,%rdi
1188: mov $0x3c,%rax
118f: syscall
1191: hlt
1192: data16 cs nopw 0x0(%rax,%rax,1)
119d: nopl (%rax)
```
Cc: Bedirhan KURT <windowz414@gnuweeb.org>
Cc: Louvian Lyndal <louvianlyndal@gmail.com>
Reported-by: Peter Cordes <peter@cordes.ca>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
[wt: I did this on purpose due to a misunderstanding of the spec, other
archs will thus have to be rechecked, particularly i386]
Cc: stable@vger.kernel.org
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:28:14 +02:00
/*
* x86 - 64 System V ABI mandates :
* 1 ) % rsp must be 16 - byte aligned right before the function call .
* 2 ) The deepest stack frame should be zero ( the % rbp ) .
*
*/
2018-09-09 13:26:04 +02:00
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)
tools/nolibc: x86-64: Fix startup code bug
Before this patch, the `_start` function looks like this:
```
0000000000001170 <_start>:
1170: pop %rdi
1171: mov %rsp,%rsi
1174: lea 0x8(%rsi,%rdi,8),%rdx
1179: and $0xfffffffffffffff0,%rsp
117d: sub $0x8,%rsp
1181: call 1000 <main>
1186: movzbq %al,%rdi
118a: mov $0x3c,%rax
1191: syscall
1193: hlt
1194: data16 cs nopw 0x0(%rax,%rax,1)
119f: nop
```
Note the "and" to %rsp with $-16, it makes the %rsp be 16-byte aligned,
but then there is a "sub" with $0x8 which makes the %rsp no longer
16-byte aligned, then it calls main. That's the bug!
What actually the x86-64 System V ABI mandates is that right before the
"call", the %rsp must be 16-byte aligned, not after the "call". So the
"sub" with $0x8 here breaks the alignment. Remove it.
An example where this rule matters is when the callee needs to align
its stack at 16-byte for aligned move instruction, like `movdqa` and
`movaps`. If the callee can't align its stack properly, it will result
in segmentation fault.
x86-64 System V ABI also mandates the deepest stack frame should be
zero. Just to be safe, let's zero the %rbp on startup as the content
of %rbp may be unspecified when the program starts. Now it looks like
this:
```
0000000000001170 <_start>:
1170: pop %rdi
1171: mov %rsp,%rsi
1174: lea 0x8(%rsi,%rdi,8),%rdx
1179: xor %ebp,%ebp # zero the %rbp
117b: and $0xfffffffffffffff0,%rsp # align the %rsp
117f: call 1000 <main>
1184: movzbq %al,%rdi
1188: mov $0x3c,%rax
118f: syscall
1191: hlt
1192: data16 cs nopw 0x0(%rax,%rax,1)
119d: nopl (%rax)
```
Cc: Bedirhan KURT <windowz414@gnuweeb.org>
Cc: Louvian Lyndal <louvianlyndal@gmail.com>
Reported-by: Peter Cordes <peter@cordes.ca>
Signed-off-by: Ammar Faizi <ammar.faizi@students.amikom.ac.id>
[wt: I did this on purpose due to a misunderstanding of the spec, other
archs will thus have to be rechecked, particularly i386]
Cc: stable@vger.kernel.org
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
2021-10-24 19:28:14 +02:00
" xor %ebp, %ebp \n " // zero the stack frame
" and $-16, %rsp \n " // x86 ABI : esp must be 16-byte aligned before call
2018-09-09 13:26:04 +02:00
" call main \n " // main() returns the status code, we'll exit with it.
2021-10-24 19:28:16 +02:00
" mov %eax, %edi \n " // retrieve exit code (32 bit)
2021-10-24 19:43:22 +02:00
" mov $60, %eax \n " // NR_exit == 60
2018-09-09 13:26:04 +02:00
" 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 */
2021-10-24 19:28:15 +02:00
/*
* i386 System V ABI mandates :
* 1 ) last pushed argument must be 16 - byte aligned .
* 2 ) The deepest stack frame should be set to zero
*
*/
2018-09-09 13:26:04 +02:00
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)
2021-10-24 19:28:15 +02:00
" xor %ebp, %ebp \n " // zero the stack frame
" and $-16, %esp \n " // x86 ABI : esp must be 16-byte aligned before
" sub $4, %esp \n " // the call instruction (args are aligned)
2018-09-09 13:26:04 +02:00
" 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
2021-10-24 19:28:16 +02:00
" mov %eax, %ebx \n " // retrieve exit code (32-bit int)
" movl $1, %eax \n " // NR_exit == 1
" int $0x80 \n " // exit now
2018-09-09 13:26:04 +02:00
" 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.
" 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.
" 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
2021-06-24 08:53:13 +02:00
* if an error occurred , in which case errno is in v0 .
2018-09-09 13:26:04 +02:00
* - 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
2021-10-24 19:28:16 +02:00
" move $a0, $v0 \n " // retrieve 32-bit exit code from v0
2018-09-09 13:26:04 +02:00
" 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.
" 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 ) ;
}
2021-10-24 19:43:23 +02:00
static __attribute__ ( ( unused ) )
pid_t sys_gettid ( void )
{
return my_syscall0 ( __NR_gettid ) ;
}
2018-09-09 13:26:04 +02:00
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 ;
}
2021-10-24 19:43:23 +02:00
static __attribute__ ( ( unused ) )
pid_t gettid ( void )
{
pid_t ret = sys_gettid ( ) ;
if ( ret < 0 ) {
SET_ERRNO ( - ret ) ;
ret = - 1 ;
}
return ret ;
}
2018-09-09 13:26:04 +02:00
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 ;
}
2021-06-24 08:53:14 +02:00
static __attribute__ ( ( unused ) )
int msleep ( unsigned int msecs )
{
struct timeval my_timeval = { msecs / 1000 , ( msecs % 1000 ) * 1000 } ;
if ( sys_select ( 0 , 0 , 0 , 0 , & my_timeval ) < 0 )
return ( my_timeval . tv_sec * 1000 ) +
( my_timeval . tv_usec / 1000 ) +
! ! ( my_timeval . tv_usec % 1000 ) ;
else
return 0 ;
}
2018-09-09 13:26:04 +02:00
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 ) ;
}