#pragma once #include #include #include #if defined(__x86_64__) #if defined(__linux__) constexpr bool is_x86_64_linux = true; #else constexpr bool is_x86_64_linux = false; #endif #else constexpr bool is_x86_64_linux = false; #endif template struct syscall; template requires is_x86_64_linux struct syscall { int64_t operator()(int64_t p1) const { int64_t ret; asm volatile ( "syscall" : "=a" (ret) : "0"(syscall_id), "D"(p1) : "rcx", "r11", "memory" ); return ret; } }; template requires is_x86_64_linux struct syscall { int64_t operator()(int64_t p1,int64_t p2) const { int64_t ret; asm volatile ( "syscall" : "=a" (ret) : "0"(syscall_id), "D"(p1), "S"(p2) : "rcx", "r11", "memory" ); return ret; } }; template requires is_x86_64_linux struct syscall { int64_t operator()(int64_t p1,int64_t p2,int64_t p3) const { int64_t ret; asm volatile ( "syscall" : "=a" (ret) : "0"(syscall_id), "D"(p1), "S"(p2), "d"(p3) : "rcx", "r11", "memory" ); return ret; } }; template requires is_x86_64_linux struct syscall { int64_t operator()(int64_t p1,int64_t p2,int64_t p3,int64_t p4) const { int64_t ret; register long r10 asm("r10") = p4; asm volatile ( "syscall" : "=a" (ret) : "0"(syscall_id), "D"(p1), "S"(p2), "d"(p3), "r"(r10) : "rcx", "r11", "memory" ); return ret; } }; template requires is_x86_64_linux struct syscall { int64_t operator()(int64_t p1,int64_t p2,int64_t p3,int64_t p4,int64_t p5) const { int64_t ret; register long r10 asm("r10") = p4; register long r8 asm("r8") = p5; asm volatile ( "syscall" : "=a" (ret) : "0"(syscall_id), "D"(p1), "S"(p2), "d"(p3), "r"(r10), "r"(r8) : "rcx", "r11", "memory" ); return ret; } }; template requires is_x86_64_linux struct syscall { int64_t operator()(int64_t p1,int64_t p2,int64_t p3,int64_t p4,int64_t p5,int64_t p6) const { int64_t ret; register long r10 asm("r10") = p4; register long r8 asm("r8") = p5; register long r9 asm("r9") = p6; asm volatile ( "syscall" : "=a" (ret) : "0"(syscall_id), "D"(p1), "S"(p2), "d"(p3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory" ); return ret; } }; constexpr auto _read = syscall<0, 3>{}; constexpr auto _write = syscall<1, 3>{}; constexpr auto _mmap = syscall<9, 6>{}; constexpr auto _munmap = syscall<11, 2>{}; constexpr auto _exit = syscall<60, 1>{}; inline int read(int fd, char* buffer, size_t sz) { return _read((int64_t)fd, (int64_t)buffer, (int64_t)sz); } inline int write(int fd, char* buffer, size_t sz) { return _write((int64_t)fd, (int64_t)buffer, (int64_t)sz); } inline void* mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { return (void*)_mmap((int64_t)addr, (int64_t)length, (int64_t)prot, (int64_t)flags, (int64_t)fd, (int64_t)offset); } inline int munmap(void *addr, size_t length) { return _munmap((int64_t)addr, (int64_t)length); } extern "C" { /// Yes, __attribute__((__noreturn__)), not [[noreturn]], because some God forsaken potato decided that those attributes are not the attributes I am looking for inline __attribute__ ((__noreturn__)) void exit(int status) { _exit((int64_t)status); while(true); } } inline int read(int fd, gp::buffer buffer) { return _read((int64_t)fd, (int64_t)buffer.begin().data, (int64_t)buffer.size()); } inline int write(int fd, gp::buffer buffer) { return _write((int64_t)fd, (int64_t)buffer.begin().data, (int64_t)buffer.size()); }