#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 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 */