166b6f755SWilly Tarreau/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
266b6f755SWilly Tarreau/* nolibc.h
366b6f755SWilly Tarreau * Copyright (C) 2017-2018 Willy Tarreau <w@1wt.eu>
466b6f755SWilly Tarreau */
566b6f755SWilly Tarreau
6cc72a509SWilly Tarreau/*
7cc72a509SWilly Tarreau * This file is designed to be used as a libc alternative for minimal programs
8cc72a509SWilly Tarreau * with very limited requirements. It consists of a small number of syscall and
9cc72a509SWilly Tarreau * type definitions, and the minimal startup code needed to call main().
10cc72a509SWilly Tarreau * All syscalls are declared as static functions so that they can be optimized
11cc72a509SWilly Tarreau * away by the compiler when not used.
12cc72a509SWilly Tarreau *
13cc72a509SWilly Tarreau * Syscalls are split into 3 levels:
14cc72a509SWilly Tarreau *   - The lower level is the arch-specific syscall() definition, consisting in
15cc72a509SWilly Tarreau *     assembly code in compound expressions. These are called my_syscall0() to
16cc72a509SWilly Tarreau *     my_syscall6() depending on the number of arguments. The MIPS
17cc72a509SWilly Tarreau *     implementation is limited to 5 arguments. All input arguments are cast
18cc72a509SWilly Tarreau *     to a long stored in a register. These expressions always return the
19cc72a509SWilly Tarreau *     syscall's return value as a signed long value which is often either a
20cc72a509SWilly Tarreau *     pointer or the negated errno value.
21cc72a509SWilly Tarreau *
22cc72a509SWilly Tarreau *   - The second level is mostly architecture-independent. It is made of
23cc72a509SWilly Tarreau *     static functions called sys_<name>() which rely on my_syscallN()
24cc72a509SWilly Tarreau *     depending on the syscall definition. These functions are responsible
25cc72a509SWilly Tarreau *     for exposing the appropriate types for the syscall arguments (int,
26cc72a509SWilly Tarreau *     pointers, etc) and for setting the appropriate return type (often int).
27cc72a509SWilly Tarreau *     A few of them are architecture-specific because the syscalls are not all
28cc72a509SWilly Tarreau *     mapped exactly the same among architectures. For example, some archs do
29cc72a509SWilly Tarreau *     not implement select() and need pselect6() instead, so the sys_select()
30cc72a509SWilly Tarreau *     function will have to abstract this.
31cc72a509SWilly Tarreau *
32cc72a509SWilly Tarreau *   - The third level is the libc call definition. It exposes the lower raw
33cc72a509SWilly Tarreau *     sys_<name>() calls in a way that looks like what a libc usually does,
34cc72a509SWilly Tarreau *     takes care of specific input values, and of setting errno upon error.
35cc72a509SWilly Tarreau *     There can be minor variations compared to standard libc calls. For
36cc72a509SWilly Tarreau *     example the open() call always takes 3 args here.
37cc72a509SWilly Tarreau *
38cc72a509SWilly Tarreau * The errno variable is declared static and unused. This way it can be
39cc72a509SWilly Tarreau * optimized away if not used. However this means that a program made of
40cc72a509SWilly Tarreau * multiple C files may observe different errno values (one per C file). For
41cc72a509SWilly Tarreau * the type of programs this project targets it usually is not a problem. The
42cc72a509SWilly Tarreau * resulting program may even be reduced by defining the NOLIBC_IGNORE_ERRNO
43cc72a509SWilly Tarreau * macro, in which case the errno value will never be assigned.
44cc72a509SWilly Tarreau *
45cc72a509SWilly Tarreau * Some stdint-like integer types are defined. These are valid on all currently
46cc72a509SWilly Tarreau * supported architectures, because signs are enforced, ints are assumed to be
47cc72a509SWilly Tarreau * 32 bits, longs the size of a pointer and long long 64 bits. If more
48cc72a509SWilly Tarreau * architectures have to be supported, this may need to be adapted.
49cc72a509SWilly Tarreau *
50cc72a509SWilly Tarreau * Some macro definitions like the O_* values passed to open(), and some
51cc72a509SWilly Tarreau * structures like the sys_stat struct depend on the architecture.
52cc72a509SWilly Tarreau *
53cc72a509SWilly Tarreau * The definitions start with the architecture-specific parts, which are picked
54cc72a509SWilly Tarreau * based on what the compiler knows about the target architecture, and are
55cc72a509SWilly Tarreau * completed with the generic code. Since it is the compiler which sets the
56cc72a509SWilly Tarreau * target architecture, cross-compiling normally works out of the box without
57cc72a509SWilly Tarreau * having to specify anything.
58cc72a509SWilly Tarreau *
59cc72a509SWilly Tarreau * Finally some very common libc-level functions are provided. It is the case
60cc72a509SWilly Tarreau * for a few functions usually found in string.h, ctype.h, or stdlib.h. Nothing
61cc72a509SWilly Tarreau * is currently provided regarding stdio emulation.
62cc72a509SWilly Tarreau *
63cc72a509SWilly Tarreau * The macro NOLIBC is always defined, so that it is possible for a program to
64cc72a509SWilly Tarreau * check this macro to know if it is being built against and decide to disable
65cc72a509SWilly Tarreau * some features or simply not to include some standard libc files.
66cc72a509SWilly Tarreau *
67cc72a509SWilly Tarreau * Ideally this file should be split in multiple files for easier long term
68cc72a509SWilly Tarreau * maintenance, but provided as a single file as it is now, it's quite
69cc72a509SWilly Tarreau * convenient to use. Maybe some variations involving a set of includes at the
70cc72a509SWilly Tarreau * top could work.
71cc72a509SWilly Tarreau *
72cc72a509SWilly Tarreau * A simple static executable may be built this way :
73cc72a509SWilly Tarreau *      $ gcc -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \
743c6ce7a5SWilly Tarreau *            -static -include nolibc.h -o hello hello.c -lgcc
75cc72a509SWilly Tarreau *
76cc72a509SWilly Tarreau * A very useful calling convention table may be found here :
77cc72a509SWilly Tarreau *      http://man7.org/linux/man-pages/man2/syscall.2.html
78cc72a509SWilly Tarreau *
79cc72a509SWilly Tarreau * This doc is quite convenient though not necessarily up to date :
80cc72a509SWilly Tarreau *      https://w3challs.com/syscalls/
81cc72a509SWilly Tarreau *
82cc72a509SWilly Tarreau */
83cc72a509SWilly Tarreau
8466b6f755SWilly Tarreau#include <asm/unistd.h>
8566b6f755SWilly Tarreau#include <asm/ioctls.h>
8666b6f755SWilly Tarreau#include <asm/errno.h>
8766b6f755SWilly Tarreau#include <linux/fs.h>
8866b6f755SWilly Tarreau#include <linux/loop.h>
8970ca7aeaSWilly Tarreau#include <linux/time.h>
9066b6f755SWilly Tarreau
9166b6f755SWilly Tarreau#define NOLIBC
9266b6f755SWilly Tarreau
9366b6f755SWilly Tarreau/* this way it will be removed if unused */
9466b6f755SWilly Tarreaustatic int errno;
9566b6f755SWilly Tarreau
9666b6f755SWilly Tarreau#ifndef NOLIBC_IGNORE_ERRNO
9766b6f755SWilly Tarreau#define SET_ERRNO(v) do { errno = (v); } while (0)
9866b6f755SWilly Tarreau#else
9966b6f755SWilly Tarreau#define SET_ERRNO(v) do { } while (0)
10066b6f755SWilly Tarreau#endif
10166b6f755SWilly Tarreau
10266b6f755SWilly Tarreau/* errno codes all ensure that they will not conflict with a valid pointer
10306dc8d45SBhaskar Chowdhury * because they all correspond to the highest addressable memory page.
10466b6f755SWilly Tarreau */
10566b6f755SWilly Tarreau#define MAX_ERRNO 4095
10666b6f755SWilly Tarreau
10766b6f755SWilly Tarreau/* Declare a few quite common macros and types that usually are in stdlib.h,
10866b6f755SWilly Tarreau * stdint.h, ctype.h, unistd.h and a few other common locations.
10966b6f755SWilly Tarreau */
11066b6f755SWilly Tarreau
11166b6f755SWilly Tarreau#define NULL ((void *)0)
11266b6f755SWilly Tarreau
11366b6f755SWilly Tarreau/* stdint types */
11466b6f755SWilly Tarreautypedef unsigned char       uint8_t;
11566b6f755SWilly Tarreautypedef   signed char        int8_t;
11666b6f755SWilly Tarreautypedef unsigned short     uint16_t;
11766b6f755SWilly Tarreautypedef   signed short      int16_t;
11866b6f755SWilly Tarreautypedef unsigned int       uint32_t;
11966b6f755SWilly Tarreautypedef   signed int        int32_t;
12066b6f755SWilly Tarreautypedef unsigned long long uint64_t;
12166b6f755SWilly Tarreautypedef   signed long long  int64_t;
12266b6f755SWilly Tarreautypedef unsigned long        size_t;
12366b6f755SWilly Tarreautypedef   signed long       ssize_t;
12466b6f755SWilly Tarreautypedef unsigned long     uintptr_t;
12566b6f755SWilly Tarreautypedef   signed long      intptr_t;
12666b6f755SWilly Tarreautypedef   signed long     ptrdiff_t;
12766b6f755SWilly Tarreau
12866b6f755SWilly Tarreau/* for stat() */
12966b6f755SWilly Tarreautypedef unsigned int          dev_t;
13066b6f755SWilly Tarreautypedef unsigned long         ino_t;
13166b6f755SWilly Tarreautypedef unsigned int         mode_t;
13266b6f755SWilly Tarreautypedef   signed int          pid_t;
13366b6f755SWilly Tarreautypedef unsigned int          uid_t;
13466b6f755SWilly Tarreautypedef unsigned int          gid_t;
13566b6f755SWilly Tarreautypedef unsigned long       nlink_t;
13666b6f755SWilly Tarreautypedef   signed long         off_t;
13766b6f755SWilly Tarreautypedef   signed long     blksize_t;
13866b6f755SWilly Tarreautypedef   signed long      blkcnt_t;
13966b6f755SWilly Tarreautypedef   signed long        time_t;
14066b6f755SWilly Tarreau
14166b6f755SWilly Tarreau/* for poll() */
14266b6f755SWilly Tarreaustruct pollfd {
14385ebb12cSWilly Tarreau	int fd;
14485ebb12cSWilly Tarreau	short int events;
14585ebb12cSWilly Tarreau	short int revents;
14666b6f755SWilly Tarreau};
14766b6f755SWilly Tarreau
14866b6f755SWilly Tarreau/* for getdents64() */
14966b6f755SWilly Tarreaustruct linux_dirent64 {
15066b6f755SWilly Tarreau	uint64_t       d_ino;
15166b6f755SWilly Tarreau	int64_t        d_off;
15266b6f755SWilly Tarreau	unsigned short d_reclen;
15366b6f755SWilly Tarreau	unsigned char  d_type;
15466b6f755SWilly Tarreau	char           d_name[];
15566b6f755SWilly Tarreau};
15666b6f755SWilly Tarreau
15766b6f755SWilly Tarreau/* commonly an fd_set represents 256 FDs */
15866b6f755SWilly Tarreau#define FD_SETSIZE 256
15966b6f755SWilly Tarreautypedef struct { uint32_t fd32[FD_SETSIZE/32]; } fd_set;
16066b6f755SWilly Tarreau
16166b6f755SWilly Tarreau/* needed by wait4() */
16266b6f755SWilly Tarreaustruct rusage {
16366b6f755SWilly Tarreau	struct timeval ru_utime;
16466b6f755SWilly Tarreau	struct timeval ru_stime;
16566b6f755SWilly Tarreau	long   ru_maxrss;
16666b6f755SWilly Tarreau	long   ru_ixrss;
16766b6f755SWilly Tarreau	long   ru_idrss;
16866b6f755SWilly Tarreau	long   ru_isrss;
16966b6f755SWilly Tarreau	long   ru_minflt;
17066b6f755SWilly Tarreau	long   ru_majflt;
17166b6f755SWilly Tarreau	long   ru_nswap;
17266b6f755SWilly Tarreau	long   ru_inblock;
17366b6f755SWilly Tarreau	long   ru_oublock;
17466b6f755SWilly Tarreau	long   ru_msgsnd;
17566b6f755SWilly Tarreau	long   ru_msgrcv;
17666b6f755SWilly Tarreau	long   ru_nsignals;
17766b6f755SWilly Tarreau	long   ru_nvcsw;
17866b6f755SWilly Tarreau	long   ru_nivcsw;
17966b6f755SWilly Tarreau};
18066b6f755SWilly Tarreau
18166b6f755SWilly Tarreau/* stat flags (WARNING, octal here) */
18266b6f755SWilly Tarreau#define S_IFDIR       0040000
18366b6f755SWilly Tarreau#define S_IFCHR       0020000
18466b6f755SWilly Tarreau#define S_IFBLK       0060000
18566b6f755SWilly Tarreau#define S_IFREG       0100000
18666b6f755SWilly Tarreau#define S_IFIFO       0010000
18766b6f755SWilly Tarreau#define S_IFLNK       0120000
18866b6f755SWilly Tarreau#define S_IFSOCK      0140000
18966b6f755SWilly Tarreau#define S_IFMT        0170000
19066b6f755SWilly Tarreau
19166b6f755SWilly Tarreau#define S_ISDIR(mode)  (((mode) & S_IFDIR) == S_IFDIR)
19266b6f755SWilly Tarreau#define S_ISCHR(mode)  (((mode) & S_IFCHR) == S_IFCHR)
19366b6f755SWilly Tarreau#define S_ISBLK(mode)  (((mode) & S_IFBLK) == S_IFBLK)
19466b6f755SWilly Tarreau#define S_ISREG(mode)  (((mode) & S_IFREG) == S_IFREG)
19566b6f755SWilly Tarreau#define S_ISFIFO(mode) (((mode) & S_IFIFO) == S_IFIFO)
19666b6f755SWilly Tarreau#define S_ISLNK(mode)  (((mode) & S_IFLNK) == S_IFLNK)
19766b6f755SWilly Tarreau#define S_ISSOCK(mode) (((mode) & S_IFSOCK) == S_IFSOCK)
19866b6f755SWilly Tarreau
19966b6f755SWilly Tarreau#define DT_UNKNOWN 0
20066b6f755SWilly Tarreau#define DT_FIFO    1
20166b6f755SWilly Tarreau#define DT_CHR     2
20266b6f755SWilly Tarreau#define DT_DIR     4
20366b6f755SWilly Tarreau#define DT_BLK     6
20466b6f755SWilly Tarreau#define DT_REG     8
20566b6f755SWilly Tarreau#define DT_LNK    10
20666b6f755SWilly Tarreau#define DT_SOCK   12
20766b6f755SWilly Tarreau
20866b6f755SWilly Tarreau/* all the *at functions */
2096c5b9de2SSamuel Hernandez#ifndef AT_FDCWD
21066b6f755SWilly Tarreau#define AT_FDCWD             -100
21166b6f755SWilly Tarreau#endif
21266b6f755SWilly Tarreau
21366b6f755SWilly Tarreau/* lseek */
21466b6f755SWilly Tarreau#define SEEK_SET        0
21566b6f755SWilly Tarreau#define SEEK_CUR        1
21666b6f755SWilly Tarreau#define SEEK_END        2
21766b6f755SWilly Tarreau
21866b6f755SWilly Tarreau/* reboot */
21966b6f755SWilly Tarreau#define LINUX_REBOOT_MAGIC1         0xfee1dead
22066b6f755SWilly Tarreau#define LINUX_REBOOT_MAGIC2         0x28121969
22166b6f755SWilly Tarreau#define LINUX_REBOOT_CMD_HALT       0xcdef0123
22266b6f755SWilly Tarreau#define LINUX_REBOOT_CMD_POWER_OFF  0x4321fedc
22366b6f755SWilly Tarreau#define LINUX_REBOOT_CMD_RESTART    0x01234567
22466b6f755SWilly Tarreau#define LINUX_REBOOT_CMD_SW_SUSPEND 0xd000fce2
22566b6f755SWilly Tarreau
22666b6f755SWilly Tarreau
22766b6f755SWilly Tarreau/* The format of the struct as returned by the libc to the application, which
22866b6f755SWilly Tarreau * significantly differs from the format returned by the stat() syscall flavours.
22966b6f755SWilly Tarreau */
23066b6f755SWilly Tarreaustruct stat {
23166b6f755SWilly Tarreau	dev_t     st_dev;     /* ID of device containing file */
23266b6f755SWilly Tarreau	ino_t     st_ino;     /* inode number */
23366b6f755SWilly Tarreau	mode_t    st_mode;    /* protection */
23466b6f755SWilly Tarreau	nlink_t   st_nlink;   /* number of hard links */
23566b6f755SWilly Tarreau	uid_t     st_uid;     /* user ID of owner */
23666b6f755SWilly Tarreau	gid_t     st_gid;     /* group ID of owner */
23766b6f755SWilly Tarreau	dev_t     st_rdev;    /* device ID (if special file) */
23866b6f755SWilly Tarreau	off_t     st_size;    /* total size, in bytes */
23966b6f755SWilly Tarreau	blksize_t st_blksize; /* blocksize for file system I/O */
24066b6f755SWilly Tarreau	blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
24166b6f755SWilly Tarreau	time_t    st_atime;   /* time of last access */
24266b6f755SWilly Tarreau	time_t    st_mtime;   /* time of last modification */
24366b6f755SWilly Tarreau	time_t    st_ctime;   /* time of last status change */
24466b6f755SWilly Tarreau};
24566b6f755SWilly Tarreau
24666b6f755SWilly Tarreau#define WEXITSTATUS(status)   (((status) & 0xff00) >> 8)
24766b6f755SWilly Tarreau#define WIFEXITED(status)     (((status) & 0x7f) == 0)
24866b6f755SWilly Tarreau
249be60ca41SWilly Tarreau/* for SIGCHLD */
250be60ca41SWilly Tarreau#include <asm/signal.h>
25166b6f755SWilly Tarreau
25266b6f755SWilly Tarreau/* Below comes the architecture-specific code. For each architecture, we have
25366b6f755SWilly Tarreau * the syscall declarations and the _start code definition. This is the only
25466b6f755SWilly Tarreau * global part. On all architectures the kernel puts everything in the stack
25566b6f755SWilly Tarreau * before jumping to _start just above us, without any return address (_start
25666b6f755SWilly Tarreau * is not a function but an entry pint). So at the stack pointer we find argc.
25766b6f755SWilly Tarreau * Then argv[] begins, and ends at the first NULL. Then we have envp which
25866b6f755SWilly Tarreau * starts and ends with a NULL as well. So envp=argv+argc+1.
25966b6f755SWilly Tarreau */
26066b6f755SWilly Tarreau
26166b6f755SWilly Tarreau#if defined(__x86_64__)
26266b6f755SWilly Tarreau/* Syscalls for x86_64 :
26366b6f755SWilly Tarreau *   - registers are 64-bit
26466b6f755SWilly Tarreau *   - syscall number is passed in rax
26566b6f755SWilly Tarreau *   - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively
26666b6f755SWilly Tarreau *   - the system call is performed by calling the syscall instruction
26766b6f755SWilly Tarreau *   - syscall return comes in rax
268bf916669SAmmar Faizi *   - rcx and r11 are clobbered, others are preserved.
26966b6f755SWilly Tarreau *   - the arguments are cast to long and assigned into the target registers
27066b6f755SWilly Tarreau *     which are then simply passed as registers to the asm code, so that we
27166b6f755SWilly Tarreau *     don't have to experience issues with register constraints.
27266b6f755SWilly Tarreau *   - the syscall number is always specified last in order to allow to force
27366b6f755SWilly Tarreau *     some registers before (gcc refuses a %-register at the last position).
274bf916669SAmmar Faizi *   - see also x86-64 ABI section A.2 AMD64 Linux Kernel Conventions, A.2.1
275bf916669SAmmar Faizi *     Calling Conventions.
276bf916669SAmmar Faizi *
277bf916669SAmmar Faizi * Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/x86-64-psABI
278bf916669SAmmar Faizi *
27966b6f755SWilly Tarreau */
28066b6f755SWilly Tarreau
28166b6f755SWilly Tarreau#define my_syscall0(num)                                                      \
28266b6f755SWilly Tarreau({                                                                            \
28366b6f755SWilly Tarreau	long _ret;                                                            \
28466b6f755SWilly Tarreau	register long _num  asm("rax") = (num);                               \
28566b6f755SWilly Tarreau									      \
28666b6f755SWilly Tarreau	asm volatile (                                                        \
28766b6f755SWilly Tarreau		"syscall\n"                                                   \
288bf916669SAmmar Faizi		: "=a"(_ret)                                                  \
28966b6f755SWilly Tarreau		: "0"(_num)                                                   \
290bf916669SAmmar Faizi		: "rcx", "r11", "memory", "cc"                                \
29166b6f755SWilly Tarreau	);                                                                    \
29266b6f755SWilly Tarreau	_ret;                                                                 \
29366b6f755SWilly Tarreau})
29466b6f755SWilly Tarreau
29566b6f755SWilly Tarreau#define my_syscall1(num, arg1)                                                \
29666b6f755SWilly Tarreau({                                                                            \
29766b6f755SWilly Tarreau	long _ret;                                                            \
29866b6f755SWilly Tarreau	register long _num  asm("rax") = (num);                               \
29966b6f755SWilly Tarreau	register long _arg1 asm("rdi") = (long)(arg1);                        \
30066b6f755SWilly Tarreau									      \
30166b6f755SWilly Tarreau	asm volatile (                                                        \
30266b6f755SWilly Tarreau		"syscall\n"                                                   \
303bf916669SAmmar Faizi		: "=a"(_ret)                                                  \
30466b6f755SWilly Tarreau		: "r"(_arg1),                                                 \
30566b6f755SWilly Tarreau		  "0"(_num)                                                   \
306bf916669SAmmar Faizi		: "rcx", "r11", "memory", "cc"                                \
30766b6f755SWilly Tarreau	);                                                                    \
30866b6f755SWilly Tarreau	_ret;                                                                 \
30966b6f755SWilly Tarreau})
31066b6f755SWilly Tarreau
31166b6f755SWilly Tarreau#define my_syscall2(num, arg1, arg2)                                          \
31266b6f755SWilly Tarreau({                                                                            \
31366b6f755SWilly Tarreau	long _ret;                                                            \
31466b6f755SWilly Tarreau	register long _num  asm("rax") = (num);                               \
31566b6f755SWilly Tarreau	register long _arg1 asm("rdi") = (long)(arg1);                        \
31666b6f755SWilly Tarreau	register long _arg2 asm("rsi") = (long)(arg2);                        \
31766b6f755SWilly Tarreau									      \
31866b6f755SWilly Tarreau	asm volatile (                                                        \
31966b6f755SWilly Tarreau		"syscall\n"                                                   \
320bf916669SAmmar Faizi		: "=a"(_ret)                                                  \
32166b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2),                                     \
32266b6f755SWilly Tarreau		  "0"(_num)                                                   \
323bf916669SAmmar Faizi		: "rcx", "r11", "memory", "cc"                                \
32466b6f755SWilly Tarreau	);                                                                    \
32566b6f755SWilly Tarreau	_ret;                                                                 \
32666b6f755SWilly Tarreau})
32766b6f755SWilly Tarreau
32866b6f755SWilly Tarreau#define my_syscall3(num, arg1, arg2, arg3)                                    \
32966b6f755SWilly Tarreau({                                                                            \
33066b6f755SWilly Tarreau	long _ret;                                                            \
33166b6f755SWilly Tarreau	register long _num  asm("rax") = (num);                               \
33266b6f755SWilly Tarreau	register long _arg1 asm("rdi") = (long)(arg1);                        \
33366b6f755SWilly Tarreau	register long _arg2 asm("rsi") = (long)(arg2);                        \
33466b6f755SWilly Tarreau	register long _arg3 asm("rdx") = (long)(arg3);                        \
33566b6f755SWilly Tarreau									      \
33666b6f755SWilly Tarreau	asm volatile (                                                        \
33766b6f755SWilly Tarreau		"syscall\n"                                                   \
338bf916669SAmmar Faizi		: "=a"(_ret)                                                  \
33966b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \
34066b6f755SWilly Tarreau		  "0"(_num)                                                   \
341bf916669SAmmar Faizi		: "rcx", "r11", "memory", "cc"                                \
34266b6f755SWilly Tarreau	);                                                                    \
34366b6f755SWilly Tarreau	_ret;                                                                 \
34466b6f755SWilly Tarreau})
34566b6f755SWilly Tarreau
34666b6f755SWilly Tarreau#define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
34766b6f755SWilly Tarreau({                                                                            \
34866b6f755SWilly Tarreau	long _ret;                                                            \
34966b6f755SWilly Tarreau	register long _num  asm("rax") = (num);                               \
35066b6f755SWilly Tarreau	register long _arg1 asm("rdi") = (long)(arg1);                        \
35166b6f755SWilly Tarreau	register long _arg2 asm("rsi") = (long)(arg2);                        \
35266b6f755SWilly Tarreau	register long _arg3 asm("rdx") = (long)(arg3);                        \
35366b6f755SWilly Tarreau	register long _arg4 asm("r10") = (long)(arg4);                        \
35466b6f755SWilly Tarreau									      \
35566b6f755SWilly Tarreau	asm volatile (                                                        \
35666b6f755SWilly Tarreau		"syscall\n"                                                   \
357bf916669SAmmar Faizi		: "=a"(_ret)                                                  \
35866b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \
35966b6f755SWilly Tarreau		  "0"(_num)                                                   \
360bf916669SAmmar Faizi		: "rcx", "r11", "memory", "cc"                                \
36166b6f755SWilly Tarreau	);                                                                    \
36266b6f755SWilly Tarreau	_ret;                                                                 \
36366b6f755SWilly Tarreau})
36466b6f755SWilly Tarreau
36566b6f755SWilly Tarreau#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
36666b6f755SWilly Tarreau({                                                                            \
36766b6f755SWilly Tarreau	long _ret;                                                            \
36866b6f755SWilly Tarreau	register long _num  asm("rax") = (num);                               \
36966b6f755SWilly Tarreau	register long _arg1 asm("rdi") = (long)(arg1);                        \
37066b6f755SWilly Tarreau	register long _arg2 asm("rsi") = (long)(arg2);                        \
37166b6f755SWilly Tarreau	register long _arg3 asm("rdx") = (long)(arg3);                        \
37266b6f755SWilly Tarreau	register long _arg4 asm("r10") = (long)(arg4);                        \
37366b6f755SWilly Tarreau	register long _arg5 asm("r8")  = (long)(arg5);                        \
37466b6f755SWilly Tarreau									      \
37566b6f755SWilly Tarreau	asm volatile (                                                        \
37666b6f755SWilly Tarreau		"syscall\n"                                                   \
377bf916669SAmmar Faizi		: "=a"(_ret)                                                  \
37866b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
37966b6f755SWilly Tarreau		  "0"(_num)                                                   \
380bf916669SAmmar Faizi		: "rcx", "r11", "memory", "cc"                                \
38166b6f755SWilly Tarreau	);                                                                    \
38266b6f755SWilly Tarreau	_ret;                                                                 \
38366b6f755SWilly Tarreau})
38466b6f755SWilly Tarreau
38566b6f755SWilly Tarreau#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
38666b6f755SWilly Tarreau({                                                                            \
38766b6f755SWilly Tarreau	long _ret;                                                            \
38866b6f755SWilly Tarreau	register long _num  asm("rax") = (num);                               \
38966b6f755SWilly Tarreau	register long _arg1 asm("rdi") = (long)(arg1);                        \
39066b6f755SWilly Tarreau	register long _arg2 asm("rsi") = (long)(arg2);                        \
39166b6f755SWilly Tarreau	register long _arg3 asm("rdx") = (long)(arg3);                        \
39266b6f755SWilly Tarreau	register long _arg4 asm("r10") = (long)(arg4);                        \
39366b6f755SWilly Tarreau	register long _arg5 asm("r8")  = (long)(arg5);                        \
39466b6f755SWilly Tarreau	register long _arg6 asm("r9")  = (long)(arg6);                        \
39566b6f755SWilly Tarreau									      \
39666b6f755SWilly Tarreau	asm volatile (                                                        \
39766b6f755SWilly Tarreau		"syscall\n"                                                   \
398bf916669SAmmar Faizi		: "=a"(_ret)                                                  \
39966b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
40066b6f755SWilly Tarreau		  "r"(_arg6), "0"(_num)                                       \
40166b6f755SWilly Tarreau		: "rcx", "r11", "memory", "cc"                                \
40266b6f755SWilly Tarreau	);                                                                    \
40366b6f755SWilly Tarreau	_ret;                                                                 \
40466b6f755SWilly Tarreau})
40566b6f755SWilly Tarreau
40666b6f755SWilly Tarreau/* startup code */
407937ed91cSAmmar Faizi/*
408937ed91cSAmmar Faizi * x86-64 System V ABI mandates:
409937ed91cSAmmar Faizi * 1) %rsp must be 16-byte aligned right before the function call.
410937ed91cSAmmar Faizi * 2) The deepest stack frame should be zero (the %rbp).
411937ed91cSAmmar Faizi *
412937ed91cSAmmar Faizi */
41366b6f755SWilly Tarreauasm(".section .text\n"
41466b6f755SWilly Tarreau    ".global _start\n"
41566b6f755SWilly Tarreau    "_start:\n"
41666b6f755SWilly Tarreau    "pop %rdi\n"                // argc   (first arg, %rdi)
41766b6f755SWilly Tarreau    "mov %rsp, %rsi\n"          // argv[] (second arg, %rsi)
41866b6f755SWilly Tarreau    "lea 8(%rsi,%rdi,8),%rdx\n" // then a NULL then envp (third arg, %rdx)
419937ed91cSAmmar Faizi    "xor %ebp, %ebp\n"          // zero the stack frame
420937ed91cSAmmar Faizi    "and $-16, %rsp\n"          // x86 ABI : esp must be 16-byte aligned before call
42166b6f755SWilly Tarreau    "call main\n"               // main() returns the status code, we'll exit with it.
422de0244aeSWilly Tarreau    "mov %eax, %edi\n"          // retrieve exit code (32 bit)
4237bdc0e7aSAmmar Faizi    "mov $60, %eax\n"           // NR_exit == 60
42466b6f755SWilly Tarreau    "syscall\n"                 // really exit
42566b6f755SWilly Tarreau    "hlt\n"                     // ensure it does not return
42666b6f755SWilly Tarreau    "");
42766b6f755SWilly Tarreau
42866b6f755SWilly Tarreau/* fcntl / open */
42966b6f755SWilly Tarreau#define O_RDONLY            0
43066b6f755SWilly Tarreau#define O_WRONLY            1
43166b6f755SWilly Tarreau#define O_RDWR              2
43266b6f755SWilly Tarreau#define O_CREAT          0x40
43366b6f755SWilly Tarreau#define O_EXCL           0x80
43466b6f755SWilly Tarreau#define O_NOCTTY        0x100
43566b6f755SWilly Tarreau#define O_TRUNC         0x200
43666b6f755SWilly Tarreau#define O_APPEND        0x400
43766b6f755SWilly Tarreau#define O_NONBLOCK      0x800
43866b6f755SWilly Tarreau#define O_DIRECTORY   0x10000
43966b6f755SWilly Tarreau
44066b6f755SWilly Tarreau/* The struct returned by the stat() syscall, equivalent to stat64(). The
44166b6f755SWilly Tarreau * syscall returns 116 bytes and stops in the middle of __unused.
44266b6f755SWilly Tarreau */
44366b6f755SWilly Tarreaustruct sys_stat_struct {
44466b6f755SWilly Tarreau	unsigned long st_dev;
44566b6f755SWilly Tarreau	unsigned long st_ino;
44666b6f755SWilly Tarreau	unsigned long st_nlink;
44766b6f755SWilly Tarreau	unsigned int  st_mode;
44866b6f755SWilly Tarreau	unsigned int  st_uid;
44966b6f755SWilly Tarreau
45066b6f755SWilly Tarreau	unsigned int  st_gid;
45166b6f755SWilly Tarreau	unsigned int  __pad0;
45266b6f755SWilly Tarreau	unsigned long st_rdev;
45366b6f755SWilly Tarreau	long          st_size;
45466b6f755SWilly Tarreau	long          st_blksize;
45566b6f755SWilly Tarreau
45666b6f755SWilly Tarreau	long          st_blocks;
45766b6f755SWilly Tarreau	unsigned long st_atime;
45866b6f755SWilly Tarreau	unsigned long st_atime_nsec;
45966b6f755SWilly Tarreau	unsigned long st_mtime;
46066b6f755SWilly Tarreau
46166b6f755SWilly Tarreau	unsigned long st_mtime_nsec;
46266b6f755SWilly Tarreau	unsigned long st_ctime;
46366b6f755SWilly Tarreau	unsigned long st_ctime_nsec;
46466b6f755SWilly Tarreau	long          __unused[3];
46566b6f755SWilly Tarreau};
46666b6f755SWilly Tarreau
46766b6f755SWilly Tarreau#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
46866b6f755SWilly Tarreau/* Syscalls for i386 :
46966b6f755SWilly Tarreau *   - mostly similar to x86_64
47066b6f755SWilly Tarreau *   - registers are 32-bit
47166b6f755SWilly Tarreau *   - syscall number is passed in eax
47266b6f755SWilly Tarreau *   - arguments are in ebx, ecx, edx, esi, edi, ebp respectively
47366b6f755SWilly Tarreau *   - all registers are preserved (except eax of course)
47466b6f755SWilly Tarreau *   - the system call is performed by calling int $0x80
47566b6f755SWilly Tarreau *   - syscall return comes in eax
47666b6f755SWilly Tarreau *   - the arguments are cast to long and assigned into the target registers
47766b6f755SWilly Tarreau *     which are then simply passed as registers to the asm code, so that we
47866b6f755SWilly Tarreau *     don't have to experience issues with register constraints.
47966b6f755SWilly Tarreau *   - the syscall number is always specified last in order to allow to force
48066b6f755SWilly Tarreau *     some registers before (gcc refuses a %-register at the last position).
48166b6f755SWilly Tarreau *
48266b6f755SWilly Tarreau * Also, i386 supports the old_select syscall if newselect is not available
48366b6f755SWilly Tarreau */
48466b6f755SWilly Tarreau#define __ARCH_WANT_SYS_OLD_SELECT
48566b6f755SWilly Tarreau
48666b6f755SWilly Tarreau#define my_syscall0(num)                                                      \
48766b6f755SWilly Tarreau({                                                                            \
48866b6f755SWilly Tarreau	long _ret;                                                            \
48966b6f755SWilly Tarreau	register long _num asm("eax") = (num);                                \
49066b6f755SWilly Tarreau									      \
49166b6f755SWilly Tarreau	asm volatile (                                                        \
49266b6f755SWilly Tarreau		"int $0x80\n"                                                 \
49366b6f755SWilly Tarreau		: "=a" (_ret)                                                 \
49466b6f755SWilly Tarreau		: "0"(_num)                                                   \
49566b6f755SWilly Tarreau		: "memory", "cc"                                              \
49666b6f755SWilly Tarreau	);                                                                    \
49766b6f755SWilly Tarreau	_ret;                                                                 \
49866b6f755SWilly Tarreau})
49966b6f755SWilly Tarreau
50066b6f755SWilly Tarreau#define my_syscall1(num, arg1)                                                \
50166b6f755SWilly Tarreau({                                                                            \
50266b6f755SWilly Tarreau	long _ret;                                                            \
50366b6f755SWilly Tarreau	register long _num asm("eax") = (num);                                \
50466b6f755SWilly Tarreau	register long _arg1 asm("ebx") = (long)(arg1);                        \
50566b6f755SWilly Tarreau									      \
50666b6f755SWilly Tarreau	asm volatile (                                                        \
50766b6f755SWilly Tarreau		"int $0x80\n"                                                 \
50866b6f755SWilly Tarreau		: "=a" (_ret)                                                 \
50966b6f755SWilly Tarreau		: "r"(_arg1),                                                 \
51066b6f755SWilly Tarreau		  "0"(_num)                                                   \
51166b6f755SWilly Tarreau		: "memory", "cc"                                              \
51266b6f755SWilly Tarreau	);                                                                    \
51366b6f755SWilly Tarreau	_ret;                                                                 \
51466b6f755SWilly Tarreau})
51566b6f755SWilly Tarreau
51666b6f755SWilly Tarreau#define my_syscall2(num, arg1, arg2)                                          \
51766b6f755SWilly Tarreau({                                                                            \
51866b6f755SWilly Tarreau	long _ret;                                                            \
51966b6f755SWilly Tarreau	register long _num asm("eax") = (num);                                \
52066b6f755SWilly Tarreau	register long _arg1 asm("ebx") = (long)(arg1);                        \
52166b6f755SWilly Tarreau	register long _arg2 asm("ecx") = (long)(arg2);                        \
52266b6f755SWilly Tarreau									      \
52366b6f755SWilly Tarreau	asm volatile (                                                        \
52466b6f755SWilly Tarreau		"int $0x80\n"                                                 \
52566b6f755SWilly Tarreau		: "=a" (_ret)                                                 \
52666b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2),                                     \
52766b6f755SWilly Tarreau		  "0"(_num)                                                   \
52866b6f755SWilly Tarreau		: "memory", "cc"                                              \
52966b6f755SWilly Tarreau	);                                                                    \
53066b6f755SWilly Tarreau	_ret;                                                                 \
53166b6f755SWilly Tarreau})
53266b6f755SWilly Tarreau
53366b6f755SWilly Tarreau#define my_syscall3(num, arg1, arg2, arg3)                                    \
53466b6f755SWilly Tarreau({                                                                            \
53566b6f755SWilly Tarreau	long _ret;                                                            \
53666b6f755SWilly Tarreau	register long _num asm("eax") = (num);                                \
53766b6f755SWilly Tarreau	register long _arg1 asm("ebx") = (long)(arg1);                        \
53866b6f755SWilly Tarreau	register long _arg2 asm("ecx") = (long)(arg2);                        \
53966b6f755SWilly Tarreau	register long _arg3 asm("edx") = (long)(arg3);                        \
54066b6f755SWilly Tarreau									      \
54166b6f755SWilly Tarreau	asm volatile (                                                        \
54266b6f755SWilly Tarreau		"int $0x80\n"                                                 \
54366b6f755SWilly Tarreau		: "=a" (_ret)                                                 \
54466b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \
54566b6f755SWilly Tarreau		  "0"(_num)                                                   \
54666b6f755SWilly Tarreau		: "memory", "cc"                                              \
54766b6f755SWilly Tarreau	);                                                                    \
54866b6f755SWilly Tarreau	_ret;                                                                 \
54966b6f755SWilly Tarreau})
55066b6f755SWilly Tarreau
55166b6f755SWilly Tarreau#define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
55266b6f755SWilly Tarreau({                                                                            \
55366b6f755SWilly Tarreau	long _ret;                                                            \
55466b6f755SWilly Tarreau	register long _num asm("eax") = (num);                                \
55566b6f755SWilly Tarreau	register long _arg1 asm("ebx") = (long)(arg1);                        \
55666b6f755SWilly Tarreau	register long _arg2 asm("ecx") = (long)(arg2);                        \
55766b6f755SWilly Tarreau	register long _arg3 asm("edx") = (long)(arg3);                        \
55866b6f755SWilly Tarreau	register long _arg4 asm("esi") = (long)(arg4);                        \
55966b6f755SWilly Tarreau									      \
56066b6f755SWilly Tarreau	asm volatile (                                                        \
56166b6f755SWilly Tarreau		"int $0x80\n"                                                 \
56266b6f755SWilly Tarreau		: "=a" (_ret)                                                 \
56366b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \
56466b6f755SWilly Tarreau		  "0"(_num)                                                   \
56566b6f755SWilly Tarreau		: "memory", "cc"                                              \
56666b6f755SWilly Tarreau	);                                                                    \
56766b6f755SWilly Tarreau	_ret;                                                                 \
56866b6f755SWilly Tarreau})
56966b6f755SWilly Tarreau
57066b6f755SWilly Tarreau#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
57166b6f755SWilly Tarreau({                                                                            \
57266b6f755SWilly Tarreau	long _ret;                                                            \
57366b6f755SWilly Tarreau	register long _num asm("eax") = (num);                                \
57466b6f755SWilly Tarreau	register long _arg1 asm("ebx") = (long)(arg1);                        \
57566b6f755SWilly Tarreau	register long _arg2 asm("ecx") = (long)(arg2);                        \
57666b6f755SWilly Tarreau	register long _arg3 asm("edx") = (long)(arg3);                        \
57766b6f755SWilly Tarreau	register long _arg4 asm("esi") = (long)(arg4);                        \
57866b6f755SWilly Tarreau	register long _arg5 asm("edi") = (long)(arg5);                        \
57966b6f755SWilly Tarreau									      \
58066b6f755SWilly Tarreau	asm volatile (                                                        \
58166b6f755SWilly Tarreau		"int $0x80\n"                                                 \
58266b6f755SWilly Tarreau		: "=a" (_ret)                                                 \
58366b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
58466b6f755SWilly Tarreau		  "0"(_num)                                                   \
58566b6f755SWilly Tarreau		: "memory", "cc"                                              \
58666b6f755SWilly Tarreau	);                                                                    \
58766b6f755SWilly Tarreau	_ret;                                                                 \
58866b6f755SWilly Tarreau})
58966b6f755SWilly Tarreau
59066b6f755SWilly Tarreau/* startup code */
591ebbe0d8aSWilly Tarreau/*
592ebbe0d8aSWilly Tarreau * i386 System V ABI mandates:
593ebbe0d8aSWilly Tarreau * 1) last pushed argument must be 16-byte aligned.
594ebbe0d8aSWilly Tarreau * 2) The deepest stack frame should be set to zero
595ebbe0d8aSWilly Tarreau *
596ebbe0d8aSWilly Tarreau */
59766b6f755SWilly Tarreauasm(".section .text\n"
59866b6f755SWilly Tarreau    ".global _start\n"
59966b6f755SWilly Tarreau    "_start:\n"
60066b6f755SWilly Tarreau    "pop %eax\n"                // argc   (first arg, %eax)
60166b6f755SWilly Tarreau    "mov %esp, %ebx\n"          // argv[] (second arg, %ebx)
60266b6f755SWilly Tarreau    "lea 4(%ebx,%eax,4),%ecx\n" // then a NULL then envp (third arg, %ecx)
603ebbe0d8aSWilly Tarreau    "xor %ebp, %ebp\n"          // zero the stack frame
604ebbe0d8aSWilly Tarreau    "and $-16, %esp\n"          // x86 ABI : esp must be 16-byte aligned before
605ebbe0d8aSWilly Tarreau    "sub $4, %esp\n"            // the call instruction (args are aligned)
60666b6f755SWilly Tarreau    "push %ecx\n"               // push all registers on the stack so that we
60766b6f755SWilly Tarreau    "push %ebx\n"               // support both regparm and plain stack modes
60866b6f755SWilly Tarreau    "push %eax\n"
60966b6f755SWilly Tarreau    "call main\n"               // main() returns the status code in %eax
610de0244aeSWilly Tarreau    "mov %eax, %ebx\n"          // retrieve exit code (32-bit int)
611de0244aeSWilly Tarreau    "movl $1, %eax\n"           // NR_exit == 1
612de0244aeSWilly Tarreau    "int $0x80\n"               // exit now
61366b6f755SWilly Tarreau    "hlt\n"                     // ensure it does not
61466b6f755SWilly Tarreau    "");
61566b6f755SWilly Tarreau
61666b6f755SWilly Tarreau/* fcntl / open */
61766b6f755SWilly Tarreau#define O_RDONLY            0
61866b6f755SWilly Tarreau#define O_WRONLY            1
61966b6f755SWilly Tarreau#define O_RDWR              2
62066b6f755SWilly Tarreau#define O_CREAT          0x40
62166b6f755SWilly Tarreau#define O_EXCL           0x80
62266b6f755SWilly Tarreau#define O_NOCTTY        0x100
62366b6f755SWilly Tarreau#define O_TRUNC         0x200
62466b6f755SWilly Tarreau#define O_APPEND        0x400
62566b6f755SWilly Tarreau#define O_NONBLOCK      0x800
62666b6f755SWilly Tarreau#define O_DIRECTORY   0x10000
62766b6f755SWilly Tarreau
62866b6f755SWilly Tarreau/* The struct returned by the stat() syscall, 32-bit only, the syscall returns
62966b6f755SWilly Tarreau * exactly 56 bytes (stops before the unused array).
63066b6f755SWilly Tarreau */
63166b6f755SWilly Tarreaustruct sys_stat_struct {
63266b6f755SWilly Tarreau	unsigned long  st_dev;
63366b6f755SWilly Tarreau	unsigned long  st_ino;
63466b6f755SWilly Tarreau	unsigned short st_mode;
63566b6f755SWilly Tarreau	unsigned short st_nlink;
63666b6f755SWilly Tarreau	unsigned short st_uid;
63766b6f755SWilly Tarreau	unsigned short st_gid;
63866b6f755SWilly Tarreau
63966b6f755SWilly Tarreau	unsigned long  st_rdev;
64066b6f755SWilly Tarreau	unsigned long  st_size;
64166b6f755SWilly Tarreau	unsigned long  st_blksize;
64266b6f755SWilly Tarreau	unsigned long  st_blocks;
64366b6f755SWilly Tarreau
64466b6f755SWilly Tarreau	unsigned long  st_atime;
64566b6f755SWilly Tarreau	unsigned long  st_atime_nsec;
64666b6f755SWilly Tarreau	unsigned long  st_mtime;
64766b6f755SWilly Tarreau	unsigned long  st_mtime_nsec;
64866b6f755SWilly Tarreau
64966b6f755SWilly Tarreau	unsigned long  st_ctime;
65066b6f755SWilly Tarreau	unsigned long  st_ctime_nsec;
65166b6f755SWilly Tarreau	unsigned long  __unused[2];
65266b6f755SWilly Tarreau};
65366b6f755SWilly Tarreau
65466b6f755SWilly Tarreau#elif defined(__ARM_EABI__)
65566b6f755SWilly Tarreau/* Syscalls for ARM in ARM or Thumb modes :
65666b6f755SWilly Tarreau *   - registers are 32-bit
65766b6f755SWilly Tarreau *   - stack is 8-byte aligned
65866b6f755SWilly Tarreau *     ( http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html)
65966b6f755SWilly Tarreau *   - syscall number is passed in r7
66066b6f755SWilly Tarreau *   - arguments are in r0, r1, r2, r3, r4, r5
66166b6f755SWilly Tarreau *   - the system call is performed by calling svc #0
66266b6f755SWilly Tarreau *   - syscall return comes in r0.
66366b6f755SWilly Tarreau *   - only lr is clobbered.
66466b6f755SWilly Tarreau *   - the arguments are cast to long and assigned into the target registers
66566b6f755SWilly Tarreau *     which are then simply passed as registers to the asm code, so that we
66666b6f755SWilly Tarreau *     don't have to experience issues with register constraints.
66766b6f755SWilly Tarreau *   - the syscall number is always specified last in order to allow to force
66866b6f755SWilly Tarreau *     some registers before (gcc refuses a %-register at the last position).
66966b6f755SWilly Tarreau *
67066b6f755SWilly Tarreau * Also, ARM supports the old_select syscall if newselect is not available
67166b6f755SWilly Tarreau */
67266b6f755SWilly Tarreau#define __ARCH_WANT_SYS_OLD_SELECT
67366b6f755SWilly Tarreau
67466b6f755SWilly Tarreau#define my_syscall0(num)                                                      \
67566b6f755SWilly Tarreau({                                                                            \
67666b6f755SWilly Tarreau	register long _num asm("r7") = (num);                                 \
67766b6f755SWilly Tarreau	register long _arg1 asm("r0");                                        \
67866b6f755SWilly Tarreau									      \
67966b6f755SWilly Tarreau	asm volatile (                                                        \
68066b6f755SWilly Tarreau		"svc #0\n"                                                    \
68166b6f755SWilly Tarreau		: "=r"(_arg1)                                                 \
68266b6f755SWilly Tarreau		: "r"(_num)                                                   \
68366b6f755SWilly Tarreau		: "memory", "cc", "lr"                                        \
68466b6f755SWilly Tarreau	);                                                                    \
68566b6f755SWilly Tarreau	_arg1;                                                                \
68666b6f755SWilly Tarreau})
68766b6f755SWilly Tarreau
68866b6f755SWilly Tarreau#define my_syscall1(num, arg1)                                                \
68966b6f755SWilly Tarreau({                                                                            \
69066b6f755SWilly Tarreau	register long _num asm("r7") = (num);                                 \
69166b6f755SWilly Tarreau	register long _arg1 asm("r0") = (long)(arg1);                         \
69266b6f755SWilly Tarreau									      \
69366b6f755SWilly Tarreau	asm volatile (                                                        \
69466b6f755SWilly Tarreau		"svc #0\n"                                                    \
69566b6f755SWilly Tarreau		: "=r"(_arg1)                                                 \
69666b6f755SWilly Tarreau		: "r"(_arg1),                                                 \
69766b6f755SWilly Tarreau		  "r"(_num)                                                   \
69866b6f755SWilly Tarreau		: "memory", "cc", "lr"                                        \
69966b6f755SWilly Tarreau	);                                                                    \
70066b6f755SWilly Tarreau	_arg1;                                                                \
70166b6f755SWilly Tarreau})
70266b6f755SWilly Tarreau
70366b6f755SWilly Tarreau#define my_syscall2(num, arg1, arg2)                                          \
70466b6f755SWilly Tarreau({                                                                            \
70566b6f755SWilly Tarreau	register long _num asm("r7") = (num);                                 \
70666b6f755SWilly Tarreau	register long _arg1 asm("r0") = (long)(arg1);                         \
70766b6f755SWilly Tarreau	register long _arg2 asm("r1") = (long)(arg2);                         \
70866b6f755SWilly Tarreau									      \
70966b6f755SWilly Tarreau	asm volatile (                                                        \
71066b6f755SWilly Tarreau		"svc #0\n"                                                    \
71166b6f755SWilly Tarreau		: "=r"(_arg1)                                                 \
71266b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2),                                     \
71366b6f755SWilly Tarreau		  "r"(_num)                                                   \
71466b6f755SWilly Tarreau		: "memory", "cc", "lr"                                        \
71566b6f755SWilly Tarreau	);                                                                    \
71666b6f755SWilly Tarreau	_arg1;                                                                \
71766b6f755SWilly Tarreau})
71866b6f755SWilly Tarreau
71966b6f755SWilly Tarreau#define my_syscall3(num, arg1, arg2, arg3)                                    \
72066b6f755SWilly Tarreau({                                                                            \
72166b6f755SWilly Tarreau	register long _num asm("r7") = (num);                                 \
72266b6f755SWilly Tarreau	register long _arg1 asm("r0") = (long)(arg1);                         \
72366b6f755SWilly Tarreau	register long _arg2 asm("r1") = (long)(arg2);                         \
72466b6f755SWilly Tarreau	register long _arg3 asm("r2") = (long)(arg3);                         \
72566b6f755SWilly Tarreau									      \
72666b6f755SWilly Tarreau	asm volatile (                                                        \
72766b6f755SWilly Tarreau		"svc #0\n"                                                    \
72866b6f755SWilly Tarreau		: "=r"(_arg1)                                                 \
72966b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \
73066b6f755SWilly Tarreau		  "r"(_num)                                                   \
73166b6f755SWilly Tarreau		: "memory", "cc", "lr"                                        \
73266b6f755SWilly Tarreau	);                                                                    \
73366b6f755SWilly Tarreau	_arg1;                                                                \
73466b6f755SWilly Tarreau})
73566b6f755SWilly Tarreau
73666b6f755SWilly Tarreau#define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
73766b6f755SWilly Tarreau({                                                                            \
73866b6f755SWilly Tarreau	register long _num asm("r7") = (num);                                 \
73966b6f755SWilly Tarreau	register long _arg1 asm("r0") = (long)(arg1);                         \
74066b6f755SWilly Tarreau	register long _arg2 asm("r1") = (long)(arg2);                         \
74166b6f755SWilly Tarreau	register long _arg3 asm("r2") = (long)(arg3);                         \
74266b6f755SWilly Tarreau	register long _arg4 asm("r3") = (long)(arg4);                         \
74366b6f755SWilly Tarreau									      \
74466b6f755SWilly Tarreau	asm volatile (                                                        \
74566b6f755SWilly Tarreau		"svc #0\n"                                                    \
74666b6f755SWilly Tarreau		: "=r"(_arg1)                                                 \
74766b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \
74866b6f755SWilly Tarreau		  "r"(_num)                                                   \
74966b6f755SWilly Tarreau		: "memory", "cc", "lr"                                        \
75066b6f755SWilly Tarreau	);                                                                    \
75166b6f755SWilly Tarreau	_arg1;                                                                \
75266b6f755SWilly Tarreau})
75366b6f755SWilly Tarreau
75466b6f755SWilly Tarreau#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
75566b6f755SWilly Tarreau({                                                                            \
75666b6f755SWilly Tarreau	register long _num asm("r7") = (num);                                 \
75766b6f755SWilly Tarreau	register long _arg1 asm("r0") = (long)(arg1);                         \
75866b6f755SWilly Tarreau	register long _arg2 asm("r1") = (long)(arg2);                         \
75966b6f755SWilly Tarreau	register long _arg3 asm("r2") = (long)(arg3);                         \
76066b6f755SWilly Tarreau	register long _arg4 asm("r3") = (long)(arg4);                         \
76166b6f755SWilly Tarreau	register long _arg5 asm("r4") = (long)(arg5);                         \
76266b6f755SWilly Tarreau									      \
76366b6f755SWilly Tarreau	asm volatile (                                                        \
76466b6f755SWilly Tarreau		"svc #0\n"                                                    \
76566b6f755SWilly Tarreau		: "=r" (_arg1)                                                \
76666b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
76766b6f755SWilly Tarreau		  "r"(_num)                                                   \
76866b6f755SWilly Tarreau		: "memory", "cc", "lr"                                        \
76966b6f755SWilly Tarreau	);                                                                    \
77066b6f755SWilly Tarreau	_arg1;                                                                \
77166b6f755SWilly Tarreau})
77266b6f755SWilly Tarreau
77366b6f755SWilly Tarreau/* startup code */
77466b6f755SWilly Tarreauasm(".section .text\n"
77566b6f755SWilly Tarreau    ".global _start\n"
77666b6f755SWilly Tarreau    "_start:\n"
77766b6f755SWilly Tarreau#if defined(__THUMBEB__) || defined(__THUMBEL__)
77866b6f755SWilly Tarreau    /* We enter here in 32-bit mode but if some previous functions were in
77966b6f755SWilly Tarreau     * 16-bit mode, the assembler cannot know, so we need to tell it we're in
78066b6f755SWilly Tarreau     * 32-bit now, then switch to 16-bit (is there a better way to do it than
78166b6f755SWilly Tarreau     * adding 1 by hand ?) and tell the asm we're now in 16-bit mode so that
78266b6f755SWilly Tarreau     * it generates correct instructions. Note that we do not support thumb1.
78366b6f755SWilly Tarreau     */
78466b6f755SWilly Tarreau    ".code 32\n"
78566b6f755SWilly Tarreau    "add     r0, pc, #1\n"
78666b6f755SWilly Tarreau    "bx      r0\n"
78766b6f755SWilly Tarreau    ".code 16\n"
78866b6f755SWilly Tarreau#endif
78966b6f755SWilly Tarreau    "pop {%r0}\n"                 // argc was in the stack
79066b6f755SWilly Tarreau    "mov %r1, %sp\n"              // argv = sp
79166b6f755SWilly Tarreau    "add %r2, %r1, %r0, lsl #2\n" // envp = argv + 4*argc ...
79266b6f755SWilly Tarreau    "add %r2, %r2, $4\n"          //        ... + 4
79366b6f755SWilly Tarreau    "and %r3, %r1, $-8\n"         // AAPCS : sp must be 8-byte aligned in the
79466b6f755SWilly Tarreau    "mov %sp, %r3\n"              //         callee, an bl doesn't push (lr=pc)
79566b6f755SWilly Tarreau    "bl main\n"                   // main() returns the status code, we'll exit with it.
79666b6f755SWilly Tarreau    "movs r7, $1\n"               // NR_exit == 1
79766b6f755SWilly Tarreau    "svc $0x00\n"
79866b6f755SWilly Tarreau    "");
79966b6f755SWilly Tarreau
80066b6f755SWilly Tarreau/* fcntl / open */
80166b6f755SWilly Tarreau#define O_RDONLY            0
80266b6f755SWilly Tarreau#define O_WRONLY            1
80366b6f755SWilly Tarreau#define O_RDWR              2
80466b6f755SWilly Tarreau#define O_CREAT          0x40
80566b6f755SWilly Tarreau#define O_EXCL           0x80
80666b6f755SWilly Tarreau#define O_NOCTTY        0x100
80766b6f755SWilly Tarreau#define O_TRUNC         0x200
80866b6f755SWilly Tarreau#define O_APPEND        0x400
80966b6f755SWilly Tarreau#define O_NONBLOCK      0x800
81066b6f755SWilly Tarreau#define O_DIRECTORY    0x4000
81166b6f755SWilly Tarreau
81266b6f755SWilly Tarreau/* The struct returned by the stat() syscall, 32-bit only, the syscall returns
81366b6f755SWilly Tarreau * exactly 56 bytes (stops before the unused array). In big endian, the format
81466b6f755SWilly Tarreau * differs as devices are returned as short only.
81566b6f755SWilly Tarreau */
81666b6f755SWilly Tarreaustruct sys_stat_struct {
81766b6f755SWilly Tarreau#if defined(__ARMEB__)
81866b6f755SWilly Tarreau	unsigned short st_dev;
81966b6f755SWilly Tarreau	unsigned short __pad1;
82066b6f755SWilly Tarreau#else
82166b6f755SWilly Tarreau	unsigned long  st_dev;
82266b6f755SWilly Tarreau#endif
82366b6f755SWilly Tarreau	unsigned long  st_ino;
82466b6f755SWilly Tarreau	unsigned short st_mode;
82566b6f755SWilly Tarreau	unsigned short st_nlink;
82666b6f755SWilly Tarreau	unsigned short st_uid;
82766b6f755SWilly Tarreau	unsigned short st_gid;
82866b6f755SWilly Tarreau#if defined(__ARMEB__)
82966b6f755SWilly Tarreau	unsigned short st_rdev;
83066b6f755SWilly Tarreau	unsigned short __pad2;
83166b6f755SWilly Tarreau#else
83266b6f755SWilly Tarreau	unsigned long  st_rdev;
83366b6f755SWilly Tarreau#endif
83466b6f755SWilly Tarreau	unsigned long  st_size;
83566b6f755SWilly Tarreau	unsigned long  st_blksize;
83666b6f755SWilly Tarreau	unsigned long  st_blocks;
83766b6f755SWilly Tarreau	unsigned long  st_atime;
83866b6f755SWilly Tarreau	unsigned long  st_atime_nsec;
83966b6f755SWilly Tarreau	unsigned long  st_mtime;
84066b6f755SWilly Tarreau	unsigned long  st_mtime_nsec;
84166b6f755SWilly Tarreau	unsigned long  st_ctime;
84266b6f755SWilly Tarreau	unsigned long  st_ctime_nsec;
84366b6f755SWilly Tarreau	unsigned long  __unused[2];
84466b6f755SWilly Tarreau};
84566b6f755SWilly Tarreau
84666b6f755SWilly Tarreau#elif defined(__aarch64__)
84766b6f755SWilly Tarreau/* Syscalls for AARCH64 :
84866b6f755SWilly Tarreau *   - registers are 64-bit
84966b6f755SWilly Tarreau *   - stack is 16-byte aligned
85066b6f755SWilly Tarreau *   - syscall number is passed in x8
85166b6f755SWilly Tarreau *   - arguments are in x0, x1, x2, x3, x4, x5
85266b6f755SWilly Tarreau *   - the system call is performed by calling svc 0
85366b6f755SWilly Tarreau *   - syscall return comes in x0.
85466b6f755SWilly Tarreau *   - the arguments are cast to long and assigned into the target registers
85566b6f755SWilly Tarreau *     which are then simply passed as registers to the asm code, so that we
85666b6f755SWilly Tarreau *     don't have to experience issues with register constraints.
85766b6f755SWilly Tarreau *
85866b6f755SWilly Tarreau * On aarch64, select() is not implemented so we have to use pselect6().
85966b6f755SWilly Tarreau */
86066b6f755SWilly Tarreau#define __ARCH_WANT_SYS_PSELECT6
86166b6f755SWilly Tarreau
86266b6f755SWilly Tarreau#define my_syscall0(num)                                                      \
86366b6f755SWilly Tarreau({                                                                            \
86466b6f755SWilly Tarreau	register long _num  asm("x8") = (num);                                \
86566b6f755SWilly Tarreau	register long _arg1 asm("x0");                                        \
86666b6f755SWilly Tarreau									      \
86766b6f755SWilly Tarreau	asm volatile (                                                        \
86866b6f755SWilly Tarreau		"svc #0\n"                                                    \
86966b6f755SWilly Tarreau		: "=r"(_arg1)                                                 \
87066b6f755SWilly Tarreau		: "r"(_num)                                                   \
87166b6f755SWilly Tarreau		: "memory", "cc"                                              \
87266b6f755SWilly Tarreau	);                                                                    \
87366b6f755SWilly Tarreau	_arg1;                                                                \
87466b6f755SWilly Tarreau})
87566b6f755SWilly Tarreau
87666b6f755SWilly Tarreau#define my_syscall1(num, arg1)                                                \
87766b6f755SWilly Tarreau({                                                                            \
87866b6f755SWilly Tarreau	register long _num  asm("x8") = (num);                                \
87966b6f755SWilly Tarreau	register long _arg1 asm("x0") = (long)(arg1);                         \
88066b6f755SWilly Tarreau									      \
88166b6f755SWilly Tarreau	asm volatile (                                                        \
88266b6f755SWilly Tarreau		"svc #0\n"                                                    \
88366b6f755SWilly Tarreau		: "=r"(_arg1)                                                 \
88466b6f755SWilly Tarreau		: "r"(_arg1),                                                 \
88566b6f755SWilly Tarreau		  "r"(_num)                                                   \
88666b6f755SWilly Tarreau		: "memory", "cc"                                              \
88766b6f755SWilly Tarreau	);                                                                    \
88866b6f755SWilly Tarreau	_arg1;                                                                \
88966b6f755SWilly Tarreau})
89066b6f755SWilly Tarreau
89166b6f755SWilly Tarreau#define my_syscall2(num, arg1, arg2)                                          \
89266b6f755SWilly Tarreau({                                                                            \
89366b6f755SWilly Tarreau	register long _num  asm("x8") = (num);                                \
89466b6f755SWilly Tarreau	register long _arg1 asm("x0") = (long)(arg1);                         \
89566b6f755SWilly Tarreau	register long _arg2 asm("x1") = (long)(arg2);                         \
89666b6f755SWilly Tarreau									      \
89766b6f755SWilly Tarreau	asm volatile (                                                        \
89866b6f755SWilly Tarreau		"svc #0\n"                                                    \
89966b6f755SWilly Tarreau		: "=r"(_arg1)                                                 \
90066b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2),                                     \
90166b6f755SWilly Tarreau		  "r"(_num)                                                   \
90266b6f755SWilly Tarreau		: "memory", "cc"                                              \
90366b6f755SWilly Tarreau	);                                                                    \
90466b6f755SWilly Tarreau	_arg1;                                                                \
90566b6f755SWilly Tarreau})
90666b6f755SWilly Tarreau
90766b6f755SWilly Tarreau#define my_syscall3(num, arg1, arg2, arg3)                                    \
90866b6f755SWilly Tarreau({                                                                            \
90966b6f755SWilly Tarreau	register long _num  asm("x8") = (num);                                \
91066b6f755SWilly Tarreau	register long _arg1 asm("x0") = (long)(arg1);                         \
91166b6f755SWilly Tarreau	register long _arg2 asm("x1") = (long)(arg2);                         \
91266b6f755SWilly Tarreau	register long _arg3 asm("x2") = (long)(arg3);                         \
91366b6f755SWilly Tarreau									      \
91466b6f755SWilly Tarreau	asm volatile (                                                        \
91566b6f755SWilly Tarreau		"svc #0\n"                                                    \
91666b6f755SWilly Tarreau		: "=r"(_arg1)                                                 \
91766b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \
91866b6f755SWilly Tarreau		  "r"(_num)                                                   \
91966b6f755SWilly Tarreau		: "memory", "cc"                                              \
92066b6f755SWilly Tarreau	);                                                                    \
92166b6f755SWilly Tarreau	_arg1;                                                                \
92266b6f755SWilly Tarreau})
92366b6f755SWilly Tarreau
92466b6f755SWilly Tarreau#define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
92566b6f755SWilly Tarreau({                                                                            \
92666b6f755SWilly Tarreau	register long _num  asm("x8") = (num);                                \
92766b6f755SWilly Tarreau	register long _arg1 asm("x0") = (long)(arg1);                         \
92866b6f755SWilly Tarreau	register long _arg2 asm("x1") = (long)(arg2);                         \
92966b6f755SWilly Tarreau	register long _arg3 asm("x2") = (long)(arg3);                         \
93066b6f755SWilly Tarreau	register long _arg4 asm("x3") = (long)(arg4);                         \
93166b6f755SWilly Tarreau									      \
93266b6f755SWilly Tarreau	asm volatile (                                                        \
93366b6f755SWilly Tarreau		"svc #0\n"                                                    \
93466b6f755SWilly Tarreau		: "=r"(_arg1)                                                 \
93566b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \
93666b6f755SWilly Tarreau		  "r"(_num)                                                   \
93766b6f755SWilly Tarreau		: "memory", "cc"                                              \
93866b6f755SWilly Tarreau	);                                                                    \
93966b6f755SWilly Tarreau	_arg1;                                                                \
94066b6f755SWilly Tarreau})
94166b6f755SWilly Tarreau
94266b6f755SWilly Tarreau#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
94366b6f755SWilly Tarreau({                                                                            \
94466b6f755SWilly Tarreau	register long _num  asm("x8") = (num);                                \
94566b6f755SWilly Tarreau	register long _arg1 asm("x0") = (long)(arg1);                         \
94666b6f755SWilly Tarreau	register long _arg2 asm("x1") = (long)(arg2);                         \
94766b6f755SWilly Tarreau	register long _arg3 asm("x2") = (long)(arg3);                         \
94866b6f755SWilly Tarreau	register long _arg4 asm("x3") = (long)(arg4);                         \
94966b6f755SWilly Tarreau	register long _arg5 asm("x4") = (long)(arg5);                         \
95066b6f755SWilly Tarreau									      \
95166b6f755SWilly Tarreau	asm volatile (                                                        \
95266b6f755SWilly Tarreau		"svc #0\n"                                                    \
95366b6f755SWilly Tarreau		: "=r" (_arg1)                                                \
95466b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
95566b6f755SWilly Tarreau		  "r"(_num)                                                   \
95666b6f755SWilly Tarreau		: "memory", "cc"                                              \
95766b6f755SWilly Tarreau	);                                                                    \
95866b6f755SWilly Tarreau	_arg1;                                                                \
95966b6f755SWilly Tarreau})
96066b6f755SWilly Tarreau
96166b6f755SWilly Tarreau#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
96266b6f755SWilly Tarreau({                                                                            \
96366b6f755SWilly Tarreau	register long _num  asm("x8") = (num);                                \
96466b6f755SWilly Tarreau	register long _arg1 asm("x0") = (long)(arg1);                         \
96566b6f755SWilly Tarreau	register long _arg2 asm("x1") = (long)(arg2);                         \
96666b6f755SWilly Tarreau	register long _arg3 asm("x2") = (long)(arg3);                         \
96766b6f755SWilly Tarreau	register long _arg4 asm("x3") = (long)(arg4);                         \
96866b6f755SWilly Tarreau	register long _arg5 asm("x4") = (long)(arg5);                         \
96966b6f755SWilly Tarreau	register long _arg6 asm("x5") = (long)(arg6);                         \
97066b6f755SWilly Tarreau									      \
97166b6f755SWilly Tarreau	asm volatile (                                                        \
97266b6f755SWilly Tarreau		"svc #0\n"                                                    \
97366b6f755SWilly Tarreau		: "=r" (_arg1)                                                \
97466b6f755SWilly Tarreau		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
97566b6f755SWilly Tarreau		  "r"(_arg6), "r"(_num)                                       \
97666b6f755SWilly Tarreau		: "memory", "cc"                                              \
97766b6f755SWilly Tarreau	);                                                                    \
97866b6f755SWilly Tarreau	_arg1;                                                                \
97966b6f755SWilly Tarreau})
98066b6f755SWilly Tarreau
98166b6f755SWilly Tarreau/* startup code */
98266b6f755SWilly Tarreauasm(".section .text\n"
98366b6f755SWilly Tarreau    ".global _start\n"
98466b6f755SWilly Tarreau    "_start:\n"
98566b6f755SWilly Tarreau    "ldr x0, [sp]\n"              // argc (x0) was in the stack
98666b6f755SWilly Tarreau    "add x1, sp, 8\n"             // argv (x1) = sp
98766b6f755SWilly Tarreau    "lsl x2, x0, 3\n"             // envp (x2) = 8*argc ...
98866b6f755SWilly Tarreau    "add x2, x2, 8\n"             //           + 8 (skip null)
98966b6f755SWilly Tarreau    "add x2, x2, x1\n"            //           + argv
99066b6f755SWilly Tarreau    "and sp, x1, -16\n"           // sp must be 16-byte aligned in the callee
99166b6f755SWilly Tarreau    "bl main\n"                   // main() returns the status code, we'll exit with it.
99266b6f755SWilly Tarreau    "mov x8, 93\n"                // NR_exit == 93
99366b6f755SWilly Tarreau    "svc #0\n"
99466b6f755SWilly Tarreau    "");
99566b6f755SWilly Tarreau
99666b6f755SWilly Tarreau/* fcntl / open */
99766b6f755SWilly Tarreau#define O_RDONLY            0
99866b6f755SWilly Tarreau#define O_WRONLY            1
99966b6f755SWilly Tarreau#define O_RDWR              2
100066b6f755SWilly Tarreau#define O_CREAT          0x40
100166b6f755SWilly Tarreau#define O_EXCL           0x80
100266b6f755SWilly Tarreau#define O_NOCTTY        0x100
100366b6f755SWilly Tarreau#define O_TRUNC         0x200
100466b6f755SWilly Tarreau#define O_APPEND        0x400
100566b6f755SWilly Tarreau#define O_NONBLOCK      0x800
100666b6f755SWilly Tarreau#define O_DIRECTORY    0x4000
100766b6f755SWilly Tarreau
100866b6f755SWilly Tarreau/* The struct returned by the newfstatat() syscall. Differs slightly from the
100966b6f755SWilly Tarreau * x86_64's stat one by field ordering, so be careful.
101066b6f755SWilly Tarreau */
101166b6f755SWilly Tarreaustruct sys_stat_struct {
101266b6f755SWilly Tarreau	unsigned long   st_dev;
101366b6f755SWilly Tarreau	unsigned long   st_ino;
101466b6f755SWilly Tarreau	unsigned int    st_mode;
101566b6f755SWilly Tarreau	unsigned int    st_nlink;
101666b6f755SWilly Tarreau	unsigned int    st_uid;
101766b6f755SWilly Tarreau	unsigned int    st_gid;
101866b6f755SWilly Tarreau
101966b6f755SWilly Tarreau	unsigned long   st_rdev;
102066b6f755SWilly Tarreau	unsigned long   __pad1;
102166b6f755SWilly Tarreau	long            st_size;
102266b6f755SWilly Tarreau	int             st_blksize;
102366b6f755SWilly Tarreau	int             __pad2;
102466b6f755SWilly Tarreau
102566b6f755SWilly Tarreau	long            st_blocks;
102666b6f755SWilly Tarreau	long            st_atime;
102766b6f755SWilly Tarreau	unsigned long   st_atime_nsec;
102866b6f755SWilly Tarreau	long            st_mtime;
102966b6f755SWilly Tarreau
103066b6f755SWilly Tarreau	unsigned long   st_mtime_nsec;
103166b6f755SWilly Tarreau	long            st_ctime;
103266b6f755SWilly Tarreau	unsigned long   st_ctime_nsec;
103366b6f755SWilly Tarreau	unsigned int    __unused[2];
103466b6f755SWilly Tarreau};
103566b6f755SWilly Tarreau
103666b6f755SWilly Tarreau#elif defined(__mips__) && defined(_ABIO32)
103766b6f755SWilly Tarreau/* Syscalls for MIPS ABI O32 :
103866b6f755SWilly Tarreau *   - WARNING! there's always a delayed slot!
103966b6f755SWilly Tarreau *   - WARNING again, the syntax is different, registers take a '$' and numbers
104066b6f755SWilly Tarreau *     do not.
104166b6f755SWilly Tarreau *   - registers are 32-bit
104266b6f755SWilly Tarreau *   - stack is 8-byte aligned
104366b6f755SWilly Tarreau *   - syscall number is passed in v0 (starts at 0xfa0).
104466b6f755SWilly Tarreau *   - arguments are in a0, a1, a2, a3, then the stack. The caller needs to
104566b6f755SWilly Tarreau *     leave some room in the stack for the callee to save a0..a3 if needed.
104666b6f755SWilly Tarreau *   - Many registers are clobbered, in fact only a0..a2 and s0..s8 are
104766b6f755SWilly Tarreau *     preserved. See: https://www.linux-mips.org/wiki/Syscall as well as
104866b6f755SWilly Tarreau *     scall32-o32.S in the kernel sources.
104966b6f755SWilly Tarreau *   - the system call is performed by calling "syscall"
105066b6f755SWilly Tarreau *   - syscall return comes in v0, and register a3 needs to be checked to know
10519a83f9aeSBhaskar Chowdhury *     if an error occurred, in which case errno is in v0.
105266b6f755SWilly Tarreau *   - the arguments are cast to long and assigned into the target registers
105366b6f755SWilly Tarreau *     which are then simply passed as registers to the asm code, so that we
105466b6f755SWilly Tarreau *     don't have to experience issues with register constraints.
105566b6f755SWilly Tarreau */
105666b6f755SWilly Tarreau
105766b6f755SWilly Tarreau#define my_syscall0(num)                                                      \
105866b6f755SWilly Tarreau({                                                                            \
105966b6f755SWilly Tarreau	register long _num asm("v0") = (num);                                 \
106066b6f755SWilly Tarreau	register long _arg4 asm("a3");                                        \
106166b6f755SWilly Tarreau									      \
106266b6f755SWilly Tarreau	asm volatile (                                                        \
106366b6f755SWilly Tarreau		"addiu $sp, $sp, -32\n"                                       \
106466b6f755SWilly Tarreau		"syscall\n"                                                   \
106566b6f755SWilly Tarreau		"addiu $sp, $sp, 32\n"                                        \
106666b6f755SWilly Tarreau		: "=r"(_num), "=r"(_arg4)                                     \
106766b6f755SWilly Tarreau		: "r"(_num)                                                   \
106866b6f755SWilly Tarreau		: "memory", "cc", "at", "v1", "hi", "lo",                     \
1069f90a66d6SWilly Tarreau		  "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"  \
107066b6f755SWilly Tarreau	);                                                                    \
107166b6f755SWilly Tarreau	_arg4 ? -_num : _num;                                                 \
107266b6f755SWilly Tarreau})
107366b6f755SWilly Tarreau
107466b6f755SWilly Tarreau#define my_syscall1(num, arg1)                                                \
107566b6f755SWilly Tarreau({                                                                            \
107666b6f755SWilly Tarreau	register long _num asm("v0") = (num);                                 \
107766b6f755SWilly Tarreau	register long _arg1 asm("a0") = (long)(arg1);                         \
107866b6f755SWilly Tarreau	register long _arg4 asm("a3");                                        \
107966b6f755SWilly Tarreau									      \
108066b6f755SWilly Tarreau	asm volatile (                                                        \
108166b6f755SWilly Tarreau		"addiu $sp, $sp, -32\n"                                       \
108266b6f755SWilly Tarreau		"syscall\n"                                                   \
108366b6f755SWilly Tarreau		"addiu $sp, $sp, 32\n"                                        \
108466b6f755SWilly Tarreau		: "=r"(_num), "=r"(_arg4)                                     \
108566b6f755SWilly Tarreau		: "0"(_num),                                                  \
108666b6f755SWilly Tarreau		  "r"(_arg1)                                                  \
108766b6f755SWilly Tarreau		: "memory", "cc", "at", "v1", "hi", "lo",                     \
1088f90a66d6SWilly Tarreau		  "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"  \
108966b6f755SWilly Tarreau	);                                                                    \
109066b6f755SWilly Tarreau	_arg4 ? -_num : _num;                                                 \
109166b6f755SWilly Tarreau})
109266b6f755SWilly Tarreau
109366b6f755SWilly Tarreau#define my_syscall2(num, arg1, arg2)                                          \
109466b6f755SWilly Tarreau({                                                                            \
109566b6f755SWilly Tarreau	register long _num asm("v0") = (num);                                 \
109666b6f755SWilly Tarreau	register long _arg1 asm("a0") = (long)(arg1);                         \
109766b6f755SWilly Tarreau	register long _arg2 asm("a1") = (long)(arg2);                         \
109866b6f755SWilly Tarreau	register long _arg4 asm("a3");                                        \
109966b6f755SWilly Tarreau									      \
110066b6f755SWilly Tarreau	asm volatile (                                                        \
110166b6f755SWilly Tarreau		"addiu $sp, $sp, -32\n"                                       \
110266b6f755SWilly Tarreau		"syscall\n"                                                   \
110366b6f755SWilly Tarreau		"addiu $sp, $sp, 32\n"                                        \
110466b6f755SWilly Tarreau		: "=r"(_num), "=r"(_arg4)                                     \
110566b6f755SWilly Tarreau		: "0"(_num),                                                  \
110666b6f755SWilly Tarreau		  "r"(_arg1), "r"(_arg2)                                      \
110766b6f755SWilly Tarreau		: "memory", "cc", "at", "v1", "hi", "lo",                     \
1108f90a66d6SWilly Tarreau		  "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"  \
110966b6f755SWilly Tarreau	);                                                                    \
111066b6f755SWilly Tarreau	_arg4 ? -_num : _num;                                                 \
111166b6f755SWilly Tarreau})
111266b6f755SWilly Tarreau
111366b6f755SWilly Tarreau#define my_syscall3(num, arg1, arg2, arg3)                                    \
111466b6f755SWilly Tarreau({                                                                            \
111566b6f755SWilly Tarreau	register long _num asm("v0")  = (num);                                \
111666b6f755SWilly Tarreau	register long _arg1 asm("a0") = (long)(arg1);                         \
111766b6f755SWilly Tarreau	register long _arg2 asm("a1") = (long)(arg2);                         \
111866b6f755SWilly Tarreau	register long _arg3 asm("a2") = (long)(arg3);                         \
111966b6f755SWilly Tarreau	register long _arg4 asm("a3");                                        \
112066b6f755SWilly Tarreau									      \
112166b6f755SWilly Tarreau	asm volatile (                                                        \
112266b6f755SWilly Tarreau		"addiu $sp, $sp, -32\n"                                       \
112366b6f755SWilly Tarreau		"syscall\n"                                                   \
112466b6f755SWilly Tarreau		"addiu $sp, $sp, 32\n"                                        \
112566b6f755SWilly Tarreau		: "=r"(_num), "=r"(_arg4)                                     \
112666b6f755SWilly Tarreau		: "0"(_num),                                                  \
112766b6f755SWilly Tarreau		  "r"(_arg1), "r"(_arg2), "r"(_arg3)                          \
112866b6f755SWilly Tarreau		: "memory", "cc", "at", "v1", "hi", "lo",                     \
1129f90a66d6SWilly Tarreau		  "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"  \
113066b6f755SWilly Tarreau	);                                                                    \
113166b6f755SWilly Tarreau	_arg4 ? -_num : _num;                                                 \
113266b6f755SWilly Tarreau})
113366b6f755SWilly Tarreau
113466b6f755SWilly Tarreau#define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
113566b6f755SWilly Tarreau({                                                                            \
113666b6f755SWilly Tarreau	register long _num asm("v0") = (num);                                 \
113766b6f755SWilly Tarreau	register long _arg1 asm("a0") = (long)(arg1);                         \
113866b6f755SWilly Tarreau	register long _arg2 asm("a1") = (long)(arg2);                         \
113966b6f755SWilly Tarreau	register long _arg3 asm("a2") = (long)(arg3);                         \
114066b6f755SWilly Tarreau	register long _arg4 asm("a3") = (long)(arg4);                         \
114166b6f755SWilly Tarreau									      \
114266b6f755SWilly Tarreau	asm volatile (                                                        \
114366b6f755SWilly Tarreau		"addiu $sp, $sp, -32\n"                                       \
114466b6f755SWilly Tarreau		"syscall\n"                                                   \
114566b6f755SWilly Tarreau		"addiu $sp, $sp, 32\n"                                        \
114666b6f755SWilly Tarreau		: "=r" (_num), "=r"(_arg4)                                    \
114766b6f755SWilly Tarreau		: "0"(_num),                                                  \
114866b6f755SWilly Tarreau		  "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4)              \
114966b6f755SWilly Tarreau		: "memory", "cc", "at", "v1", "hi", "lo",                     \
1150f90a66d6SWilly Tarreau		  "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"  \
115166b6f755SWilly Tarreau	);                                                                    \
115266b6f755SWilly Tarreau	_arg4 ? -_num : _num;                                                 \
115366b6f755SWilly Tarreau})
115466b6f755SWilly Tarreau
115566b6f755SWilly Tarreau#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
115666b6f755SWilly Tarreau({                                                                            \
115766b6f755SWilly Tarreau	register long _num asm("v0") = (num);                                 \
115866b6f755SWilly Tarreau	register long _arg1 asm("a0") = (long)(arg1);                         \
115966b6f755SWilly Tarreau	register long _arg2 asm("a1") = (long)(arg2);                         \
116066b6f755SWilly Tarreau	register long _arg3 asm("a2") = (long)(arg3);                         \
116166b6f755SWilly Tarreau	register long _arg4 asm("a3") = (long)(arg4);                         \
116266b6f755SWilly Tarreau	register long _arg5 = (long)(arg5);				      \
116366b6f755SWilly Tarreau									      \
116466b6f755SWilly Tarreau	asm volatile (                                                        \
116566b6f755SWilly Tarreau		"addiu $sp, $sp, -32\n"                                       \
116666b6f755SWilly Tarreau		"sw %7, 16($sp)\n"                                            \
116766b6f755SWilly Tarreau		"syscall\n  "                                                 \
116866b6f755SWilly Tarreau		"addiu $sp, $sp, 32\n"                                        \
116966b6f755SWilly Tarreau		: "=r" (_num), "=r"(_arg4)                                    \
117066b6f755SWilly Tarreau		: "0"(_num),                                                  \
117166b6f755SWilly Tarreau		  "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5)  \
117266b6f755SWilly Tarreau		: "memory", "cc", "at", "v1", "hi", "lo",                     \
1173f90a66d6SWilly Tarreau		  "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9"  \
117466b6f755SWilly Tarreau	);                                                                    \
117566b6f755SWilly Tarreau	_arg4 ? -_num : _num;                                                 \
117666b6f755SWilly Tarreau})
117766b6f755SWilly Tarreau
117866b6f755SWilly Tarreau/* startup code, note that it's called __start on MIPS */
117966b6f755SWilly Tarreauasm(".section .text\n"
118066b6f755SWilly Tarreau    ".set nomips16\n"
118166b6f755SWilly Tarreau    ".global __start\n"
118266b6f755SWilly Tarreau    ".set    noreorder\n"
118366b6f755SWilly Tarreau    ".option pic0\n"
118466b6f755SWilly Tarreau    ".ent __start\n"
118566b6f755SWilly Tarreau    "__start:\n"
118666b6f755SWilly Tarreau    "lw $a0,($sp)\n"              // argc was in the stack
118766b6f755SWilly Tarreau    "addiu  $a1, $sp, 4\n"        // argv = sp + 4
118866b6f755SWilly Tarreau    "sll $a2, $a0, 2\n"           // a2 = argc * 4
118966b6f755SWilly Tarreau    "add   $a2, $a2, $a1\n"       // envp = argv + 4*argc ...
119066b6f755SWilly Tarreau    "addiu $a2, $a2, 4\n"         //        ... + 4
119166b6f755SWilly Tarreau    "li $t0, -8\n"
119266b6f755SWilly Tarreau    "and $sp, $sp, $t0\n"         // sp must be 8-byte aligned
119366b6f755SWilly Tarreau    "addiu $sp,$sp,-16\n"         // the callee expects to save a0..a3 there!
119466b6f755SWilly Tarreau    "jal main\n"                  // main() returns the status code, we'll exit with it.
119566b6f755SWilly Tarreau    "nop\n"                       // delayed slot
1196de0244aeSWilly Tarreau    "move $a0, $v0\n"             // retrieve 32-bit exit code from v0
119766b6f755SWilly Tarreau    "li $v0, 4001\n"              // NR_exit == 4001
119866b6f755SWilly Tarreau    "syscall\n"
119966b6f755SWilly Tarreau    ".end __start\n"
120066b6f755SWilly Tarreau    "");
120166b6f755SWilly Tarreau
120266b6f755SWilly Tarreau/* fcntl / open */
120366b6f755SWilly Tarreau#define O_RDONLY            0
120466b6f755SWilly Tarreau#define O_WRONLY            1
120566b6f755SWilly Tarreau#define O_RDWR              2
120666b6f755SWilly Tarreau#define O_APPEND       0x0008
120766b6f755SWilly Tarreau#define O_NONBLOCK     0x0080
120866b6f755SWilly Tarreau#define O_CREAT        0x0100
120966b6f755SWilly Tarreau#define O_TRUNC        0x0200
121066b6f755SWilly Tarreau#define O_EXCL         0x0400
121166b6f755SWilly Tarreau#define O_NOCTTY       0x0800
121266b6f755SWilly Tarreau#define O_DIRECTORY   0x10000
121366b6f755SWilly Tarreau
121466b6f755SWilly Tarreau/* The struct returned by the stat() syscall. 88 bytes are returned by the
121566b6f755SWilly Tarreau * syscall.
121666b6f755SWilly Tarreau */
121766b6f755SWilly Tarreaustruct sys_stat_struct {
121866b6f755SWilly Tarreau	unsigned int  st_dev;
121966b6f755SWilly Tarreau	long          st_pad1[3];
122066b6f755SWilly Tarreau	unsigned long st_ino;
122166b6f755SWilly Tarreau	unsigned int  st_mode;
122266b6f755SWilly Tarreau	unsigned int  st_nlink;
122366b6f755SWilly Tarreau	unsigned int  st_uid;
122466b6f755SWilly Tarreau	unsigned int  st_gid;
122566b6f755SWilly Tarreau	unsigned int  st_rdev;
122666b6f755SWilly Tarreau	long          st_pad2[2];
122766b6f755SWilly Tarreau	long          st_size;
122866b6f755SWilly Tarreau	long          st_pad3;
122966b6f755SWilly Tarreau	long          st_atime;
123066b6f755SWilly Tarreau	long          st_atime_nsec;
123166b6f755SWilly Tarreau	long          st_mtime;
123266b6f755SWilly Tarreau	long          st_mtime_nsec;
123366b6f755SWilly Tarreau	long          st_ctime;
123466b6f755SWilly Tarreau	long          st_ctime_nsec;
123566b6f755SWilly Tarreau	long          st_blksize;
123666b6f755SWilly Tarreau	long          st_blocks;
123766b6f755SWilly Tarreau	long          st_pad4[14];
123866b6f755SWilly Tarreau};
123966b6f755SWilly Tarreau
1240582e84f7SPranith Kumar#elif defined(__riscv)
1241582e84f7SPranith Kumar
1242582e84f7SPranith Kumar#if   __riscv_xlen == 64
1243582e84f7SPranith Kumar#define PTRLOG "3"
1244582e84f7SPranith Kumar#define SZREG  "8"
1245582e84f7SPranith Kumar#elif __riscv_xlen == 32
1246582e84f7SPranith Kumar#define PTRLOG "2"
1247582e84f7SPranith Kumar#define SZREG  "4"
1248582e84f7SPranith Kumar#endif
1249582e84f7SPranith Kumar
1250582e84f7SPranith Kumar/* Syscalls for RISCV :
1251582e84f7SPranith Kumar *   - stack is 16-byte aligned
1252582e84f7SPranith Kumar *   - syscall number is passed in a7