diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile | 7 | ||||
-rw-r--r-- | lib/include/alloc.h | 6 | ||||
-rw-r--r-- | lib/include/auxv.h | 2 | ||||
-rw-r--r-- | lib/include/common.h | 21 | ||||
-rw-r--r-- | lib/include/elf.h | 156 | ||||
-rw-r--r-- | lib/include/syscall.h | 58 | ||||
-rw-r--r-- | lib/include/syscalls.h | 40 | ||||
-rw-r--r-- | lib/src/alloc.c | 87 | ||||
-rw-r--r-- | lib/src/common.c | 38 | ||||
-rw-r--r-- | lib/src/fmt.c | 12 | ||||
-rw-r--r-- | lib/src/io.c | 11 | ||||
-rw-r--r-- | lib/src/syscalls.c | 62 |
12 files changed, 441 insertions, 59 deletions
diff --git a/lib/Makefile b/lib/Makefile index 29c103a..5f8a1a9 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,13 +1,18 @@ # Copyright (c) 2020 Johannes Stoelp +HDR+=include/alloc.h HDR+=include/auxv.h HDR+=include/elf.h HDR+=include/fmt.h HDR+=include/io.h HDR+=include/syscall.h +HDR+=include/syscalls.h -DEP+=src/io.o +DEP+=src/alloc.o +DEP+=src/common.o DEP+=src/fmt.o +DEP+=src/io.o +DEP+=src/syscalls.o libcommon.a: $(HDR) $(DEP) ar -crs $@ $(filter %.o, $^) diff --git a/lib/include/alloc.h b/lib/include/alloc.h new file mode 100644 index 0000000..baf8d3d --- /dev/null +++ b/lib/include/alloc.h @@ -0,0 +1,6 @@ +// Copyright (c) 2021 Johannes Stoelp + +#pragma once + +void* alloc(unsigned size); +void dealloc(void* ptr); diff --git a/lib/include/auxv.h b/lib/include/auxv.h index 42dac38..1ac953e 100644 --- a/lib/include/auxv.h +++ b/lib/include/auxv.h @@ -15,7 +15,7 @@ #define AT_EXECFD 2 /* [val] File descriptor of user program (in case Linux Kernel didn't mapped) */ #define AT_PHDR 3 /* [ptr] Address of Phdr of use program (in case Kernel mapped user program) */ #define AT_PHENT 4 /* [val] Size in bytes of one Phdr entry */ -#define AT_PHNUM 5 /* [val] Number of Phread entries */ +#define AT_PHNUM 5 /* [val] Number of Phdr entries */ #define AT_PAGESZ 6 /* [val] System page size */ #define AT_BASE 7 /* [ptr] `base address` interpreter was loaded to */ #define AT_FLAGS 8 /* [val] */ diff --git a/lib/include/common.h b/lib/include/common.h index 5ea6050..d006d71 100644 --- a/lib/include/common.h +++ b/lib/include/common.h @@ -3,14 +3,17 @@ #pragma once #include "io.h" -#include "syscall.h" +#include "syscalls.h" -#include <asm/unistd.h> - -#define ERROR_ON(cond, ...) \ - do { \ - if ((cond)) { \ - efmt(__VA_ARGS__); \ - syscall1(__NR_exit, 1); \ - } \ +#define ERROR_ON(cond, fmt, ...) \ + do { \ + if ((cond)) { \ + efmt("%s:%d " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ + _exit(1); \ + } \ } while (0) + + +void* memset(void* s, int c, size_t n); +void* memcpy(void* d, const void* s, size_t n); + diff --git a/lib/include/elf.h b/lib/include/elf.h index a0fe6f7..0317859 100644 --- a/lib/include/elf.h +++ b/lib/include/elf.h @@ -4,6 +4,51 @@ #include <stdint.h> +/// ---------- +/// ELF Header +/// ---------- + +// Index into `ident`. +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_OSABI 7 + +// indent[EI_CLASS] +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +// indent[EI_CLASS] +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +// indent[EI_OSABI] +#define ELFOSABI_SYSV 0 + +// Objec file `type`. +#define ET_NONE 0 +#define ET_DYN 3 + +typedef struct { + uint8_t ident[16]; // ELF identification. + uint16_t type; // Object file type. + uint16_t machine; // Machine type. + uint32_t version; // Object file version. + uint64_t entry; // Entrypoint address. + uint64_t phoff; // Program header file offset. + uint64_t shoff; // Section header file offset. + uint32_t flags; // Processor specific flags. + uint16_t ehsize; // ELF header size. + uint16_t phentsize; // Program header entry size. + uint16_t phnum; // Number of program header entries. + uint16_t shentsize; // Section header entry size. + uint16_t shnum; // Number of section header entries. + uint16_t shstrndx; // Section name string table index. +} Elf64Ehdr; + /// -------------- /// Program Header /// -------------- @@ -15,6 +60,7 @@ #define PT_NOTE 4 /* Location of auxiliary information */ #define PT_SHLIB 5 /* Reserved, but unspecified semantic */ #define PT_PHDR 6 /* Location & size of program headers itself */ +#define PT_TLS 7 /* Thread local storage */ #define PT_GNU_EH_FRAME 0x6474e550 /* [x86-64] stack unwinding tables */ #define PT_LOPROC 0x70000000 @@ -39,32 +85,36 @@ typedef struct { /// Dynamic Section /// --------------- -#define DT_NULL 0 /* [ignored] Marks end of dynamic section */ -#define DT_NEEDED 1 /* [val] Name of needed library */ -#define DT_PLTRELSZ 2 /* [val] Size in bytes of PLT relocs */ -#define DT_PLTGOT 3 /* [ptr] Processor defined value */ -#define DT_HASH 4 /* [ptr] Address of symbol hash table */ -#define DT_STRTAB 5 /* [ptr] Address of string table */ -#define DT_SYMTAB 6 /* [ptr] Address of symbol table */ -#define DT_RELA 7 /* [ptr] Address of Rela relocs */ -#define DT_RELASZ 8 /* [val] Total size of Rela relocs */ -#define DT_RELAENT 9 /* [val] Size of one Rela reloc */ -#define DT_STRSZ 10 /* [val] Size of string table */ -#define DT_SYMENT 11 /* [val] Size of one symbol table entry */ -#define DT_INIT 12 /* [ptr] Address of init function */ -#define DT_FINI 13 /* [ptr] Address of termination function */ -#define DT_SONAME 14 /* [val] Name of shared object */ -#define DT_RPATH 15 /* [val] Library search path (deprecated) */ -#define DT_SYMBOLIC 16 /* [ignored] Start symbol search here */ -#define DT_REL 17 /* [ptr] Address of Rel relocs */ -#define DT_RELSZ 18 /* [val] Total size of Rel relocs */ -#define DT_RELENT 19 /* [val] Size of one Rel reloc */ -#define DT_PLTREL 20 /* [val] Type of reloc in PLT */ -#define DT_DEBUG 21 /* [ptr] For debugging; unspecified */ -#define DT_TEXTREL 22 /* [ignored] Reloc might modify .text */ -#define DT_JMPREL 23 /* [ptr] Address of PLT relocs */ -#define DT_BIND_NOW 24 /* [ignored] Process relocations of object */ -#define DT_MAX_CNT 25 +#define DT_NULL 0 /* [ignored] Marks end of dynamic section */ +#define DT_NEEDED 1 /* [val] Name of needed library */ +#define DT_PLTRELSZ 2 /* [val] Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* [ptr] Processor defined value */ +#define DT_HASH 4 /* [ptr] Address of symbol hash table */ +#define DT_STRTAB 5 /* [ptr] Address of string table */ +#define DT_SYMTAB 6 /* [ptr] Address of symbol table */ +#define DT_RELA 7 /* [ptr] Address of Rela relocs */ +#define DT_RELASZ 8 /* [val] Total size of Rela relocs */ +#define DT_RELAENT 9 /* [val] Size of one Rela reloc */ +#define DT_STRSZ 10 /* [val] Size of string table */ +#define DT_SYMENT 11 /* [val] Size of one symbol table entry */ +#define DT_INIT 12 /* [ptr] Address of init function */ +#define DT_FINI 13 /* [ptr] Address of termination function */ +#define DT_SONAME 14 /* [val] Name of shared object */ +#define DT_RPATH 15 /* [val] Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* [ignored] Start symbol search here */ +#define DT_REL 17 /* [ptr] Address of Rel relocs */ +#define DT_RELSZ 18 /* [val] Total size of Rel relocs */ +#define DT_RELENT 19 /* [val] Size of one Rel reloc */ +#define DT_PLTREL 20 /* [val] Type of reloc in PLT */ +#define DT_DEBUG 21 /* [ptr] For debugging; unspecified */ +#define DT_TEXTREL 22 /* [ignored] Reloc might modify .text */ +#define DT_JMPREL 23 /* [ptr] Address of PLT relocs */ +#define DT_BIND_NOW 24 /* [ignored] Process relocations of object */ +#define DT_INIT_ARRAY 25 /* [ptr] Address of array of initialization functions */ +#define DT_FINI_ARRAY 26 /* [ptr] Address of array of termination functions */ +#define DT_INIT_ARRAYSZ 27 /* [val] Size in bytes of the initialization array */ +#define DT_FINI_ARRAYSZ 28 /* [val] Size in bytes of the termination array */ +#define DT_MAX_CNT 29 typedef struct { uint64_t tag; @@ -73,3 +123,57 @@ typedef struct { void* ptr; }; } Elf64Dyn; + +/// ------------ +/// Symbol Entry +/// ------------ + +typedef struct { + uint32_t name; // Symbol name (index into string table). + uint8_t info; // Symbol Binding bits[7..4] + Symbol Type bits[3..0]. + uint8_t other; // Reserved. + uint16_t shndx; // Section table index. + uint64_t value; // + uint64_t size; // +} Elf64Sym; + +#define ELF64_ST_BIND(i) ((i) >> 4) +#define ELF64_ST_TYPE(i) ((i)&0xf) + +// Symbold Bindings. +#define STB_GLOBAL 1 /* Global symbol, visible to all object files. */ +#define STB_WEAK 2 /* Global scope, but with lower precedence than global symbols. */ + +// Symbol Types. +#define STT_NOTYPE 0 /* No type. */ +#define STT_OBJECT 1 /* Data Object. */ +#define STT_FUNC 2 /* Function entry point. */ + +// Special Section Indicies. +#define SHN_UNDEF 0 /* Undefined section. */ +#define SHN_ABS 0xff1 /* Indicates an absolute value. */ + +/// ----------------- +/// Relocations Entry +/// ----------------- + +typedef struct { + uint64_t offset; // Virtual address of the storage unit affected by the relocation. + uint64_t info; // Symbol table index + relocation type. +} Elf64Rel; + +typedef struct { + uint64_t offset; // Virtual address of the storage unit affected by the relocation. + uint64_t info; // Symbol table index + relocation type. + int64_t addend; // Constant value used to compute the relocation value. +} Elf64Rela; + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i)&0xffffffffL) + +// x86_64 relocation types. +#define R_X86_64_64 1 /* Absolute 64bit address, address affected by relocation: `base + offset` */ +#define R_X86_64_COPY 5 /* Copy content from sym addr to relocation address: `base + offset` */ +#define R_X86_64_GLOB_DAT 6 /* Address affected by relocation: `base + offset` */ +#define R_X86_64_JUMP_SLOT 7 /* Address affected by relocation: `base + offset` */ +#define R_X86_64_RELATIVE 8 /* Relative address *`base + offset` = `base + addend` */ diff --git a/lib/include/syscall.h b/lib/include/syscall.h index 4947155..10dc545 100644 --- a/lib/include/syscall.h +++ b/lib/include/syscall.h @@ -19,6 +19,7 @@ // // Machine specific constraints (x86_64): // a | a register (eg rax) +// c | c register (eg rcx) // d | d register (eg rdx) // D | di register (eg rdi) // S | si register (eg rsi) @@ -35,29 +36,62 @@ // https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html // https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html - -// Linux syscall ABI -// x86-64 -// #syscall: rax -// ret : rax -// instr : syscall -// args : rdi rsi rdx r10 r8 r9 +// +// +// Linux syscall ABI - x86-64 +// #syscall: rax +// ret : rax +// instr : syscall +// args : rdi rsi rdx r10 r8 r9 // // Reference: // syscall(2) +// +// +// X86_64 `syscall` instruction additionally clobbers following registers: +// rcx Store return address. +// r11 Store RFLAGS. +// +// Reference: +// https://www.felixcloutier.com/x86/syscall -#define argcast(A) ((long)(A)) -#define syscall1(n, a1) _syscall1(n, argcast(a1)) -#define syscall3(n, a1, a2, a3) _syscall3(n, argcast(a1), argcast(a2), argcast(a3)) +#define argcast(A) ((long)(A)) +#define syscall1(n, a1) _syscall1(n, argcast(a1)) +#define syscall2(n, a1, a2) _syscall2(n, argcast(a1), argcast(a2)) +#define syscall3(n, a1, a2, a3) _syscall3(n, argcast(a1), argcast(a2), argcast(a3)) +#define syscall4(n, a1, a2, a3, a4) _syscall4(n, argcast(a1), argcast(a2), argcast(a3), argcast(a4)) +#define syscall6(n, a1, a2, a3, a4, a5, a6) _syscall6(n, argcast(a1), argcast(a2), argcast(a3), argcast(a4), argcast(a5), argcast(a6)) static inline long _syscall1(long n, long a1) { long ret; - asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "memory"); + asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "rcx", "r11", "memory"); + return ret; +} + +static inline long _syscall2(long n, long a1, long a2) { + long ret; + asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2) : "rcx", "r11", "memory"); return ret; } static inline long _syscall3(long n, long a1, long a2, long a3) { long ret; - asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), "d"(a3) : "memory"); + asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), "d"(a3) : "rcx", "r11", "memory"); + return ret; +} + +static inline long _syscall4(long n, long a1, long a2, long a3, long a4) { + long ret; + register long r10 asm("r10") = a4; + asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10) : "rcx", "r11", "memory"); + return ret; +} + +static inline long _syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) { + long ret; + register long r10 asm("r10") = a4; + register long r8 asm("r8") = a5; + register long r9 asm("r9") = a6; + asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory"); return ret; } diff --git a/lib/include/syscalls.h b/lib/include/syscalls.h new file mode 100644 index 0000000..7808e98 --- /dev/null +++ b/lib/include/syscalls.h @@ -0,0 +1,40 @@ +// Copyright (c) 2021 Johannes Stoelp + +#pragma once + +#include <stddef.h> // size_t +#include <sys/types.h> // ssize_t, off_t, ... + +extern int dynld_errno; + +// Syscall definitions taken from corresponding man pages, eg +// open(2) +// read(2) +// ... + +#define O_RDONLY 00 +int open(const char* path, int flags); +int close(int fd); + +#define F_OK 0 +#define R_OK 4 +int access(const char* path, int mode); + +ssize_t write(int fd, const void* buf, size_t count); +ssize_t read(int fd, void* buf, size_t count); +ssize_t pread(int fd, void* buf, size_t count, off_t offset); + +// mmap - prot: +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +#define PROT_EXEC 0x4 +// mmap - flags: +#define MAP_PRIVATE 0x2 +#define MAP_ANONYMOUS 0x20 +#define MAP_FIXED 0x10 +// mmap - ret: +#define MAP_FAILED ((void*)-1) +void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset); +int munmap(void* addr, size_t length); + +void _exit(int status); diff --git a/lib/src/alloc.c b/lib/src/alloc.c new file mode 100644 index 0000000..8b05d9e --- /dev/null +++ b/lib/src/alloc.c @@ -0,0 +1,87 @@ +// Copyright (c) 2021 Johannes Stoelp + +#include <alloc.h> +#include <common.h> + +#include <stdint.h> + +// Extremely simple and non-thread safe implementation of a dynamic +// memory allocator. Which will greatly suffer under fragmentation as +// we neither use splitting nor coalesce free blocks. It uses +// first-fit and always traverses the block list from the beginning. +// +// Bottom line, this allocator can be optimized in so many ways but it +// doesn't really matter for the purpose of this studies and therefore +// the allocator is implemented in the most naive way. + +// Allocation block descriptor. +struct BlockDescriptor { + unsigned mFree; + unsigned mSize; + struct BlockDescriptor* mNext; +}; + +// Global Allocator. + +// Size of available memory to the allocator. +enum { MEMORY_SIZE = 1 * 1024 * 1024 }; +// Memory for the allocator (statically reserved in the `.bss` section). +uint8_t gMemory[MEMORY_SIZE]; + +// Top index into `gMemory` to indicate next free memory. +unsigned gMemoryTop; + +// List of allocated blocks (free + used). +struct BlockDescriptor* gHead; + +// Request free memory from `gMemory` and advance the `gMemoryTop` index. +static void* brk(unsigned size) { + ERROR_ON(gMemoryTop + size >= MEMORY_SIZE, "Allocator OOM!"); + const unsigned old_top = gMemoryTop; + gMemoryTop += size; + return (void*)(gMemory + old_top); +} + +// Allocate memory chunk of `size` and return pointer to the chunk. +void* alloc(unsigned size) { + struct BlockDescriptor* current = 0; + + // Check if we have a free block in the list of allocated blocks + // that matches the requested size. + current = gHead; + while (current) { + if (current->mFree && current->mSize < size) { + current->mFree = 0; + return (void*)(current + 1); + }; + current = current->mNext; + } + + // Compute real allocation size: Payload + BlockDescriptor. + unsigned real_size = size + sizeof(struct BlockDescriptor); + + // No free block found in the list of blocks, allocate new block. + current = brk(real_size); + + // Initialize new block. + current->mFree = 0; + current->mSize = size; + current->mNext = 0; + + // Insert new block at the beginning of the list of blocks. + if (gHead != 0) { + current->mNext = gHead; + } + gHead = current; + + return (void*)(current + 1); +} + +void dealloc(void* ptr) { + // Get descriptor block. + struct BlockDescriptor* current = (struct BlockDescriptor*)ptr - 1; + + // Mark block as free. + ERROR_ON(current->mFree, "Tried to de-alloc free block!"); + current->mFree = 1; +} diff --git a/lib/src/common.c b/lib/src/common.c new file mode 100644 index 0000000..dd806bf --- /dev/null +++ b/lib/src/common.c @@ -0,0 +1,38 @@ +// Copyright (c) 2021 Johannes Stoelp + +#include <common.h> + +#if !defined(__linux__) || !defined(__x86_64__) +# error "Only supported on linux(x86_64)!" +#endif + +void* memset(void* s, int c, size_t n) { + asm volatile( + "cld" + "\n" + "rep stosb" + : "+D"(s), "+c"(n) + : "a"(c) + : "memory"); + return s; +} + +void* memcpy(void* d, const void* s, size_t n) { + // When `d` points into `[s, s+n[` we would override `s` while copying into `d`. + // |------------|--------| + // s d s+n + // -> We don't support. + // + // When `d` points into `]s-n, s[` it is destructive for `s` but all data + // from `s` are copied into `d`. The user gets what he asks for. + // -> Supported. + ERROR_ON(s <= d && d < (void*)((unsigned char*)s + n), "memcpy: Unsupported overlap!"); + asm volatile( + "cld" + "\n" + "rep movsb" + : "+D"(d), "+S"(s), "+c"(n) + : + : "memory"); + return d; +} diff --git a/lib/src/fmt.c b/lib/src/fmt.c index be1ca3a..24ddd98 100644 --- a/lib/src/fmt.c +++ b/lib/src/fmt.c @@ -11,7 +11,7 @@ static const char* num2dec(char* buf, unsigned long len, unsigned long long num) } while (num > 0 && pbuf != buf) { - char d = (num % 10) + '0'; + char d = (char)(num % 10) + '0'; *(--pbuf) = d; num /= 10; } @@ -28,7 +28,7 @@ static const char* num2hex(char* buf, unsigned long len, unsigned long long num) while (num > 0 && pbuf != buf) { char d = (num & 0xf); - *(--pbuf) = d + (d > 9 ? 'a' - 10 : '0'); + *(--pbuf) = (char)(d + (d > 9 ? 'a' - 10 : '0')); num >>= 4; } return pbuf; @@ -51,7 +51,7 @@ int vfmt(char* buf, unsigned long len, const char* fmt, va_list ap) { put(*s++); \ } - char scratch[16]; + char scratch[32]; int l_cnt = 0; while (*fmt) { @@ -73,7 +73,7 @@ int vfmt(char* buf, unsigned long len, const char* fmt, va_list ap) { val *= -1; put('-'); } - const char* ptr = num2dec(scratch, sizeof(scratch), val); + const char* ptr = num2dec(scratch, sizeof(scratch), (unsigned long)val); puts(ptr); } break; case 'x': { @@ -81,6 +81,10 @@ int vfmt(char* buf, unsigned long len, const char* fmt, va_list ap) { const char* ptr = num2hex(scratch, sizeof(scratch), val); puts(ptr); } break; + case 'c': { + char c = va_arg(ap, int); // By C standard, value passed to varg smaller than `sizeof(int)` will be converted to int. + put(c); + } break; case 's': { const char* ptr = va_arg(ap, const char*); puts(ptr); diff --git a/lib/src/io.c b/lib/src/io.c index b5e0dc5..5194042 100644 --- a/lib/src/io.c +++ b/lib/src/io.c @@ -1,10 +1,9 @@ // Copyright (c) 2020 Johannes Stoelp -#include <io.h> #include <fmt.h> +#include <io.h> #include <syscall.h> - -#include <asm/unistd.h> +#include <syscalls.h> // `pfmt` uses fixed-size buffer on the stack for formating the message // (for simplicity and since we don't impl buffered I/O). @@ -21,14 +20,14 @@ static int vdfmt(int fd, const char* fmt, va_list ap) { int ret = vfmt(buf, sizeof(buf), fmt, ap); if (ret > MAX_PRINTF_LEN - 1) { - syscall3(__NR_write, fd, buf, MAX_PRINTF_LEN - 1); + write(fd, buf, MAX_PRINTF_LEN - 1); static const char warn[] = "\npfmt: Message truncated, max length can be configured by defining MAX_PRINTF_LEN\n"; - syscall3(__NR_write, FD_STDERR, warn, sizeof(warn)); + write(FD_STDERR, warn, sizeof(warn)); return MAX_PRINTF_LEN - 1; } - syscall3(__NR_write, fd, buf, ret); + write(fd, buf, ret); return ret; } diff --git a/lib/src/syscalls.c b/lib/src/syscalls.c new file mode 100644 index 0000000..074fced --- /dev/null +++ b/lib/src/syscalls.c @@ -0,0 +1,62 @@ +// Copyright (c) 2021 Johannes Stoelp + +#include <asm/unistd.h> // __NR_* +#include <syscall.h> +#include <syscalls.h> + +// Storage for `dynld_errno`. +int dynld_errno; + +// Convert return value to errno/ret. +static long syscall_ret(unsigned long ret) { + if (ret > (unsigned long)-4096ul) { + dynld_errno = -ret; + return -1; + } + return ret; +} + +int open(const char* path, int flags) { + long ret = syscall2(__NR_open, path, flags); + return syscall_ret(ret); +} + +int close(int fd) { + long ret = syscall1(__NR_close, fd); + return syscall_ret(ret); +} + +int access(const char* path, int mode) { + long ret = syscall2(__NR_access, path, mode); + return syscall_ret(ret); +} + +ssize_t write(int fd, const void* buf, size_t count) { + long ret = syscall3(__NR_write, fd, buf, count); + return syscall_ret(ret); +} + +ssize_t read(int fd, void* buf, size_t count) { + long ret = syscall3(__NR_read, fd, buf, count); + return syscall_ret(ret); +} + +ssize_t pread(int fd, void* buf, size_t count, off_t offset) { + long ret = syscall4(__NR_read, fd, buf, count, offset); + return syscall_ret(ret); +} + +void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) { + long ret = syscall6(__NR_mmap, addr, length, prot, flags, fd, offset); + return (void*)syscall_ret(ret); +} + +int munmap(void* addr, size_t length) { + long ret = syscall2(__NR_munmap, addr, length); + return syscall_ret(ret); +} + +void _exit(int status) { + syscall1(__NR_exit, status); + __builtin_unreachable(); +} |