feat(syscall): add x86_64 raw syscall layer, errno, internal ABI headers
This commit is contained in:
@@ -0,0 +1,115 @@
|
|||||||
|
#ifndef VLIBC_INTERNAL_ARCH_X86_64_SYSCALL_ARCH_H
|
||||||
|
#define VLIBC_INTERNAL_ARCH_X86_64_SYSCALL_ARCH_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vlibc — x86_64 raw syscall entry (arch layer).
|
||||||
|
*
|
||||||
|
* The System V AMD64 kernel ABI: the syscall number goes in rax, arguments in
|
||||||
|
* rdi, rsi, rdx, r10, r8, r9 (this order; the fourth argument is r10, NOT
|
||||||
|
* rcx), and the kernel clobbers rcx and r11. The kernel returns the raw
|
||||||
|
* result in rax: a non-negative value on success, or -errno on error. Callers
|
||||||
|
* funnel rax through syscall_ret() (see src/internal/syscall.h), which
|
||||||
|
* translates the negative-errno convention into C return/-1 + errno.
|
||||||
|
*
|
||||||
|
* These wrappers take `long` arguments and return `long` so that pointer-sized
|
||||||
|
* syscall arguments (addresses, off_t) pass through without truncation; the
|
||||||
|
* kernel reads exactly the low 64 bits of each register, so the upper bits of
|
||||||
|
* `long` arguments are irrelevant.
|
||||||
|
*
|
||||||
|
* Each wrapper is `always_inline` so that even a -O0 build collapses to a
|
||||||
|
* bare `syscall` instruction with no call frame. The "memory" clobber tells
|
||||||
|
* the compiler the syscall may read or write anything the caller can see,
|
||||||
|
* which is always the safe assumption.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The __syscall<n> names sit in the implementation-reserved namespace (they
|
||||||
|
* are this libc's private kernel-ABI seam, never public API), and every
|
||||||
|
* argument is a `long` because that is the shape of the x86_64 syscall
|
||||||
|
* register file — both properties are intentional, so the corresponding
|
||||||
|
* bugprone checks are waived per function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// NOLINTBEGIN(bugprone-easily-swappable-parameters,bugprone-reserved-identifier)
|
||||||
|
|
||||||
|
static inline long __attribute__((always_inline))
|
||||||
|
__syscall0(long n)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
|
||||||
|
__asm__ volatile("syscall" : "=a"(ret) : "a"(n) : "rcx", "r11", "memory");
|
||||||
|
return (long)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long __attribute__((always_inline))
|
||||||
|
__syscall1(long n, long a)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
|
||||||
|
__asm__ volatile("syscall" : "=a"(ret) : "a"(n), "D"(a) : "rcx", "r11", "memory");
|
||||||
|
return (long)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long __attribute__((always_inline))
|
||||||
|
__syscall2(long n, long a, long b)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
|
||||||
|
__asm__ volatile("syscall" : "=a"(ret) : "a"(n), "D"(a), "S"(b) : "rcx", "r11", "memory");
|
||||||
|
return (long)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long __attribute__((always_inline))
|
||||||
|
__syscall3(long n, long a, long b, long c)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
|
||||||
|
__asm__ volatile("syscall"
|
||||||
|
: "=a"(ret)
|
||||||
|
: "a"(n), "D"(a), "S"(b), "d"(c)
|
||||||
|
: "rcx", "r11", "memory");
|
||||||
|
return (long)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long __attribute__((always_inline))
|
||||||
|
__syscall4(long n, long a, long b, long c, long d)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
|
||||||
|
__asm__ volatile("syscall"
|
||||||
|
: "=a"(ret)
|
||||||
|
: "a"(n), "D"(a), "S"(b), "d"(c), "r"(d)
|
||||||
|
: "rcx", "r11", "memory");
|
||||||
|
return (long)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long __attribute__((always_inline))
|
||||||
|
__syscall5(long n, long a, long b, long c, long d, long e)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
|
||||||
|
__asm__ volatile("syscall"
|
||||||
|
: "=a"(ret)
|
||||||
|
: "a"(n), "D"(a), "S"(b), "d"(c), "r"(d), "r"(e)
|
||||||
|
: "rcx", "r11", "memory");
|
||||||
|
return (long)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long __attribute__((always_inline))
|
||||||
|
__syscall6(long n, long a, long b, long c, long d, long e, long f)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
register long r10 __asm__("r10") = d;
|
||||||
|
register long r8 __asm__("r8") = e;
|
||||||
|
register long r9 __asm__("r9") = f;
|
||||||
|
|
||||||
|
__asm__ volatile("syscall"
|
||||||
|
: "=a"(ret)
|
||||||
|
: "a"(n), "D"(a), "S"(b), "d"(c), "r"(r10), "r"(r8), "r"(r9)
|
||||||
|
: "rcx", "r11", "memory");
|
||||||
|
return (long)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOLINTEND(bugprone-easily-swappable-parameters,bugprone-reserved-identifier)
|
||||||
|
|
||||||
|
#endif /* VLIBC_INTERNAL_ARCH_X86_64_SYSCALL_ARCH_H */
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
#ifndef VLIBC_INTERNAL_ATOMIC_H
|
||||||
|
#define VLIBC_INTERNAL_ATOMIC_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vlibc — internal atomics.
|
||||||
|
*
|
||||||
|
* Thin wrappers over the GCC __atomic_* builtins, so internal code writes
|
||||||
|
* portable-looking atomics without depending on a particular <stdatomic.h>.
|
||||||
|
* The wrappers operate on int and long (the widths internal counters and
|
||||||
|
* refcounts actually use); pointers get their own load/store/cmpxchg trio.
|
||||||
|
*
|
||||||
|
* All wrappers are sequentially consistent by default: a libc-internal
|
||||||
|
* operation is almost never hot enough to justify weakening, and a single
|
||||||
|
* memory order everywhere is the least error-prone choice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
atomic_load(const volatile int *p)
|
||||||
|
{
|
||||||
|
return __atomic_load_n(p, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
atomic_store(volatile int *p, int v) // NOLINT(readability-non-const-parameter)
|
||||||
|
{
|
||||||
|
__atomic_store_n(p, v, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
atomic_fetch_add(volatile int *p, int v) // NOLINT(readability-non-const-parameter)
|
||||||
|
{
|
||||||
|
return __atomic_fetch_add(p, v, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
atomic_exchange(volatile int *p, int v) // NOLINT(readability-non-const-parameter)
|
||||||
|
{
|
||||||
|
return __atomic_exchange_n(p, v, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare-and-swap: store want into *p iff *p == expect; return the value
|
||||||
|
* previously in *p (equal to expect on success). The (expect, want) order
|
||||||
|
* matches the C11 atomic_compare_exchange and GCC builtin convention.
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
atomic_cas(volatile int *p, int expect,
|
||||||
|
int want) // NOLINT(bugprone-easily-swappable-parameters,readability-non-const-parameter)
|
||||||
|
{
|
||||||
|
int old = expect;
|
||||||
|
|
||||||
|
__atomic_compare_exchange_n(p, &old, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long
|
||||||
|
atomic_load_l(const volatile long *p)
|
||||||
|
{
|
||||||
|
return __atomic_load_n(p, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
atomic_store_l(volatile long *p, long v) // NOLINT(readability-non-const-parameter)
|
||||||
|
{
|
||||||
|
__atomic_store_n(p, v, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long
|
||||||
|
atomic_fetch_add_l(volatile long *p, long v) // NOLINT(readability-non-const-parameter)
|
||||||
|
{
|
||||||
|
return __atomic_fetch_add(p, v, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long
|
||||||
|
atomic_exchange_l(volatile long *p, long v) // NOLINT(readability-non-const-parameter)
|
||||||
|
{
|
||||||
|
return __atomic_exchange_n(p, v, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline long
|
||||||
|
atomic_cas_l(
|
||||||
|
volatile long *p, long expect,
|
||||||
|
long want) // NOLINT(bugprone-easily-swappable-parameters,readability-non-const-parameter)
|
||||||
|
{
|
||||||
|
long old = expect;
|
||||||
|
|
||||||
|
__atomic_compare_exchange_n(p, &old, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
atomic_load_p(void *const volatile *p)
|
||||||
|
{
|
||||||
|
return __atomic_load_n(p, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
atomic_store_p(void *volatile *p, void *v) // NOLINT(readability-non-const-parameter)
|
||||||
|
{
|
||||||
|
__atomic_store_n(p, v, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
atomic_cas_p(
|
||||||
|
void *volatile *p, void *expect,
|
||||||
|
void *want) // NOLINT(bugprone-easily-swappable-parameters,readability-non-const-parameter)
|
||||||
|
{
|
||||||
|
void *old = expect;
|
||||||
|
|
||||||
|
__atomic_compare_exchange_n(p, &old, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
atomic_fence(void)
|
||||||
|
{
|
||||||
|
__atomic_thread_fence(__ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* VLIBC_INTERNAL_ATOMIC_H */
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "errno.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the address of the calling thread's errno slot: the TCB address
|
||||||
|
* (read through the x86_64 FS thread pointer) plus the fixed errno-slot
|
||||||
|
* offset, an ABI constant defined in errno.h and consumed by the TCB layout.
|
||||||
|
*/
|
||||||
|
int *
|
||||||
|
__errno_location(void) // NOLINT(bugprone-reserved-identifier)
|
||||||
|
{
|
||||||
|
return (int *)((char *)__builtin_thread_pointer() + VLIBC_TCB_ERRNO_OFF);
|
||||||
|
}
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
#ifndef VLIBC_INTERNAL_ERRNO_H
|
||||||
|
#define VLIBC_INTERNAL_ERRNO_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vlibc — internal errno (thread-local via the TCB).
|
||||||
|
*
|
||||||
|
* errno is per-thread state. It lives in a slot of the thread control block
|
||||||
|
* (TCB), addressed relative to the x86_64 FS thread pointer; there is no
|
||||||
|
* process-global errno object and no compiler-managed TLS (`__thread`) here.
|
||||||
|
*
|
||||||
|
* The offset of the errno slot inside the TCB is an ABI constant defined
|
||||||
|
* below and consumed by the authoritative TCB layout (see the startup todo,
|
||||||
|
* which owns the TCB/DTV layout). No other layer may re-derive errno's
|
||||||
|
* location: it must reference VLIBC_TCB_ERRNO_OFF.
|
||||||
|
*
|
||||||
|
* Slot 0 (offset 0) of the TCB is reserved for the TCB self pointer by
|
||||||
|
* convention: __errno_location() reads the thread pointer with
|
||||||
|
* __builtin_thread_pointer(), which on x86_64 loads the value at %fs:0, i.e.
|
||||||
|
* the self pointer the TCB layout must store at its first word. The errno
|
||||||
|
* slot therefore starts at offset 8, immediately after the self pointer, so
|
||||||
|
* it shares the TCB's first cache line (it is the hottest TCB member). The
|
||||||
|
* slot is 8 bytes for natural alignment; errno occupies the first 4.
|
||||||
|
*/
|
||||||
|
#define VLIBC_TCB_ERRNO_OFF 8
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the address of the calling thread's errno slot.
|
||||||
|
*
|
||||||
|
* Requires the thread pointer (FS) to be initialized to a TCB whose first
|
||||||
|
* word is the TCB's own address — the startup todo owns that bootstrap and
|
||||||
|
* sets it before any code that can touch errno runs. This function itself
|
||||||
|
* performs no setup and no other TCB access.
|
||||||
|
*
|
||||||
|
* The name sits in the implementation-reserved namespace deliberately: it is
|
||||||
|
* this libc's private errno accessor, not public API.
|
||||||
|
*/
|
||||||
|
int *
|
||||||
|
__errno_location(void); // NOLINT(bugprone-reserved-identifier)
|
||||||
|
|
||||||
|
/* The conventional errno lvalue; resolves to the caller's TCB slot. */
|
||||||
|
#define errno (*__errno_location())
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Error numbers: the Linux errno ABI (asm-generic/errno-base.h plus
|
||||||
|
* asm-generic/errno.h, which is the table x86_64 uses), transcribed as
|
||||||
|
* kernel-ABI facts. These values are fixed and shared with the kernel. The
|
||||||
|
* public <errno.h> is owned by a later todo; this internal copy is what
|
||||||
|
* internal code and tests compile against.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EPERM 1 /* Operation not permitted */
|
||||||
|
#define ENOENT 2 /* No such file or directory */
|
||||||
|
#define ESRCH 3 /* No such process */
|
||||||
|
#define EINTR 4 /* Interrupted system call */
|
||||||
|
#define EIO 5 /* I/O error */
|
||||||
|
#define ENXIO 6 /* No such device or address */
|
||||||
|
#define E2BIG 7 /* Argument list too long */
|
||||||
|
#define ENOEXEC 8 /* Exec format error */
|
||||||
|
#define EBADF 9 /* Bad file descriptor */
|
||||||
|
#define ECHILD 10 /* No child processes */
|
||||||
|
#define EAGAIN 11 /* Try again */
|
||||||
|
#define ENOMEM 12 /* Out of memory */
|
||||||
|
#define EACCES 13 /* Permission denied */
|
||||||
|
#define EFAULT 14 /* Bad address */
|
||||||
|
#define ENOTBLK 15 /* Block device required */
|
||||||
|
#define EBUSY 16 /* Device or resource busy */
|
||||||
|
#define EEXIST 17 /* File exists */
|
||||||
|
#define EXDEV 18 /* Cross-device link */
|
||||||
|
#define ENODEV 19 /* No such device */
|
||||||
|
#define ENOTDIR 20 /* Not a directory */
|
||||||
|
#define EISDIR 21 /* Is a directory */
|
||||||
|
#define EINVAL 22 /* Invalid argument */
|
||||||
|
#define ENFILE 23 /* File table overflow */
|
||||||
|
#define EMFILE 24 /* Too many open files */
|
||||||
|
#define ENOTTY 25 /* Not a typewriter */
|
||||||
|
#define ETXTBSY 26 /* Text file busy */
|
||||||
|
#define EFBIG 27 /* File too large */
|
||||||
|
#define ENOSPC 28 /* No space left on device */
|
||||||
|
#define ESPIPE 29 /* Illegal seek */
|
||||||
|
#define EROFS 30 /* Read-only file system */
|
||||||
|
#define EMLINK 31 /* Too many links */
|
||||||
|
#define EPIPE 32 /* Broken pipe */
|
||||||
|
#define EDOM 33 /* Math argument out of domain of func */
|
||||||
|
#define ERANGE 34 /* Math result not representable */
|
||||||
|
#define EDEADLK 35 /* Resource deadlock would occur */
|
||||||
|
#define ENAMETOOLONG 36 /* File name too long */
|
||||||
|
#define ENOLCK 37 /* No record locks available */
|
||||||
|
#define ENOSYS 38 /* Invalid system call number */
|
||||||
|
#define ENOTEMPTY 39 /* Directory not empty */
|
||||||
|
#define ELOOP 40 /* Too many symbolic links encountered */
|
||||||
|
#define EWOULDBLOCK EAGAIN /* Operation would block */
|
||||||
|
#define ENOMSG 42 /* No message of desired type */
|
||||||
|
#define EIDRM 43 /* Identifier removed */
|
||||||
|
#define ECHRNG 44 /* Channel number out of range */
|
||||||
|
#define EL2NSYNC 45 /* Level 2 not synchronized */
|
||||||
|
#define EL3HLT 46 /* Level 3 halted */
|
||||||
|
#define EL3RST 47 /* Level 3 reset */
|
||||||
|
#define ELNRNG 48 /* Link number out of range */
|
||||||
|
#define EUNATCH 49 /* Protocol driver not attached */
|
||||||
|
#define ENOCSI 50 /* No CSI structure available */
|
||||||
|
#define EL2HLT 51 /* Level 2 halted */
|
||||||
|
#define EBADE 52 /* Invalid exchange */
|
||||||
|
#define EBADR 53 /* Invalid request descriptor */
|
||||||
|
#define EXFULL 54 /* Exchange full */
|
||||||
|
#define ENOANO 55 /* No anode */
|
||||||
|
#define EBADRQC 56 /* Invalid request code */
|
||||||
|
#define EBADSLT 57 /* Invalid slot */
|
||||||
|
#define EDEADLOCK EDEADLK /* File locking deadlock error */
|
||||||
|
#define EBFONT 59 /* Bad font file format */
|
||||||
|
#define ENOSTR 60 /* Device not a stream */
|
||||||
|
#define ENODATA 61 /* No data available */
|
||||||
|
#define ETIME 62 /* Timer expired */
|
||||||
|
#define ENOSR 63 /* Out of streams resources */
|
||||||
|
#define ENONET 64 /* Machine is not on the network */
|
||||||
|
#define ENOPKG 65 /* Package not installed */
|
||||||
|
#define EREMOTE 66 /* Object is remote */
|
||||||
|
#define ENOLINK 67 /* Link has been severed */
|
||||||
|
#define EADV 68 /* Advertise error */
|
||||||
|
#define ESRMNT 69 /* Srmount error */
|
||||||
|
#define ECOMM 70 /* Communication error on send */
|
||||||
|
#define EPROTO 71 /* Protocol error */
|
||||||
|
#define EMULTIHOP 72 /* Multihop attempted */
|
||||||
|
#define EDOTDOT 73 /* RFS specific error */
|
||||||
|
#define EBADMSG 74 /* Not a data message */
|
||||||
|
#define EOVERFLOW 75 /* Value too large for defined data type */
|
||||||
|
#define ENOTUNIQ 76 /* Name not unique on network */
|
||||||
|
#define EBADFD 77 /* File descriptor in bad state */
|
||||||
|
#define EREMCHG 78 /* Remote address changed */
|
||||||
|
#define ELIBACC 79 /* Can not access a needed shared library */
|
||||||
|
#define ELIBBAD 80 /* Accessing a corrupted shared library */
|
||||||
|
#define ELIBSCN 81 /* .lib section in a.out corrupted */
|
||||||
|
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
|
||||||
|
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
|
||||||
|
#define EILSEQ 84 /* Illegal byte sequence */
|
||||||
|
#define ERESTART 85 /* Interrupted system call should be restarted */
|
||||||
|
#define ESTRPIPE 86 /* Streams pipe error */
|
||||||
|
#define EUSERS 87 /* Too many users */
|
||||||
|
#define ENOTSOCK 88 /* Socket operation on non-socket */
|
||||||
|
#define EDESTADDRREQ 89 /* Destination address required */
|
||||||
|
#define EMSGSIZE 90 /* Message too long */
|
||||||
|
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
|
||||||
|
#define ENOPROTOOPT 92 /* Protocol not available */
|
||||||
|
#define EPROTONOSUPPORT 93 /* Protocol not supported */
|
||||||
|
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
|
||||||
|
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
||||||
|
#define EPFNOSUPPORT 96 /* Protocol family not supported */
|
||||||
|
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
|
||||||
|
#define EADDRINUSE 98 /* Address already in use */
|
||||||
|
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
|
||||||
|
#define ENETDOWN 100 /* Network is down */
|
||||||
|
#define ENETUNREACH 101 /* Network is unreachable */
|
||||||
|
#define ENETRESET 102 /* Network dropped connection because of reset */
|
||||||
|
#define ECONNABORTED 103 /* Software caused connection abort */
|
||||||
|
#define ECONNRESET 104 /* Connection reset by peer */
|
||||||
|
#define ENOBUFS 105 /* No buffer space available */
|
||||||
|
#define EISCONN 106 /* Transport endpoint is already connected */
|
||||||
|
#define ENOTCONN 107 /* Transport endpoint is not connected */
|
||||||
|
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
|
||||||
|
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
|
||||||
|
#define ETIMEDOUT 110 /* Connection timed out */
|
||||||
|
#define ECONNREFUSED 111 /* Connection refused */
|
||||||
|
#define EHOSTDOWN 112 /* Host is down */
|
||||||
|
#define EHOSTUNREACH 113 /* No route to host */
|
||||||
|
#define EALREADY 114 /* Operation already in progress */
|
||||||
|
#define EINPROGRESS 115 /* Operation now in progress */
|
||||||
|
#define ESTALE 116 /* Stale file handle */
|
||||||
|
#define EUCLEAN 117 /* Structure needs cleaning */
|
||||||
|
#define ENOTNAM 118 /* Not a XENIX named type file */
|
||||||
|
#define ENAVAIL 119 /* No XENIX semaphores available */
|
||||||
|
#define EISNAM 120 /* Is a named type file */
|
||||||
|
#define EREMOTEIO 121 /* Remote I/O error */
|
||||||
|
#define EDQUOT 122 /* Quota exceeded */
|
||||||
|
#define ENOMEDIUM 123 /* No medium found */
|
||||||
|
#define EMEDIUMTYPE 124 /* Wrong medium type */
|
||||||
|
#define ECANCELED 125 /* Operation canceled */
|
||||||
|
#define ENOKEY 126 /* Required key not available */
|
||||||
|
#define EKEYEXPIRED 127 /* Key has expired */
|
||||||
|
#define EKEYREVOKED 128 /* Key has been revoked */
|
||||||
|
#define EKEYREJECTED 129 /* Key was rejected by service */
|
||||||
|
#define EOWNERDEAD 130 /* Owner died */
|
||||||
|
#define ENOTRECOVERABLE 131 /* State not recoverable */
|
||||||
|
#define ERFKILL 132 /* Operation not possible due to RF-kill */
|
||||||
|
#define EHWPOISON 133 /* Memory page has hardware error */
|
||||||
|
|
||||||
|
#endif /* VLIBC_INTERNAL_ERRNO_H */
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef VLIBC_INTERNAL_LIBC_H
|
||||||
|
#define VLIBC_INTERNAL_LIBC_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vlibc — internal compiler-attribute shorthand.
|
||||||
|
*
|
||||||
|
* Everything internal to the library is declared with hidden visibility so
|
||||||
|
* that neither the static archive nor the shared library exports symbols
|
||||||
|
* outside the public API surface. The shared-library case matters most:
|
||||||
|
* without `hidden`, every internal helper would become a dynamic symbol that
|
||||||
|
* could be interposed or collide with a consumer's own symbols.
|
||||||
|
*/
|
||||||
|
#define hidden __attribute__((__visibility__("hidden")))
|
||||||
|
|
||||||
|
#endif /* VLIBC_INTERNAL_LIBC_H */
|
||||||
@@ -0,0 +1,423 @@
|
|||||||
|
#ifndef VLIBC_INTERNAL_SYSCALL_H
|
||||||
|
#define VLIBC_INTERNAL_SYSCALL_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vlibc — internal raw syscall layer.
|
||||||
|
*
|
||||||
|
* This header is the single kernel-ABI seam of the library: every syscall
|
||||||
|
* vlibc makes goes through the __syscall<n>() entry points below (defined
|
||||||
|
* per-architecture in arch/x86_64/syscall_arch.h) and its result is
|
||||||
|
* translated by syscall_ret() into the C return-code + errno convention.
|
||||||
|
*
|
||||||
|
* The SYS_* table below holds the x86_64 Linux syscall numbers, transcribed
|
||||||
|
* from the kernel's arch/x86/entry/syscalls/syscall_64.tbl (the same values
|
||||||
|
* glibc exposes as <asm/unistd_64.h>). These are pure kernel-ABI facts: the
|
||||||
|
* x86_64 table, NOT the asm-generic table, which differs on several numbers
|
||||||
|
* (e.g. x86_64 SYS_open is 2, SYS_mmap is 9). Numbers 337-423 are reserved
|
||||||
|
* by the kernel and intentionally absent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../arch/x86_64/syscall_arch.h" // IWYU pragma: keep
|
||||||
|
|
||||||
|
#include "../internal/libc.h"
|
||||||
|
|
||||||
|
#define SYS_read 0
|
||||||
|
#define SYS_write 1
|
||||||
|
#define SYS_open 2
|
||||||
|
#define SYS_close 3
|
||||||
|
#define SYS_stat 4
|
||||||
|
#define SYS_fstat 5
|
||||||
|
#define SYS_lstat 6
|
||||||
|
#define SYS_poll 7
|
||||||
|
#define SYS_lseek 8
|
||||||
|
#define SYS_mmap 9
|
||||||
|
#define SYS_mprotect 10
|
||||||
|
#define SYS_munmap 11
|
||||||
|
#define SYS_brk 12
|
||||||
|
#define SYS_rt_sigaction 13
|
||||||
|
#define SYS_rt_sigprocmask 14
|
||||||
|
#define SYS_rt_sigreturn 15
|
||||||
|
#define SYS_ioctl 16
|
||||||
|
#define SYS_pread64 17
|
||||||
|
#define SYS_pwrite64 18
|
||||||
|
#define SYS_readv 19
|
||||||
|
#define SYS_writev 20
|
||||||
|
#define SYS_access 21
|
||||||
|
#define SYS_pipe 22
|
||||||
|
#define SYS_select 23
|
||||||
|
#define SYS_sched_yield 24
|
||||||
|
#define SYS_mremap 25
|
||||||
|
#define SYS_msync 26
|
||||||
|
#define SYS_mincore 27
|
||||||
|
#define SYS_madvise 28
|
||||||
|
#define SYS_shmget 29
|
||||||
|
#define SYS_shmat 30
|
||||||
|
#define SYS_shmctl 31
|
||||||
|
#define SYS_dup 32
|
||||||
|
#define SYS_dup2 33
|
||||||
|
#define SYS_pause 34
|
||||||
|
#define SYS_nanosleep 35
|
||||||
|
#define SYS_getitimer 36
|
||||||
|
#define SYS_alarm 37
|
||||||
|
#define SYS_setitimer 38
|
||||||
|
#define SYS_getpid 39
|
||||||
|
#define SYS_sendfile 40
|
||||||
|
#define SYS_socket 41
|
||||||
|
#define SYS_connect 42
|
||||||
|
#define SYS_accept 43
|
||||||
|
#define SYS_sendto 44
|
||||||
|
#define SYS_recvfrom 45
|
||||||
|
#define SYS_sendmsg 46
|
||||||
|
#define SYS_recvmsg 47
|
||||||
|
#define SYS_shutdown 48
|
||||||
|
#define SYS_bind 49
|
||||||
|
#define SYS_listen 50
|
||||||
|
#define SYS_getsockname 51
|
||||||
|
#define SYS_getpeername 52
|
||||||
|
#define SYS_socketpair 53
|
||||||
|
#define SYS_setsockopt 54
|
||||||
|
#define SYS_getsockopt 55
|
||||||
|
#define SYS_clone 56
|
||||||
|
#define SYS_fork 57
|
||||||
|
#define SYS_vfork 58
|
||||||
|
#define SYS_execve 59
|
||||||
|
#define SYS_exit 60
|
||||||
|
#define SYS_wait4 61
|
||||||
|
#define SYS_kill 62
|
||||||
|
#define SYS_uname 63
|
||||||
|
#define SYS_semget 64
|
||||||
|
#define SYS_semop 65
|
||||||
|
#define SYS_semctl 66
|
||||||
|
#define SYS_shmdt 67
|
||||||
|
#define SYS_msgget 68
|
||||||
|
#define SYS_msgsnd 69
|
||||||
|
#define SYS_msgrcv 70
|
||||||
|
#define SYS_msgctl 71
|
||||||
|
#define SYS_fcntl 72
|
||||||
|
#define SYS_flock 73
|
||||||
|
#define SYS_fsync 74
|
||||||
|
#define SYS_fdatasync 75
|
||||||
|
#define SYS_truncate 76
|
||||||
|
#define SYS_ftruncate 77
|
||||||
|
#define SYS_getdents 78
|
||||||
|
#define SYS_getcwd 79
|
||||||
|
#define SYS_chdir 80
|
||||||
|
#define SYS_fchdir 81
|
||||||
|
#define SYS_rename 82
|
||||||
|
#define SYS_mkdir 83
|
||||||
|
#define SYS_rmdir 84
|
||||||
|
#define SYS_creat 85
|
||||||
|
#define SYS_link 86
|
||||||
|
#define SYS_unlink 87
|
||||||
|
#define SYS_symlink 88
|
||||||
|
#define SYS_readlink 89
|
||||||
|
#define SYS_chmod 90
|
||||||
|
#define SYS_fchmod 91
|
||||||
|
#define SYS_chown 92
|
||||||
|
#define SYS_fchown 93
|
||||||
|
#define SYS_lchown 94
|
||||||
|
#define SYS_umask 95
|
||||||
|
#define SYS_gettimeofday 96
|
||||||
|
#define SYS_getrlimit 97
|
||||||
|
#define SYS_getrusage 98
|
||||||
|
#define SYS_sysinfo 99
|
||||||
|
#define SYS_times 100
|
||||||
|
#define SYS_ptrace 101
|
||||||
|
#define SYS_getuid 102
|
||||||
|
#define SYS_syslog 103
|
||||||
|
#define SYS_getgid 104
|
||||||
|
#define SYS_setuid 105
|
||||||
|
#define SYS_setgid 106
|
||||||
|
#define SYS_geteuid 107
|
||||||
|
#define SYS_getegid 108
|
||||||
|
#define SYS_setpgid 109
|
||||||
|
#define SYS_getppid 110
|
||||||
|
#define SYS_getpgrp 111
|
||||||
|
#define SYS_setsid 112
|
||||||
|
#define SYS_setreuid 113
|
||||||
|
#define SYS_setregid 114
|
||||||
|
#define SYS_getgroups 115
|
||||||
|
#define SYS_setgroups 116
|
||||||
|
#define SYS_setresuid 117
|
||||||
|
#define SYS_getresuid 118
|
||||||
|
#define SYS_setresgid 119
|
||||||
|
#define SYS_getresgid 120
|
||||||
|
#define SYS_getpgid 121
|
||||||
|
#define SYS_setfsuid 122
|
||||||
|
#define SYS_setfsgid 123
|
||||||
|
#define SYS_getsid 124
|
||||||
|
#define SYS_capget 125
|
||||||
|
#define SYS_capset 126
|
||||||
|
#define SYS_rt_sigpending 127
|
||||||
|
#define SYS_rt_sigtimedwait 128
|
||||||
|
#define SYS_rt_sigqueueinfo 129
|
||||||
|
#define SYS_rt_sigsuspend 130
|
||||||
|
#define SYS_sigaltstack 131
|
||||||
|
#define SYS_utime 132
|
||||||
|
#define SYS_mknod 133
|
||||||
|
#define SYS_uselib 134
|
||||||
|
#define SYS_personality 135
|
||||||
|
#define SYS_ustat 136
|
||||||
|
#define SYS_statfs 137
|
||||||
|
#define SYS_fstatfs 138
|
||||||
|
#define SYS_sysfs 139
|
||||||
|
#define SYS_getpriority 140
|
||||||
|
#define SYS_setpriority 141
|
||||||
|
#define SYS_sched_setparam 142
|
||||||
|
#define SYS_sched_getparam 143
|
||||||
|
#define SYS_sched_setscheduler 144
|
||||||
|
#define SYS_sched_getscheduler 145
|
||||||
|
#define SYS_sched_get_priority_max 146
|
||||||
|
#define SYS_sched_get_priority_min 147
|
||||||
|
#define SYS_sched_rr_get_interval 148
|
||||||
|
#define SYS_mlock 149
|
||||||
|
#define SYS_munlock 150
|
||||||
|
#define SYS_mlockall 151
|
||||||
|
#define SYS_munlockall 152
|
||||||
|
#define SYS_vhangup 153
|
||||||
|
#define SYS_modify_ldt 154
|
||||||
|
#define SYS_pivot_root 155
|
||||||
|
#define SYS__sysctl 156
|
||||||
|
#define SYS_prctl 157
|
||||||
|
#define SYS_arch_prctl 158
|
||||||
|
#define SYS_adjtimex 159
|
||||||
|
#define SYS_setrlimit 160
|
||||||
|
#define SYS_chroot 161
|
||||||
|
#define SYS_sync 162
|
||||||
|
#define SYS_acct 163
|
||||||
|
#define SYS_settimeofday 164
|
||||||
|
#define SYS_mount 165
|
||||||
|
#define SYS_umount2 166
|
||||||
|
#define SYS_swapon 167
|
||||||
|
#define SYS_swapoff 168
|
||||||
|
#define SYS_reboot 169
|
||||||
|
#define SYS_sethostname 170
|
||||||
|
#define SYS_setdomainname 171
|
||||||
|
#define SYS_iopl 172
|
||||||
|
#define SYS_ioperm 173
|
||||||
|
#define SYS_create_module 174
|
||||||
|
#define SYS_init_module 175
|
||||||
|
#define SYS_delete_module 176
|
||||||
|
#define SYS_get_kernel_syms 177
|
||||||
|
#define SYS_query_module 178
|
||||||
|
#define SYS_quotactl 179
|
||||||
|
#define SYS_nfsservctl 180
|
||||||
|
#define SYS_getpmsg 181
|
||||||
|
#define SYS_putpmsg 182
|
||||||
|
#define SYS_afs_syscall 183
|
||||||
|
#define SYS_tuxcall 184
|
||||||
|
#define SYS_security 185
|
||||||
|
#define SYS_gettid 186
|
||||||
|
#define SYS_readahead 187
|
||||||
|
#define SYS_setxattr 188
|
||||||
|
#define SYS_lsetxattr 189
|
||||||
|
#define SYS_fsetxattr 190
|
||||||
|
#define SYS_getxattr 191
|
||||||
|
#define SYS_lgetxattr 192
|
||||||
|
#define SYS_fgetxattr 193
|
||||||
|
#define SYS_listxattr 194
|
||||||
|
#define SYS_llistxattr 195
|
||||||
|
#define SYS_flistxattr 196
|
||||||
|
#define SYS_removexattr 197
|
||||||
|
#define SYS_lremovexattr 198
|
||||||
|
#define SYS_fremovexattr 199
|
||||||
|
#define SYS_tkill 200
|
||||||
|
#define SYS_time 201
|
||||||
|
#define SYS_futex 202
|
||||||
|
#define SYS_sched_setaffinity 203
|
||||||
|
#define SYS_sched_getaffinity 204
|
||||||
|
#define SYS_set_thread_area 205
|
||||||
|
#define SYS_io_setup 206
|
||||||
|
#define SYS_io_destroy 207
|
||||||
|
#define SYS_io_getevents 208
|
||||||
|
#define SYS_io_submit 209
|
||||||
|
#define SYS_io_cancel 210
|
||||||
|
#define SYS_get_thread_area 211
|
||||||
|
#define SYS_lookup_dcookie 212
|
||||||
|
#define SYS_epoll_create 213
|
||||||
|
#define SYS_epoll_ctl_old 214
|
||||||
|
#define SYS_epoll_wait_old 215
|
||||||
|
#define SYS_remap_file_pages 216
|
||||||
|
#define SYS_getdents64 217
|
||||||
|
#define SYS_set_tid_address 218
|
||||||
|
#define SYS_restart_syscall 219
|
||||||
|
#define SYS_semtimedop 220
|
||||||
|
#define SYS_fadvise64 221
|
||||||
|
#define SYS_timer_create 222
|
||||||
|
#define SYS_timer_settime 223
|
||||||
|
#define SYS_timer_gettime 224
|
||||||
|
#define SYS_timer_getoverrun 225
|
||||||
|
#define SYS_timer_delete 226
|
||||||
|
#define SYS_clock_settime 227
|
||||||
|
#define SYS_clock_gettime 228
|
||||||
|
#define SYS_clock_getres 229
|
||||||
|
#define SYS_clock_nanosleep 230
|
||||||
|
#define SYS_exit_group 231
|
||||||
|
#define SYS_epoll_wait 232
|
||||||
|
#define SYS_epoll_ctl 233
|
||||||
|
#define SYS_tgkill 234
|
||||||
|
#define SYS_utimes 235
|
||||||
|
#define SYS_vserver 236
|
||||||
|
#define SYS_mbind 237
|
||||||
|
#define SYS_set_mempolicy 238
|
||||||
|
#define SYS_get_mempolicy 239
|
||||||
|
#define SYS_mq_open 240
|
||||||
|
#define SYS_mq_unlink 241
|
||||||
|
#define SYS_mq_timedsend 242
|
||||||
|
#define SYS_mq_timedreceive 243
|
||||||
|
#define SYS_mq_notify 244
|
||||||
|
#define SYS_mq_getsetattr 245
|
||||||
|
#define SYS_kexec_load 246
|
||||||
|
#define SYS_waitid 247
|
||||||
|
#define SYS_add_key 248
|
||||||
|
#define SYS_request_key 249
|
||||||
|
#define SYS_keyctl 250
|
||||||
|
#define SYS_ioprio_set 251
|
||||||
|
#define SYS_ioprio_get 252
|
||||||
|
#define SYS_inotify_init 253
|
||||||
|
#define SYS_inotify_add_watch 254
|
||||||
|
#define SYS_inotify_rm_watch 255
|
||||||
|
#define SYS_migrate_pages 256
|
||||||
|
#define SYS_openat 257
|
||||||
|
#define SYS_mkdirat 258
|
||||||
|
#define SYS_mknodat 259
|
||||||
|
#define SYS_fchownat 260
|
||||||
|
#define SYS_futimesat 261
|
||||||
|
#define SYS_newfstatat 262
|
||||||
|
#define SYS_unlinkat 263
|
||||||
|
#define SYS_renameat 264
|
||||||
|
#define SYS_linkat 265
|
||||||
|
#define SYS_symlinkat 266
|
||||||
|
#define SYS_readlinkat 267
|
||||||
|
#define SYS_fchmodat 268
|
||||||
|
#define SYS_faccessat 269
|
||||||
|
#define SYS_pselect6 270
|
||||||
|
#define SYS_ppoll 271
|
||||||
|
#define SYS_unshare 272
|
||||||
|
#define SYS_set_robust_list 273
|
||||||
|
#define SYS_get_robust_list 274
|
||||||
|
#define SYS_splice 275
|
||||||
|
#define SYS_tee 276
|
||||||
|
#define SYS_sync_file_range 277
|
||||||
|
#define SYS_vmsplice 278
|
||||||
|
#define SYS_move_pages 279
|
||||||
|
#define SYS_utimensat 280
|
||||||
|
#define SYS_epoll_pwait 281
|
||||||
|
#define SYS_signalfd 282
|
||||||
|
#define SYS_timerfd_create 283
|
||||||
|
#define SYS_eventfd 284
|
||||||
|
#define SYS_fallocate 285
|
||||||
|
#define SYS_timerfd_settime 286
|
||||||
|
#define SYS_timerfd_gettime 287
|
||||||
|
#define SYS_accept4 288
|
||||||
|
#define SYS_signalfd4 289
|
||||||
|
#define SYS_eventfd2 290
|
||||||
|
#define SYS_epoll_create1 291
|
||||||
|
#define SYS_dup3 292
|
||||||
|
#define SYS_pipe2 293
|
||||||
|
#define SYS_inotify_init1 294
|
||||||
|
#define SYS_preadv 295
|
||||||
|
#define SYS_pwritev 296
|
||||||
|
#define SYS_rt_tgsigqueueinfo 297
|
||||||
|
#define SYS_perf_event_open 298
|
||||||
|
#define SYS_recvmmsg 299
|
||||||
|
#define SYS_fanotify_init 300
|
||||||
|
#define SYS_fanotify_mark 301
|
||||||
|
#define SYS_prlimit64 302
|
||||||
|
#define SYS_name_to_handle_at 303
|
||||||
|
#define SYS_open_by_handle_at 304
|
||||||
|
#define SYS_clock_adjtime 305
|
||||||
|
#define SYS_syncfs 306
|
||||||
|
#define SYS_sendmmsg 307
|
||||||
|
#define SYS_setns 308
|
||||||
|
#define SYS_getcpu 309
|
||||||
|
#define SYS_process_vm_readv 310
|
||||||
|
#define SYS_process_vm_writev 311
|
||||||
|
#define SYS_kcmp 312
|
||||||
|
#define SYS_finit_module 313
|
||||||
|
#define SYS_sched_setattr 314
|
||||||
|
#define SYS_sched_getattr 315
|
||||||
|
#define SYS_renameat2 316
|
||||||
|
#define SYS_seccomp 317
|
||||||
|
#define SYS_getrandom 318
|
||||||
|
#define SYS_memfd_create 319
|
||||||
|
#define SYS_kexec_file_load 320
|
||||||
|
#define SYS_bpf 321
|
||||||
|
#define SYS_execveat 322
|
||||||
|
#define SYS_userfaultfd 323
|
||||||
|
#define SYS_membarrier 324
|
||||||
|
#define SYS_mlock2 325
|
||||||
|
#define SYS_copy_file_range 326
|
||||||
|
#define SYS_preadv2 327
|
||||||
|
#define SYS_pwritev2 328
|
||||||
|
#define SYS_pkey_mprotect 329
|
||||||
|
#define SYS_pkey_alloc 330
|
||||||
|
#define SYS_pkey_free 331
|
||||||
|
#define SYS_statx 332
|
||||||
|
#define SYS_io_pgetevents 333
|
||||||
|
#define SYS_rseq 334
|
||||||
|
#define SYS_uretprobe 335
|
||||||
|
#define SYS_uprobe 336
|
||||||
|
#define SYS_pidfd_send_signal 424
|
||||||
|
#define SYS_io_uring_setup 425
|
||||||
|
#define SYS_io_uring_enter 426
|
||||||
|
#define SYS_io_uring_register 427
|
||||||
|
#define SYS_open_tree 428
|
||||||
|
#define SYS_move_mount 429
|
||||||
|
#define SYS_fsopen 430
|
||||||
|
#define SYS_fsconfig 431
|
||||||
|
#define SYS_fsmount 432
|
||||||
|
#define SYS_fspick 433
|
||||||
|
#define SYS_pidfd_open 434
|
||||||
|
#define SYS_clone3 435
|
||||||
|
#define SYS_close_range 436
|
||||||
|
#define SYS_openat2 437
|
||||||
|
#define SYS_pidfd_getfd 438
|
||||||
|
#define SYS_faccessat2 439
|
||||||
|
#define SYS_process_madvise 440
|
||||||
|
#define SYS_epoll_pwait2 441
|
||||||
|
#define SYS_mount_setattr 442
|
||||||
|
#define SYS_quotactl_fd 443
|
||||||
|
#define SYS_landlock_create_ruleset 444
|
||||||
|
#define SYS_landlock_add_rule 445
|
||||||
|
#define SYS_landlock_restrict_self 446
|
||||||
|
#define SYS_memfd_secret 447
|
||||||
|
#define SYS_process_mrelease 448
|
||||||
|
#define SYS_futex_waitv 449
|
||||||
|
#define SYS_set_mempolicy_home_node 450
|
||||||
|
#define SYS_cachestat 451
|
||||||
|
#define SYS_fchmodat2 452
|
||||||
|
#define SYS_map_shadow_stack 453
|
||||||
|
#define SYS_futex_wake 454
|
||||||
|
#define SYS_futex_wait 455
|
||||||
|
#define SYS_futex_requeue 456
|
||||||
|
#define SYS_statmount 457
|
||||||
|
#define SYS_listmount 458
|
||||||
|
#define SYS_lsm_get_self_attr 459
|
||||||
|
#define SYS_lsm_set_self_attr 460
|
||||||
|
#define SYS_lsm_list_modules 461
|
||||||
|
#define SYS_mseal 462
|
||||||
|
#define SYS_setxattrat 463
|
||||||
|
#define SYS_getxattrat 464
|
||||||
|
#define SYS_listxattrat 465
|
||||||
|
#define SYS_removexattrat 466
|
||||||
|
#define SYS_open_tree_attr 467
|
||||||
|
#define SYS_file_getattr 468
|
||||||
|
#define SYS_file_setattr 469
|
||||||
|
#define SYS_listns 470
|
||||||
|
#define SYS_rseq_slice_yield 471
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Translate a raw syscall result into the C convention.
|
||||||
|
*
|
||||||
|
* On success (rax >= 0) the value is returned unchanged. On error the kernel
|
||||||
|
* returns -errno in rax; syscall_ret stores errno into the calling thread's
|
||||||
|
* TCB errno slot (via __errno_location()) and returns -1. The -4095 bound
|
||||||
|
* matches the kernel's MAX_ERRNO: results at or below -4096 are legitimate
|
||||||
|
* values (e.g. mmap addresses cannot happen to land here, but the rule is
|
||||||
|
* kept exact).
|
||||||
|
*/
|
||||||
|
hidden int
|
||||||
|
syscall_ret(long r);
|
||||||
|
|
||||||
|
#endif /* VLIBC_INTERNAL_SYSCALL_H */
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "errno.h"
|
||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Translate a raw syscall result into the C convention: return the value on
|
||||||
|
* success, or store the negated errno and return -1 on error. The -4095
|
||||||
|
* bound is the kernel's MAX_ERRNO: any result at or below -4096 is a
|
||||||
|
* legitimate value, not an error code.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
syscall_ret(long r)
|
||||||
|
{
|
||||||
|
if (r < 0 && r > -4096)
|
||||||
|
{
|
||||||
|
errno = (int)-r;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return (int)r;
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#ifndef VLIBC_INTERNAL_TYPES_H
|
||||||
|
#define VLIBC_INTERNAL_TYPES_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vlibc — internal scalar types.
|
||||||
|
*
|
||||||
|
* The kernel-ABI-correct scalar types internal code needs before the public
|
||||||
|
* <sys/types.h> exists. Widths follow the x86_64 LP64 model, matching the
|
||||||
|
* kernel's UAPI: pointers and long are 64-bit, int is 32-bit. ssize_t is
|
||||||
|
* derived from the compiler's pointer-difference type so it always matches
|
||||||
|
* the machine word. The public headers own their own (possibly richer)
|
||||||
|
* typedefs; this header is deliberately the minimal internal subset.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Signed type for byte counts and read()/write() results (x86_64: long). */
|
||||||
|
typedef __PTRDIFF_TYPE__ ssize_t;
|
||||||
|
|
||||||
|
/* File offset and its Linux large-file counterpart. */
|
||||||
|
typedef long off_t;
|
||||||
|
typedef long long loff_t;
|
||||||
|
|
||||||
|
/* Calendar time in seconds. */
|
||||||
|
typedef long time_t;
|
||||||
|
|
||||||
|
/* Process ID. */
|
||||||
|
typedef int pid_t;
|
||||||
|
|
||||||
|
/* User and group IDs. */
|
||||||
|
typedef unsigned int uid_t;
|
||||||
|
typedef unsigned int gid_t;
|
||||||
|
|
||||||
|
/* File mode bits (and permissions). */
|
||||||
|
typedef unsigned int mode_t;
|
||||||
|
|
||||||
|
/* Socket address lengths. */
|
||||||
|
typedef unsigned int socklen_t;
|
||||||
|
|
||||||
|
/* Microsecond intervals. */
|
||||||
|
typedef unsigned int useconds_t;
|
||||||
|
|
||||||
|
/* Hard link count. */
|
||||||
|
typedef unsigned long long nlink_t;
|
||||||
|
|
||||||
|
/* Device and inode numbers. */
|
||||||
|
typedef unsigned long long dev_t;
|
||||||
|
typedef unsigned long long ino_t;
|
||||||
|
|
||||||
|
/* Block counts and sizes. */
|
||||||
|
typedef long blkcnt_t;
|
||||||
|
typedef long blksize_t;
|
||||||
|
|
||||||
|
#endif /* VLIBC_INTERNAL_TYPES_H */
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* vlibc — syscall layer test (todo 1).
|
||||||
|
*
|
||||||
|
* Exercises the raw __syscall<n>() entry points and the errno TCB-slot
|
||||||
|
* mechanism end to end:
|
||||||
|
*
|
||||||
|
* 1. happy path: __syscall3(SYS_write, 1, "x", 1) emits "x" on stdout and
|
||||||
|
* returns 1 (one byte written);
|
||||||
|
* 2. failure path: syscall_ret(SYS_openat on a nonexistent path) returns -1
|
||||||
|
* and leaves errno == ENOENT in the calling thread's TCB slot;
|
||||||
|
* 3. TCB offset mechanics: a fake TCB (a local buffer whose first word is
|
||||||
|
* its own address, as the real TCB layout will have) is installed as
|
||||||
|
* the FS thread pointer via SYS_arch_prctl; __errno_location() must
|
||||||
|
* then point exactly at fake + VLIBC_TCB_ERRNO_OFF, a failing syscall
|
||||||
|
* must land its errno in that slot, and the real thread pointer is
|
||||||
|
* restored afterwards.
|
||||||
|
*
|
||||||
|
* All diagnostics go through raw SYS_write (no printf): between installing
|
||||||
|
* and restoring the fake thread pointer the test must not call any libc
|
||||||
|
* function, whose TLS reads would see the fake TCB.
|
||||||
|
*
|
||||||
|
* Not part of the library proper; compiled manually for this todo (the
|
||||||
|
* tests/ + make check wiring is owned by a later todo).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../src/internal/errno.h"
|
||||||
|
#include "../src/internal/syscall.h"
|
||||||
|
#include "../src/internal/types.h"
|
||||||
|
|
||||||
|
/* Flag constants the public <fcntl.h> will own; test-local copies. */
|
||||||
|
#define TEST_AT_FDCWD (-100)
|
||||||
|
#define TEST_O_RDONLY 0
|
||||||
|
#define TEST_O_CLOEXEC 0x80000
|
||||||
|
|
||||||
|
/* arch_prctl codes (kernel UAPI). */
|
||||||
|
#define TEST_ARCH_SET_FS 0x1002
|
||||||
|
#define TEST_ARCH_GET_FS 0x1003
|
||||||
|
|
||||||
|
static int failures;
|
||||||
|
|
||||||
|
/* Write a NUL-terminated string to fd via the raw syscall layer. */
|
||||||
|
static void
|
||||||
|
say(int fd, const char *s)
|
||||||
|
{
|
||||||
|
ssize_t n = 0;
|
||||||
|
|
||||||
|
while (s[n] != '\0')
|
||||||
|
{
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
syscall_ret(__syscall3(SYS_write, fd, (long)s, (long)n));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check(int cond, const char *what)
|
||||||
|
{
|
||||||
|
if (!cond)
|
||||||
|
{
|
||||||
|
say(2, "FAIL: ");
|
||||||
|
say(2, what);
|
||||||
|
say(2, "\n");
|
||||||
|
failures++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A stand-in thread control block. The real TCB layout (owned by the
|
||||||
|
* startup todo) will store the TCB's own address at offset 0 — the self
|
||||||
|
* pointer __builtin_thread_pointer() reads through %fs:0 — and errno at
|
||||||
|
* VLIBC_TCB_ERRNO_OFF. This buffer mirrors exactly those two slots.
|
||||||
|
*/
|
||||||
|
static unsigned long fake_tcb[32];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The fake TCB must be installed over a saved copy of the real FS base:
|
||||||
|
* the kernel's arch_prctl only reads or writes the current base, so the
|
||||||
|
* save must happen while the real thread pointer is still installed.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
install_fake_tcb(unsigned long *real_fs) // NOLINT(readability-non-const-parameter)
|
||||||
|
{
|
||||||
|
long r;
|
||||||
|
|
||||||
|
fake_tcb[0] = (unsigned long)fake_tcb; /* TCB self pointer at slot 0 */
|
||||||
|
r = syscall_ret(__syscall2(SYS_arch_prctl, TEST_ARCH_GET_FS, (long)real_fs));
|
||||||
|
if (r != 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
r = syscall_ret(__syscall2(SYS_arch_prctl, TEST_ARCH_SET_FS, (long)fake_tcb));
|
||||||
|
if (r != 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
restore_real_tcb(unsigned long real_fs)
|
||||||
|
{
|
||||||
|
return syscall_ret(__syscall2(SYS_arch_prctl, TEST_ARCH_SET_FS, (long)real_fs)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Failure scenario (-f): SYS_openat on a nonexistent path must return -1
|
||||||
|
* and leave errno == ENOENT in the TCB slot. Prints the observed result to
|
||||||
|
* stdout; exits 0 only when the failure behaved exactly as specified.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
failure_scenario(void)
|
||||||
|
{
|
||||||
|
unsigned long real_fs = 0;
|
||||||
|
long r;
|
||||||
|
int saved_errno;
|
||||||
|
|
||||||
|
if (install_fake_tcb(&real_fs))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
r = syscall_ret(__syscall4(SYS_openat, TEST_AT_FDCWD, (long)"/nonexistent/vlibc",
|
||||||
|
TEST_O_RDONLY | TEST_O_CLOEXEC, 0));
|
||||||
|
saved_errno = errno;
|
||||||
|
if (restore_real_tcb(real_fs))
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r == -1 && saved_errno == ENOENT)
|
||||||
|
{
|
||||||
|
say(1, "openat=-1 errno=ENOENT\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
say(1, "openat FAIL\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
long r;
|
||||||
|
unsigned long real_fs = 0;
|
||||||
|
|
||||||
|
if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'f')
|
||||||
|
{
|
||||||
|
return failure_scenario();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 1. Happy path: one raw byte to stdout, byte count returned. */
|
||||||
|
r = __syscall3(SYS_write, 1, (long)"x", 1);
|
||||||
|
check(r == 1, "SYS_write returned byte count");
|
||||||
|
|
||||||
|
/* 2. Point FS at the fake TCB and verify the errno slot mechanics. */
|
||||||
|
check(install_fake_tcb(&real_fs) == 0, "arch_prctl fake TCB install");
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned long now_fs = 0;
|
||||||
|
|
||||||
|
r = syscall_ret(__syscall2(SYS_arch_prctl, TEST_ARCH_GET_FS, (long)&now_fs));
|
||||||
|
check(r == 0 && now_fs == (unsigned long)fake_tcb,
|
||||||
|
"arch_prctl(ARCH_GET_FS) reads fake base");
|
||||||
|
}
|
||||||
|
|
||||||
|
check((char *)__errno_location() == (char *)fake_tcb + VLIBC_TCB_ERRNO_OFF,
|
||||||
|
"__errno_location == fake TCB + VLIBC_TCB_ERRNO_OFF");
|
||||||
|
|
||||||
|
r = syscall_ret(__syscall4(SYS_openat, TEST_AT_FDCWD, (long)"/nonexistent/vlibc",
|
||||||
|
TEST_O_RDONLY | TEST_O_CLOEXEC, 0));
|
||||||
|
check(r == -1, "SYS_openat on nonexistent path returns -1");
|
||||||
|
check(errno == ENOENT, "errno == ENOENT via TCB slot");
|
||||||
|
|
||||||
|
/* 3. Restore the real thread pointer; the fake slot keeps its value. */
|
||||||
|
check(restore_real_tcb(real_fs) == 0, "arch_prctl(ARCH_SET_FS, real TCB) restored");
|
||||||
|
check(*(int *)((char *)fake_tcb + VLIBC_TCB_ERRNO_OFF) == ENOENT,
|
||||||
|
"fake TCB errno slot retains ENOENT after restore");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VLIBC_TCB_ERRNO_OFF addresses slot 1 of whichever TCB the FS thread
|
||||||
|
* pointer selects; under the host libc that slot is its private TLS
|
||||||
|
* state, so an errno round-trip through the real thread pointer would
|
||||||
|
* corrupt the host libc. The fake-TCB path proves the offset mechanics;
|
||||||
|
* the real TCB is exercised once the startup todo installs vlibc's own
|
||||||
|
* thread pointer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (failures > 0)
|
||||||
|
{
|
||||||
|
say(2, "FAILED\n");
|
||||||
|
}
|
||||||
|
return failures == 0 ? 0 : 1;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user