├── include ├── ctype.h ├── wchar.h ├── cia │ ├── conf.h │ ├── sync.h │ ├── def.h │ └── mem.h ├── time.h ├── stddef.h ├── stdbool.h ├── stdlib.h ├── stdatomic.h ├── string.h ├── linux │ ├── fcntl.h │ ├── asm │ │ └── prctl.h │ ├── sys │ │ ├── mman.h │ │ └── syscall.h │ ├── sched.h │ ├── signal.h │ └── futex.h ├── threads.h ├── stdio.h ├── cia-ld │ └── tcb.h ├── tinyrt.h ├── errno.h ├── stdint.h └── bin │ └── elf.h ├── os ├── windows │ ├── conf.h │ ├── utf8 │ │ ├── utf8.rc │ │ └── utf8.xml │ ├── windows.c │ ├── tinyrt.json │ ├── cia-init.c │ ├── crt-entry.c │ └── tinyrt.c └── linux │ ├── conf.h │ ├── entry.c │ ├── crt-ctors.c │ ├── tinyrt.c │ └── tinyrt-threads.c ├── tests ├── empty.c ├── hello.c ├── crt.c ├── tls.c ├── threaded.c ├── mm_seq_cst.c └── testing.h ├── src ├── stdlib-file │ ├── common.c │ ├── file.c │ └── fmt.c ├── cia-sync │ ├── futex.c │ └── mutex.c ├── cia-mem │ ├── util.c │ ├── arena.c │ ├── allocator.c │ └── pool.c ├── stdlib-string │ ├── str.c │ └── mem.c ├── stdlib-thread │ └── thread.c └── stdlib-program │ └── program.c ├── .gitignore ├── todo.md ├── arch ├── sysv_x86-64 │ ├── loader-entry.asm │ ├── loader-trampoline.asm │ └── thread-entry.asm └── x64_x86-64 │ └── chkstk.asm ├── license ├── cia.c ├── .github └── workflows │ ├── build-linux.yml │ └── build-windows.yml ├── loader ├── loader.h ├── stack.c ├── loader-self-reloc.c └── loader.c └── readme.md /include/ctype.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /include/wchar.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | typedef u32 wchar_t; 5 | -------------------------------------------------------------------------------- /os/windows/conf.h: -------------------------------------------------------------------------------- 1 | 2 | #define _CIA_OS_WINDOWS 3 | #define _CIA_DATA_LLP64 4 | -------------------------------------------------------------------------------- /tests/empty.c: -------------------------------------------------------------------------------- 1 | 2 | int main(int argc, char **argv) { 3 | return 0; 4 | } 5 | -------------------------------------------------------------------------------- /include/cia/conf.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define CIA_DATA_LP64 5 | #define CIA_OS_LINUX 6 | 7 | -------------------------------------------------------------------------------- /include/time.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | struct timespec { 5 | time_t tv_sec; 6 | long tv_nsec; 7 | }; -------------------------------------------------------------------------------- /os/windows/utf8/utf8.rc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "utf8.xml" 4 | -------------------------------------------------------------------------------- /os/windows/windows.c: -------------------------------------------------------------------------------- 1 | 2 | #define NOGDI 3 | #define NOUSER 4 | #define NOMINMAX 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | -------------------------------------------------------------------------------- /src/stdlib-file/common.c: -------------------------------------------------------------------------------- 1 | 2 | FILE *stdin; 3 | FILE *stdout; 4 | FILE *stderr; 5 | 6 | static Cia_Pool _page_allocator; 7 | static Cia_Pool _file_pool; 8 | static Cia_Mutex _g_pool_mutex; 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /lib 3 | /a 4 | a.out 5 | *.a 6 | *.so 7 | *.exe 8 | *.lib 9 | *.obj 10 | *.pdb 11 | *.ilk 12 | *.exp 13 | *.o 14 | *.4coder 15 | *.rdbg 16 | /.venv 17 | test/ 18 | vgcore.* -------------------------------------------------------------------------------- /include/stddef.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | typedef u64 size_t; 7 | typedef i64 ptrdiff_t; 8 | 9 | #if !defined(NULL) 10 | #define NULL ((void *)0) 11 | #endif 12 | -------------------------------------------------------------------------------- /include/stdbool.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #if !defined(__bool_true_false_are_defined) 5 | typedef _Bool bool; 6 | #define true ((bool)1) 7 | #define false ((bool)0) 8 | #define __bool_true_false_are_defined 9 | #endif 10 | -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | 2 | # TO-DO list for ciabatta 3 | 4 | Library: 5 | 6 | * In `cia-def.h` have macros defined depending on which modules were exported 7 | * Allow for ciabatta to be used by including source files 8 | 9 | Support: 10 | 11 | * EssenseOS platform (?) 12 | -------------------------------------------------------------------------------- /include/stdlib.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | int atexit(void (*func)(void)); 7 | int at_quick_exit(void (*func)(void)); 8 | _Noreturn void abort(void); 9 | _Noreturn void exit(int code); 10 | _Noreturn void _Exit(int code); 11 | _Noreturn void quick_exit(int code); -------------------------------------------------------------------------------- /tests/hello.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | int main(int argc, char **argv, char **envp) { 6 | // char string[] = "Hello, world!\n"; 7 | // fwrite(string, 1, sizeof string-1, stdout); 8 | printf("Hello, world! %d\n", 4); 9 | return 0; 10 | } 11 | -------------------------------------------------------------------------------- /tests/crt.c: -------------------------------------------------------------------------------- 1 | 2 | #include "testing.h" 3 | 4 | int main(int argc, char **argv) { 5 | JUNIT_START("test/junit.xml"); 6 | FEATURE_START("My feature"); 7 | TEST(1 == 1, "Tests work"); 8 | TESTS_PREPARE(); 9 | TESTS_PRINT_RESULT(); 10 | JUNIT_END(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /os/windows/utf8/utf8.xml: -------------------------------------------------------------------------------- 1 | UTF-8 -------------------------------------------------------------------------------- /include/stdatomic.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #if defined(__has_include_next) 9 | #if __has_include_next() 10 | #include_next 11 | #else 12 | #define __STDC_NO_ATOMICS__ 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /tests/tls.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | _Thread_local u64 my_thread_local; 6 | 7 | int main(void) { 8 | int arr[16] = {0}; 9 | my_thread_local = 2; 10 | arr[3] = 5; 11 | char string[] = "Hello, world!\n"; 12 | fwrite(string, 1, sizeof string-1, stdout); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /src/cia-sync/futex.c: -------------------------------------------------------------------------------- 1 | 2 | int cia_wait(u32 *addr, u32 compare_with, u64 time) { 3 | _rt_sync_wait(addr, compare_with, time); 4 | } 5 | 6 | int cia_wake_one(u32 *addr, u32 *n_woken) { 7 | _rt_sync_wake_one(addr, n_woken); 8 | } 9 | 10 | int cia_wake_all(u32 *addr, u32 *n_woken) { 11 | _rt_sync_wake_all(addr, n_woken); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /os/windows/tinyrt.json: -------------------------------------------------------------------------------- 1 | // This file contains TinyRT API subsets that are exported 2 | // for this operating system, one name per line. This file 3 | // is used in a build script to generate tinyrt_macro file 4 | // and to resolve higher-level API dependencies 5 | 6 | rt_api_file: true, 7 | rt_api_program: true, 8 | rt_api_shell: false, 9 | rt_api_memory: true, -------------------------------------------------------------------------------- /arch/sysv_x86-64/loader-entry.asm: -------------------------------------------------------------------------------- 1 | 2 | bits 64 3 | 4 | section .text 5 | default rel 6 | global _dlstart 7 | extern _DYNAMIC:weak 8 | 9 | _dlstart: 10 | xor rbp, rbp 11 | mov rdi, rsp 12 | lea rsi, _DYNAMIC 13 | and rsp, -16 14 | ; `call` pushes 8-byte value onto the stack 15 | ; by pushing an 8-bit value ourselves we can make 16 | ; sure the stack is aligned after rbp push in prologue 17 | push 0 18 | 19 | -------------------------------------------------------------------------------- /include/cia/sync.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | int cia_wait(u32 *addr, u32 compare_with, u64 time); 7 | int cia_wake_one(u32 *addr, u32 *n_woken); 8 | int cia_wake_all(u32 *addr, u32 *n_woken); 9 | 10 | struct Cia_Mutex typedef Cia_Mutex; 11 | struct Cia_Mutex { 12 | _Atomic(u32) tag; 13 | }; 14 | 15 | void cia_mutex_init(Cia_Mutex *mutex); 16 | void cia_mutex_lock(Cia_Mutex *mutex); 17 | void cia_mutex_unlock(Cia_Mutex *mutex); 18 | 19 | -------------------------------------------------------------------------------- /include/cia/def.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | // Pre-C23 keyword macros 5 | #define static_assert _Static_assert 6 | 7 | // Stdint and a layer on top 8 | #include 9 | 10 | // Short type definitions 11 | typedef int8_t i8; 12 | typedef uint8_t u8; 13 | typedef int16_t i16; 14 | typedef uint16_t u16; 15 | typedef int32_t i32; 16 | typedef uint32_t u32; 17 | typedef int64_t i64; 18 | typedef uint64_t u64; 19 | 20 | // Other commonly-used standard includes 21 | #include 22 | #include 23 | -------------------------------------------------------------------------------- /os/linux/conf.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | static u64 cia_stack_size; 5 | static u64 cia_tls_image_size; 6 | static void *cia_tls_image_base; 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "tinyrt.c" 20 | #include "tinyrt-threads.c" 21 | #include "entry.c" 22 | 23 | -------------------------------------------------------------------------------- /include/string.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | void *memcpy(void *restrict dst, void const *restrict src, size_t count); 7 | void *memccpy(void *restrict dst, void const *restrict src, int c, size_t count); 8 | void *memmove(void *dst, const void *src, size_t count) 9 | 10 | char *strcpy(char *restrict dst, char const *restrict src); 11 | char *strncpy(char *restrict dst, char const *restrict src, size_t count); 12 | 13 | void memset(void *dst, int ch, size_t length); 14 | int _wcsicmp(uint16_t *s1, uint16_t *s2); 15 | -------------------------------------------------------------------------------- /include/linux/fcntl.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define O_ACCMODE 03 5 | #define O_RDONLY 00 6 | #define O_WRONLY 01 7 | #define O_RDWR 02 8 | #define O_CREAT 0100 9 | #define O_EXCL 0200 10 | #define O_NOCTTY 0400 11 | #define O_TRUNC 01000 12 | #define O_APPEND 02000 13 | #define O_NONBLOCK 04000 14 | #define O_NDELAY O_NONBLOCK 15 | #define O_SYNC 04010000 16 | #define O_FSYNC O_SYNC 17 | #define O_ASYNC 020000 18 | #define O_CLOEXEC 02000000 19 | #define O_DIRECT 040000 -------------------------------------------------------------------------------- /src/cia-mem/util.c: -------------------------------------------------------------------------------- 1 | 2 | void *cia_ptr_alignf(void *ptr, u64 alignment) { 3 | u64 addr = (u64)ptr; 4 | u64 aligned = (addr + alignment - 1) & ~(alignment - 1); 5 | return (void *)aligned; 6 | } 7 | 8 | void *cia_ptr_alignb(void *ptr, u64 alignment) { 9 | u64 addr = (u64)ptr; 10 | u64 aligned = addr & ~(alignment - 1); 11 | return (void *)aligned; 12 | } 13 | 14 | u64 cia_size_alignf(u64 size, u64 alignment) { 15 | return (size + alignment - 1) & ~(alignment - 1); 16 | } 17 | 18 | u64 cia_size_alignb(u64 size, u64 alignment) { 19 | return size & ~(alignment - 1); 20 | } -------------------------------------------------------------------------------- /arch/x64_x86-64/chkstk.asm: -------------------------------------------------------------------------------- 1 | 2 | bits 64 3 | 4 | segment .text 5 | global __chkstk 6 | __chkstk: 7 | sub rsp, 0x10 8 | mov [rsp], r10 9 | mov [rsp+0x8], r11 10 | xor r11, r11 11 | lea r10, [rsp+0x18] 12 | sub r10, rax 13 | cmovb r10, r11 14 | mov r11, gs:[0x10] 15 | cmp r10, r11 16 | jnb .end 17 | and r10w, 0xf000 18 | .loop: 19 | lea r11, [r11-0x1000] 20 | mov byte [r11], 0x0 21 | cmp r10, r11 22 | jnz .loop 23 | .end: 24 | mov r10, [rsp] 25 | mov r11, [rsp+0x8] 26 | add rsp, 0x10 27 | ret -------------------------------------------------------------------------------- /include/threads.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | typedef int (*thrd_start_t)(void *); 8 | 9 | struct thrd_t typedef thrd_t; 10 | struct thrd_t { 11 | _RT_Thread thread; 12 | }; 13 | 14 | enum { 15 | thrd_success = 0, 16 | thrd_nomem = -1, 17 | thrd_timedout = -2, 18 | thrd_busy = -3, 19 | thrd_error = -4 20 | }; 21 | 22 | int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); 23 | int thrd_join(thrd_t thr, int *out_exit_code); 24 | int thrd_detach(thrd_t thr); 25 | void thrd_yield(); 26 | 27 | void thrd_terminate(thrd_t thr); /*TODO remove later*/ -------------------------------------------------------------------------------- /os/windows/cia-init.c: -------------------------------------------------------------------------------- 1 | 2 | static void _fileapi_init(); 3 | 4 | void _cia_init() { 5 | _fileapi_init(); 6 | } 7 | 8 | void memset(void *dest, int ch, size_t length) { 9 | u8 *bytes = dest; 10 | for(int i = 0; i != length; ++i) { 11 | bytes[i] = ch; 12 | } 13 | } 14 | 15 | int _wcsicmp(uint16_t *s1, uint16_t *s2) { 16 | while(*s1 != 0 && *s2 != 0) { 17 | if(*s1 != *s2) { 18 | return *s1 - *s2; 19 | } 20 | } 21 | if(*s1 == 0 && *s2 != 0) { 22 | return -1; 23 | } 24 | if(*s1 != 0 && *s2 == 0) { 25 | return 1; 26 | } 27 | return 0; 28 | } -------------------------------------------------------------------------------- /include/linux/asm/prctl.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define ARCH_GET_CPUID 0x1011 5 | #define ARCH_GET_FS 0x1003 6 | #define ARCH_GET_GS 0x1004 7 | #define ARCH_GET_XCOMP_GUEST_PERM 0x1024 8 | #define ARCH_GET_XCOMP_PERM 0x1022 9 | #define ARCH_GET_XCOMP_SUPP 0x1021 10 | #define ARCH_MAP_VDSO_32 0x2002 11 | #define ARCH_MAP_VDSO_64 0x2003 12 | #define ARCH_MAP_VDSO_X32 0x2001 13 | #define ARCH_REQ_XCOMP_GUEST_PERM 0x1025 14 | #define ARCH_REQ_XCOMP_PERM 0x1023 15 | #define ARCH_SET_CPUID 0x1012 16 | #define ARCH_SET_FS 0x1002 17 | #define ARCH_SET_GS 0x1001 18 | -------------------------------------------------------------------------------- /src/stdlib-string/str.c: -------------------------------------------------------------------------------- 1 | 2 | char *strcpy(char *restrict dst, char const *restrict src) { 3 | i64 str_len = 0; 4 | for(i64 i = 0; src[i] != 0; ++i) { 5 | dst[i] = src[i]; 6 | str_len += 1; 7 | } 8 | dst[str_len] = 0; 9 | return dst; 10 | } 11 | 12 | char *strncpy(char *restrict dst, char const *restrict src, size_t count) { 13 | i64 str_len = 0; 14 | for(i64 i = 0; i < count; ++i) { 15 | if(src[i] == 0) { 16 | break; 17 | } 18 | dst[i] = src[i]; 19 | str_len += 1; 20 | } 21 | for(i64 i = str_len; i < count; ++i) { 22 | dst[i] = 0; 23 | } 24 | return dst; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | Zero-Clause BSD 2 | ============= 3 | 4 | Permission to use, copy, modify, and/or distribute this software for 5 | any purpose with or without fee is hereby granted. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL 8 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 9 | OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE 10 | FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY 11 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 12 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 13 | OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE -------------------------------------------------------------------------------- /include/stdio.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | typedef struct FILE FILE; 10 | struct FILE { 11 | _RT_File rt_file; 12 | Cia_Mutex mutex; 13 | }; 14 | 15 | #define EOF (-1) 16 | 17 | extern FILE *stdin; 18 | extern FILE *stdout; 19 | extern FILE *stderr; 20 | 21 | FILE *fopen(const char *restrict filename, const char *restrict mode); 22 | int fgetc(FILE *file); 23 | int fputc(int c, FILE *file); 24 | size_t fread(void *restrict buf, size_t size, size_t count, FILE *restrict file); 25 | size_t fwrite(void const *restrict buf, size_t size, size_t count, FILE *restrict file); 26 | int fclose(FILE *file); 27 | 28 | int printf(char const *restrict fmt, ...); -------------------------------------------------------------------------------- /src/stdlib-thread/thread.c: -------------------------------------------------------------------------------- 1 | 2 | int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) { 3 | _RT_Status status = _rt_thread_create(&thr->thread, (int (*)(void *))func, arg); 4 | if(status == _RT_STATUS_OK) { 5 | return thrd_success; 6 | } 7 | return thrd_error; 8 | } 9 | 10 | int thrd_detach(thrd_t thr) { 11 | _RT_Status status = _rt_thread_detach(&thr.thread); 12 | if(status == _RT_STATUS_OK) { 13 | return thrd_success; 14 | } 15 | return thrd_error; 16 | } 17 | 18 | int thrd_join(thrd_t thr, int *out_exit_code) { 19 | _RT_Status status = _rt_thread_join(&thr.thread, out_exit_code); 20 | if(status == _RT_STATUS_OK) { 21 | return thrd_success; 22 | } 23 | return thrd_error; 24 | } 25 | 26 | void thrd_yield(void) { 27 | _rt_thread_yield(); 28 | } 29 | 30 | /* remove later */ 31 | void thrd_terminate(thrd_t thr) { 32 | _rt_thread_terminate(&thr.thread); 33 | } -------------------------------------------------------------------------------- /os/linux/entry.c: -------------------------------------------------------------------------------- 1 | 2 | static char stack_chk_fail_msg[] = 3 | "Stack check failed. " 4 | "You've got a stack corruption somewhere. " 5 | "Sorry these guys didn't tell me where\n"; 6 | 7 | void __stack_chk_fail(void) { 8 | sys_write(STDERR_FILENO, stack_chk_fail_msg, sizeof stack_chk_fail_msg); 9 | sys_exit(1); 10 | } 11 | 12 | extern int main(int argc, char **argv, char **envp); 13 | static void _fileapi_init(); 14 | static void _rt_threads_setup(); 15 | 16 | void _start(_LD_CRT_Params *params) { 17 | cia_stack_size = params->stack_size; 18 | cia_tls_image_size = params->tls_image_size; 19 | cia_tls_image_base = params->tls_image_base; 20 | // Get the envp 21 | // char **envp = argv + (argc + 1); 22 | // init(argc, argv, envp); 23 | _fileapi_init(); 24 | _rt_threads_setup(); 25 | int code = main(0, NULL, NULL); 26 | _rt_thread_cancell_all_running(); 27 | sys_exit(code); 28 | } 29 | -------------------------------------------------------------------------------- /cia.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | // Base includes 5 | #include 6 | 7 | // Platform-dependent sources 8 | #include _CIA_OS_CONF 9 | 10 | // Forward declarations 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | // Module cia_memory 18 | #include "src/cia-mem/util.c" 19 | #include "src/cia-mem/allocator.c" 20 | #include "src/cia-mem/arena.c" 21 | #include "src/cia-mem/pool.c" 22 | 23 | // Module cia_sync 24 | #include "src/cia-sync/mutex.c" 25 | 26 | // Module stdlib_program 27 | #include "src/stdlib-program/program.c" 28 | 29 | // Module stdlib_threads 30 | #include "src/stdlib-thread/thread.c" 31 | 32 | // Module stdlib_file 33 | #include "src/stdlib-file/common.c" 34 | #include "src/stdlib-file/file.c" 35 | #include "src/stdlib-file/fmt.c" 36 | 37 | // Module stdlib_string 38 | #include "src/stdlib-string/mem.c" 39 | #include "src/stdlib-string/str.c" 40 | -------------------------------------------------------------------------------- /.github/workflows/build-linux.yml: -------------------------------------------------------------------------------- 1 | name: Linux 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Cache LLVM and Clang 18 | id: cache-llvm 19 | uses: actions/cache@v3 20 | with: 21 | path: | 22 | C:/Program Files/LLVM 23 | ./llvm 24 | key: llvm-15 25 | - name: Install LLVM and Clang 26 | uses: KyleMayes/install-llvm-action@v1 27 | with: 28 | version: "15" 29 | cached: ${{ steps.cache-llvm.outputs.cache-hit }} 30 | - name: Setup NASM 31 | uses: ilammy/setup-nasm@v1 32 | with: 33 | from-source: true 34 | - name: Set up Python 35 | uses: actions/setup-python@v4 36 | - name: Install python dependencies 37 | run: python -m pip install pyjson5 38 | - name: Build 39 | working-directory: ${{env.GITHUB_WORKSPACE}} 40 | shell: bash 41 | run: ./build.py -m release -t tests/hello.c 42 | -------------------------------------------------------------------------------- /.github/workflows/build-windows.yml: -------------------------------------------------------------------------------- 1 | name: Windows 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | build: 14 | env: 15 | CI: false 16 | runs-on: windows-latest 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Cache LLVM and Clang 20 | id: cache-llvm 21 | uses: actions/cache@v3 22 | with: 23 | path: | 24 | C:/Program Files/LLVM 25 | ./llvm 26 | key: llvm-15 27 | - name: Install LLVM and Clang 28 | uses: KyleMayes/install-llvm-action@v1 29 | with: 30 | version: "15" 31 | cached: ${{ steps.cache-llvm.outputs.cache-hit }} 32 | - name: Setup NASM 33 | uses: ilammy/setup-nasm@v1 34 | with: 35 | from-source: false 36 | - name: Set up Python 37 | with: 38 | python-version: '3.x' 39 | uses: actions/setup-python@v4 40 | - name: Build 41 | working-directory: ${{env.GITHUB_WORKSPACE}} 42 | shell: bash 43 | run: ./build.py -m release -t tests/hello.c 44 | -------------------------------------------------------------------------------- /src/stdlib-string/mem.c: -------------------------------------------------------------------------------- 1 | 2 | void *memcpy(void *restrict dst, void const *restrict src, size_t count) { 3 | u8 *restrict dst_bytes = dst; 4 | u8 const *restrict src_bytes = src; 5 | for(size_t i = 0; i < count; ++i) { 6 | dst_bytes[i] = src_bytes[i]; 7 | } 8 | return dst_bytes; 9 | } 10 | 11 | void *memccpy(void *restrict dst, void const *restrict src, int c, size_t count) { 12 | u8 *restrict dst_bytes = dst; 13 | u8 const *restrict src_bytes = src; 14 | for(size_t i = 0; i < count; ++i) { 15 | dst_bytes[i] = src_bytes[i]; 16 | if(src_bytes[i] == c) { 17 | return (void *)&src[i+1]; 18 | } 19 | } 20 | return NULL; 21 | } 22 | 23 | void *memmove(void *dst, const void *src, size_t count) { 24 | if(dst == src) { 25 | return dst; 26 | } 27 | u8 *dst_bytes = dst; 28 | u8 const *src_bytes = src; 29 | if(dst < src) { 30 | for(size_t i = 0; i < count; ++i) { 31 | dst_bytes[i] = src_bytes[i]; 32 | } 33 | } 34 | else { 35 | for(size_t i = count-1; i-- != 0; ) { 36 | dst_bytes[i] = src_bytes[i]; 37 | } 38 | } 39 | return dst_bytes; 40 | } 41 | -------------------------------------------------------------------------------- /include/linux/sys/mman.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define MAP_32BIT 0x40 5 | 6 | #define PROT_READ 0x1 7 | #define PROT_WRITE 0x2 8 | #define PROT_EXEC 0x4 9 | #define PROT_NONE 0x0 10 | #define PROT_GROWSDOWN 0x01000000 11 | #define PROT_GROWSUP 0x02000000 12 | 13 | #define MAP_SHARED 0x01 14 | #define MAP_PRIVATE 0x02 15 | #define MAP_SHARED_VALIDATE 0x03 16 | #define MAP_TYPE 0x0f 17 | 18 | #define MAP_FIXED 0x10 19 | #define MAP_FILE 0 20 | #define MAP_ANONYMOUS 0x20 21 | #define MAP_ANON MAP_ANONYMOUS 22 | #define MAP_HUGE_SHIFT 26 23 | #define MAP_HUGE_MASK 0x3f 24 | 25 | #define MS_ASYNC 1 26 | #define MS_SYNC 4 27 | #define MS_INVALIDATE 2 28 | 29 | #define MAP_FAILED ((void *) -1) 30 | 31 | #define MAP_GROWSDOWN 0x00100 32 | #define MAP_DENYWRITE 0x00800 33 | #define MAP_EXECUTABLE 0x01000 34 | #define MAP_LOCKED 0x02000 35 | #define MAP_NORESERVE 0x04000 36 | #define MAP_POPULATE 0x08000 37 | #define MAP_NONBLOCK 0x10000 38 | #define MAP_STACK 0x20000 39 | #define MAP_HUGETLB 0x40000 40 | #define MAP_SYNC 0x80000 41 | #define MAP_FIXED_NOREPLACE 0x100000 42 | 43 | 44 | -------------------------------------------------------------------------------- /os/linux/crt-ctors.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | // NOTE: These symbols are provided by the linker 5 | #define attribute_hidden __attribute__((__visibility__("hidden"))) 6 | extern void (*__preinit_array_start []) (int, char **, char **) attribute_hidden; 7 | extern void (*__preinit_array_end []) (int, char **, char **) attribute_hidden; 8 | extern void (*__init_array_start []) (int, char **, char **) attribute_hidden; 9 | extern void (*__init_array_end []) (int, char **, char **) attribute_hidden; 10 | extern void (*__fini_array_start []) (void) attribute_hidden; 11 | extern void (*__fini_array_end []) (void) attribute_hidden; 12 | 13 | // extern void _init(); 14 | // extern void _fini(); 15 | 16 | // These will be called by __libc_start_main 17 | void __libc_global_init(int argc, char **argv, char **envp) { 18 | // _init(); 19 | u64 size = (u64)__init_array_end - (u64)__init_array_start; 20 | for(u64 i = 0; i != size; ++i) { 21 | (*__init_array_start[i])(argc, argv, envp); 22 | } 23 | } 24 | 25 | void __libc_global_fini(int argc, char **argv, char **envp) { 26 | u64 size = (u64)__fini_array_end - (u64)__fini_array_start; 27 | u64 i = size; 28 | while(i-- > 0) { 29 | (*__fini_array_start[i])(); 30 | } 31 | // _fini(); 32 | } 33 | -------------------------------------------------------------------------------- /src/cia-mem/arena.c: -------------------------------------------------------------------------------- 1 | 2 | void cia_arena_create(Cia_Arena *arena, Cia_Allocator backing_allocator, u64 buffer_size) { 3 | arena->allocator = backing_allocator; 4 | arena->buffer_size = buffer_size; 5 | arena->used = 0; 6 | arena->buffer = cia_allocator_alloc(&arena->allocator, arena->buffer_size, 16); 7 | } 8 | 9 | void *cia_arena_alloc(Cia_Arena *arena, u64 size) { 10 | if(arena->used + size > arena->buffer_size) { 11 | return NULL; 12 | } 13 | void *ptr = &arena->buffer[arena->used]; 14 | arena->used += arena->buffer_size; 15 | return ptr; 16 | } 17 | 18 | void *cia_arena_alloc_aligned(Cia_Arena *arena, u64 size, u64 align) { 19 | void *buffer_end = &arena->buffer[arena->buffer_size]; 20 | void *region_ptr = cia_ptr_alignf(&arena->buffer[arena->used], align); 21 | void *region_end = (void *)((u64)region_ptr + size); 22 | if(region_end > buffer_end) { 23 | return NULL; 24 | } 25 | arena->used = (u64)region_ptr - (u64)arena->buffer; 26 | return region_ptr; 27 | } 28 | 29 | void cia_arena_free_all(Cia_Arena *arena) { 30 | arena->used = 0; 31 | } 32 | 33 | void cia_arena_destroy(Cia_Arena *arena) { 34 | cia_allocator_free_size(&arena->allocator, arena->buffer, arena->buffer_size); 35 | } 36 | -------------------------------------------------------------------------------- /include/linux/sched.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define CLONE_NEWTIME 0x00000080 5 | #define CLONE_VM 0x00000100 6 | #define CLONE_FS 0x00000200 7 | #define CLONE_FILES 0x00000400 8 | #define CLONE_SIGHAND 0x00000800 9 | #define CLONE_PIDFD 0x00001000 10 | #define CLONE_PTRACE 0x00002000 11 | #define CLONE_VFORK 0x00004000 12 | #define CLONE_PARENT 0x00008000 13 | #define CLONE_THREAD 0x00010000 14 | #define CLONE_NEWNS 0x00020000 15 | #define CLONE_SYSVSEM 0x00040000 16 | #define CLONE_SETTLS 0x00080000 17 | #define CLONE_PARENT_SETTID 0x00100000 18 | #define CLONE_CHILD_CLEARTID 0x00200000 19 | #define CLONE_DETACHED 0x00400000 20 | #define CLONE_UNTRACED 0x00800000 21 | #define CLONE_CHILD_SETTID 0x01000000 22 | #define CLONE_NEWCGROUP 0x02000000 23 | #define CLONE_NEWUTS 0x04000000 24 | #define CLONE_NEWIPC 0x08000000 25 | #define CLONE_NEWUSER 0x10000000 26 | #define CLONE_NEWPID 0x20000000 27 | #define CLONE_NEWNET 0x40000000 28 | #define CLONE_IO 0x80000000 29 | 30 | #define SCHED_OTHER 0 31 | #define SCHED_FIFO 1 32 | #define SCHED_RR 2 33 | #define SCHED_BATCH 3 34 | #define SCHED_ISO 4 35 | #define SCHED_IDLE 5 36 | #define SCHED_DEADLINE 6 37 | #define SCHED_RESET_ON_FORK 0x40000000 38 | -------------------------------------------------------------------------------- /tests/threaded.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | thrd_t thrd; 12 | static Cia_Mutex g_mutex; 13 | static volatile i64 counter = 0; 14 | 15 | int thrd_func(void *arg) { 16 | _LD_Thread_Block *tcb = thrd.thread.handle; 17 | printf("child thread TID: %I64d\n", tcb->thread_id); 18 | printf("child thread: ok!\n"); 19 | for(int i = 0; i < 100000; ++i) { 20 | cia_mutex_lock(&g_mutex); 21 | counter += 1; 22 | cia_mutex_unlock(&g_mutex); 23 | } 24 | for(;;); 25 | printf("child thread: counter = %I64d\n", counter); 26 | return 0; 27 | } 28 | 29 | int main() { 30 | _LD_Thread_Block *tcb = (void *)((u64)__builtin_frame_address(0) & ~(2*MB - 1)); 31 | printf("main thread ID: %I64x\n", tcb->thread_id); 32 | printf("main thread: before\n"); 33 | cia_mutex_init(&g_mutex); 34 | int status = thrd_create(&thrd, thrd_func, NULL); 35 | if(status == thrd_error) { 36 | printf("main thread: error creating child thread\n"); 37 | return 1; 38 | } 39 | printf("main thread: after!\n"); 40 | for(int i = 0; i < 100000; ++i) { 41 | cia_mutex_lock(&g_mutex); 42 | counter += 1; 43 | cia_mutex_unlock(&g_mutex); 44 | } 45 | int exit_code; 46 | thrd_detach(thrd); 47 | printf("main thread: counter = %I64d\n", counter); 48 | thrd_terminate(thrd); 49 | printf("terminated child thread\n", counter); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /arch/sysv_x86-64/loader-trampoline.asm: -------------------------------------------------------------------------------- 1 | 2 | bits 64 3 | 4 | section .text 5 | global ld_stack_trampoline 6 | 7 | ; DESCRIPTION: 8 | ; This function copies the current stack down from RSP to the top of the stack 9 | ; into a memory region provided in parameter 10 | ; After the stack has been copied, we jump into ld_stage3_entry 11 | ; PARAMS: 12 | ; RDI (u64) - dst stack base 13 | ; RSI (u64) - src stack base 14 | ; RDX (u64) - dst stack size 15 | ; RCX (u64) - src stack size 16 | ; R8 (u64) - function to call 17 | ; R9 (u64) - param to pass to function 18 | ; RETURNS: 19 | ; guess what, it doesn't 20 | ld_stack_trampoline: 21 | ; Calculate the amount of memory we need to move to the new stack 22 | add rcx, rsi 23 | sub rcx, rsp 24 | ; Calculate the base of the source memory 25 | mov rsi, rsp 26 | ; Check to see if the amount we're about to move is less than dst stack size 27 | cmp rcx, rdx 28 | jl .continue 29 | xor rdi, rdi 30 | mov rsi, r9 31 | mov rax, r8 32 | call rax 33 | .continue: 34 | ; Save rsi, rdi, rcx on stack 35 | push rsi 36 | push rdi 37 | push rcx 38 | ; copy stack 39 | shr rcx, 3 40 | rep movsq 41 | ; get back our regs 42 | pop rcx 43 | pop rdi 44 | pop rsi 45 | ; We copied the stack at this point, lets switch 46 | add rsp, rdi 47 | sub rsp, rsi 48 | add rsp, rdx 49 | sub rsp, rcx 50 | ; We should have the new stack now, which is an exact copy of the old stack 51 | and rsp, -16 52 | mov rdi, 1 53 | mov rsi, r9 54 | mov rax, r8 55 | call rax -------------------------------------------------------------------------------- /src/cia-sync/mutex.c: -------------------------------------------------------------------------------- 1 | 2 | #define _CIA_MUTEX_FREE 0 3 | #define _CIA_MUTEX_LOCK 1 4 | #define _CIA_MUTEX_CONT 2 5 | 6 | void cia_mutex_init(Cia_Mutex *mutex) { 7 | atomic_store_explicit(&mutex->tag, _CIA_MUTEX_FREE, memory_order_relaxed); 8 | } 9 | 10 | void cia_mutex_lock(Cia_Mutex *mutex) { 11 | u32 p_tag; 12 | for(;;) { 13 | p_tag = _CIA_MUTEX_FREE; 14 | atomic_compare_exchange_strong_explicit( 15 | &mutex->tag 16 | , &p_tag 17 | , _CIA_MUTEX_LOCK 18 | , memory_order_acquire 19 | , memory_order_relaxed 20 | ); 21 | 22 | // We got the mutex, lets bail 23 | if(p_tag == _CIA_MUTEX_FREE) { 24 | break; 25 | } 26 | #if 1 27 | _rt_sync_wait(&mutex->tag, _CIA_MUTEX_LOCK, _RT_SYNC_WAIT_INFINITE); 28 | #else 29 | // We should wait if: 30 | // (1) the mutex is contested 31 | // (2) 32 | bool should_wait = 0; 33 | should_wait |= (p_tag == _CIA_MUTEX_CONT); 34 | should_wait |= (__sync_val_compare_and_swap(&mutex->tag, _CIA_MUTEX_LOCK, _CIA_MUTEX_CONT) != _CIA_MUTEX_FREE); 35 | // We wait while its contested 36 | if(should_wait) { 37 | _rt_sync_wait(&mutex->tag, _CIA_MUTEX_CONT, _RT_SYNC_WAIT_INFINITE); 38 | } 39 | #endif 40 | } 41 | } 42 | 43 | void cia_mutex_unlock(Cia_Mutex *mutex) { 44 | // TODO: add error when we unlock a free mutex 45 | // TODO: support recursive muteces 46 | atomic_store_explicit(&mutex->tag, _CIA_MUTEX_FREE, memory_order_release); 47 | _rt_sync_wake_one(&mutex->tag, NULL); 48 | } 49 | -------------------------------------------------------------------------------- /arch/sysv_x86-64/thread-entry.asm: -------------------------------------------------------------------------------- 1 | 2 | bits 64 3 | 4 | section .text 5 | global _rt_thread_start 6 | 7 | extern _rt_thread_setup 8 | extern _rt_thread_finish 9 | 10 | ; flags, &stack[-2], &parent_tid, &child_tid, 0 11 | 12 | ; DESCRIPTION: 13 | ; Function to be called when using the _clone syscall 14 | ; We don't just call the _clone syscall directly because 15 | ; if we call the clone syscall wrapper that's defined in 16 | ; linux/sys, our stack will be bad and we won't be able 17 | ; to return from the syscall wrapper 18 | ; PARAMETERS: 19 | ; rdi - flags 20 | ; rsi - stack_base 21 | ; rdx - parent_tid_ptr 22 | ; rcx - child_tid_ptr 23 | ; r8 - tls 24 | ; RETURNS: 25 | ; i64 value 26 | ; 0 if returning as a parent 27 | ; 1 if returning as a child 28 | ; negative value if there was an error making the thread 29 | _rt_thread_start: 30 | mov r10, rcx 31 | ; Setup child stack 32 | sub rsi, 24 33 | mov rax, [rsp] 34 | mov [rsi+16], rax 35 | mov rax, [rsp+8] 36 | mov [rsi+8], rax 37 | mov [rsi], r9 38 | ; Call syscall right away, since the order of the first 5 arguments 39 | ; matches with the argument order of the function 40 | mov rax, 56 ; SYS_CLONE 41 | syscall 42 | ; Check to see if we're child 43 | test eax, eax 44 | jnz .exit 45 | ; If child, jump to thread function 46 | pop rdi ; thread_fn 47 | pop rsi ; ctx 48 | ; Align the stack 49 | and rsp, -16 50 | call _rt_thread_setup 51 | ; Make return value the first arg and call thread finish routine 52 | mov rdi, rax 53 | call _rt_thread_finish 54 | ; Just to be sure... 55 | hlt 56 | .exit: 57 | ret 58 | -------------------------------------------------------------------------------- /include/cia-ld/tcb.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | struct _LD_CRT_Params typedef _LD_CRT_Params; 8 | struct _LD_CRT_Params { 9 | u64 stack_size; 10 | u64 tls_image_size; 11 | void *tls_image_base; 12 | }; 13 | 14 | // These signal a decision made by the main thread 15 | // about whether a thread should be detached or joined 16 | // If its not set, upon finishing the thread will wait 17 | // until one of these flags is set. 18 | // If the flag was set to detached, the thread will perform 19 | // cleanup on its own after it reached the end of execution. 20 | // If the flag was set to joined, it cannot perform the 21 | // cleanup on its own. For if it did, the check on the state_finish 22 | // futex might fail due to TCB being destroyed by the thread. 23 | // Which is why we first need to make sure the thread stopped working 24 | // and we don't need any of its TCB fields before cleaning it up on 25 | // the main thread. 26 | #define _LD_THREAD_STATE_NOT_YET 0x0 27 | #define _LD_THREAD_STATE_DETACHED 0x1 28 | #define _LD_THREAD_STATE_JOINED 0x2 29 | 30 | struct _LD_Thread_Block typedef _LD_Thread_Block; 31 | struct _LD_Thread_Block { 32 | /* DO NOT REORDER OR CHANGE SIZES (these comments are supposed to make it hard) */ 33 | /* +0x00 */ i32 thread_id; 34 | /* +0x04 */ i32 state_finish; 35 | /* +0x08 */ _Atomic(u32) state_detach; 36 | /* +0x0c */ u32 exit_code; 37 | /* +0x10 */ u64 pad0; 38 | /* +0x18 */ u64 pad1; 39 | /* +0x20 */ u64 pad2; 40 | /* +0x28 */ u64 stack_canary; 41 | /* Not ABI dependent as far as I care (for now) */ 42 | _LD_Thread_Block *next_tcb; 43 | _LD_Thread_Block *prev_tcb; 44 | _Atomic(u32) is_cancelled; 45 | }; 46 | 47 | -------------------------------------------------------------------------------- /os/windows/crt-entry.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "windows.c" 4 | 5 | extern int main(int argc, char **argv, char **envp); 6 | extern void _cia_init(); 7 | 8 | void mainCRTStartup() { 9 | _cia_init(); 10 | __security_init_cookie(); 11 | main(0, NULL, NULL); 12 | ExitProcess(0); 13 | } 14 | 15 | void wmainCRTStartup() { 16 | ExitProcess(0); 17 | } 18 | 19 | void _WinMainCRTStartup() { 20 | ExitProcess(0); 21 | } 22 | 23 | void wWinMainCRTStartup() { 24 | ExitProcess(0); 25 | } 26 | 27 | BOOL _DllMainCRTStartup(HINSTANCE instance, DWORD reason, void *_reserved) { 28 | switch(reason) { 29 | case DLL_PROCESS_ATTACH: { 30 | // Initialize once for each new process. 31 | // Return FALSE to fail DLL load. 32 | } break; 33 | case DLL_THREAD_ATTACH: { 34 | // Do thread-specific initialization. 35 | } break; 36 | case DLL_THREAD_DETACH: { 37 | // Do thread-specific cleanup. 38 | } break; 39 | case DLL_PROCESS_DETACH: { 40 | // Perform any necessary cleanup. 41 | } break; 42 | } 43 | return TRUE; 44 | } 45 | 46 | u64 __security_cookie; 47 | 48 | void __security_init_cookie() { 49 | // They say it's a random number so I generated 50 | // one using numbergenerator.org 51 | __security_cookie = 0xb26e04cc62ba48aULL; 52 | } 53 | 54 | void __security_check_cookie(u64 retrieved) { 55 | if(__security_cookie != retrieved) { 56 | char buf[] = "Buffer overrun detected!\n"; 57 | HANDLE stdout = GetStdHandle(STD_OUTPUT_HANDLE); 58 | WriteFile(stdout, buf, sizeof buf, NULL, NULL); 59 | // TODO: abort-like behaviour here 60 | ExitProcess(1); 61 | } 62 | } 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/stdlib-program/program.c: -------------------------------------------------------------------------------- 1 | 2 | #define MAX_ATEXIT_HANDLERS 32 3 | #define MAX_AT_QUICK_EXIT_HANDLERS 32 4 | 5 | static void (*atexit_handlers[MAX_ATEXIT_HANDLERS])(void); 6 | static void (*at_quick_exit_handlers[MAX_AT_QUICK_EXIT_HANDLERS])(void); 7 | static u64 n_atexit_handlers = 0; 8 | static u64 n_at_quick_exit_handlers = 0; 9 | 10 | int atexit(void (*func)(void)) { 11 | if(n_atexit_handlers == MAX_ATEXIT_HANDLERS) { 12 | return MAX_ATEXIT_HANDLERS; 13 | } 14 | atexit_handlers[n_atexit_handlers] = func; 15 | n_atexit_handlers += 1; 16 | return 0; 17 | } 18 | 19 | int at_quick_exit(void (*func)(void)) { 20 | if(n_at_quick_exit_handlers == MAX_AT_QUICK_EXIT_HANDLERS) { 21 | return MAX_AT_QUICK_EXIT_HANDLERS; 22 | } 23 | at_quick_exit_handlers[n_at_quick_exit_handlers] = func; 24 | n_at_quick_exit_handlers += 1; 25 | return 0; 26 | } 27 | 28 | _Noreturn void abort(void) { 29 | // TODO: Ideally do a debug trap if the process is being debugged 30 | _rt_program_exit(1); 31 | __builtin_unreachable(); 32 | } 33 | 34 | _Noreturn void exit(int code) { 35 | for(i64 i = n_atexit_handlers-1; i-- > 0; ) { 36 | void (*handler)(void) = atexit_handlers[i]; 37 | handler(); 38 | } 39 | // TODO(bumbread): flush all the unflushed file streams 40 | // TODO(bumbread): close all file streams and delete temporary files 41 | _rt_program_exit(code); 42 | __builtin_unreachable(); 43 | } 44 | 45 | _Noreturn void _Exit(int code) { 46 | _rt_program_exit(code); 47 | __builtin_unreachable(); 48 | } 49 | 50 | _Noreturn void quick_exit(int code) { 51 | for(i64 i = n_at_quick_exit_handlers-1; i-- > 0; ) { 52 | void (*handler)(void) = at_quick_exit_handlers[i]; 53 | handler(); 54 | } 55 | _rt_program_exit(code); 56 | __builtin_unreachable(); 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/cia-mem/allocator.c: -------------------------------------------------------------------------------- 1 | 2 | static void *_null_allocator_proc(void *ctx, int optype, void *old_ptr, u64 old_size, u64 size, u64 alignment) { 3 | return NULL; 4 | } 5 | 6 | Cia_Allocator cia_allocator_null() { 7 | Cia_Allocator allocator = { 8 | .ctx = NULL, 9 | .proc = _null_allocator_proc, 10 | }; 11 | return allocator; 12 | } 13 | 14 | static void *_page_allocator_proc(void *ctx, int optype, void *old_ptr, u64 old_size, u64 size, u64 alignment) { 15 | switch(optype) { 16 | case CIA_MEM_OP_ALLOC: { 17 | void *addr; 18 | if(alignment > 0x1000) { 19 | return NULL; 20 | } 21 | _RT_Status status = _rt_mem_alloc(NULL, size, &addr); 22 | if(status != _RT_STATUS_OK) { 23 | return NULL; 24 | } 25 | return addr; 26 | } break; 27 | case CIA_MEM_OP_FREE: { 28 | _rt_mem_free(old_ptr, old_size); 29 | } break; 30 | case CIA_MEM_OP_FREE_ALL: { 31 | return NULL; 32 | } break; 33 | case CIA_MEM_OP_RESIZE: { 34 | return NULL; 35 | } break; 36 | } 37 | return NULL; 38 | } 39 | 40 | Cia_Allocator cia_allocator_pages() { 41 | Cia_Allocator allocator = { 42 | .ctx = NULL, 43 | .proc = _page_allocator_proc, 44 | }; 45 | return allocator; 46 | } 47 | 48 | void *cia_allocator_alloc(Cia_Allocator *alloc, u64 size, u64 alignment) { 49 | return alloc->proc(alloc->ctx, CIA_MEM_OP_ALLOC, NULL, 0, size, alignment); 50 | } 51 | 52 | void cia_allocator_free_size(Cia_Allocator *alloc, void *region_ptr, u64 region_size) { 53 | alloc->proc(alloc->ctx, CIA_MEM_OP_FREE, region_ptr, region_size, 0, 1); 54 | } 55 | 56 | void cia_allocator_free(Cia_Allocator *alloc, void *region_ptr) { 57 | alloc->proc(alloc->ctx, CIA_MEM_OP_FREE, region_ptr, 0, 0, 1); 58 | } 59 | 60 | void cia_allocator_free_all(Cia_Allocator *alloc) { 61 | alloc->proc(alloc->ctx, CIA_MEM_OP_FREE_ALL, NULL, 0, 0, 1); 62 | } 63 | 64 | void *cia_allocator_resize(Cia_Allocator *alloc, void *old_ptr, u64 old_size, u64 new_size, u64 alignment) { 65 | return alloc->proc(alloc->ctx, CIA_MEM_OP_RESIZE, old_ptr, old_size, new_size, alignment); 66 | } 67 | 68 | 69 | -------------------------------------------------------------------------------- /include/cia/mem.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #if !defined(KB) 5 | #define KB ((i64)1024) 6 | #endif 7 | 8 | #if !defined(MB) 9 | #define MB ((i64)1024*KB) 10 | #endif 11 | 12 | #if !defined(GB) 13 | #define GB ((i64)1024*MB) 14 | #endif 15 | 16 | #if !defined(TB) 17 | #define TB ((i64)1024*GB) 18 | #endif 19 | 20 | void *cia_ptr_alignf(void *ptr, u64 alignment); 21 | void *cia_ptr_alignb(void *ptr, u64 alignment); 22 | u64 cia_size_alignf(u64 size, u64 alignment); 23 | u64 cia_size_alignb(u64 size, u64 alignment); 24 | 25 | #define CIA_MEM_OP_ALLOC 1 26 | #define CIA_MEM_OP_FREE 2 27 | #define CIA_MEM_OP_FREE_ALL 3 28 | #define CIA_MEM_OP_RESIZE 4 29 | 30 | struct Cia_Allocator typedef Cia_Allocator; 31 | struct Cia_Allocator { 32 | void *ctx; 33 | void *(*proc)(void *ctx, int optype, void *old_ptr, u64 old_size, u64 size, u64 alignment); 34 | }; 35 | 36 | Cia_Allocator cia_allocator_null(); 37 | Cia_Allocator cia_allocator_pages(); 38 | 39 | void *cia_allocator_alloc(Cia_Allocator *alloc, u64 size, u64 alignment); 40 | void cia_allocator_free_size(Cia_Allocator *alloc, void *region_ptr, u64 region_size); 41 | void cia_allocator_free(Cia_Allocator *alloc, void *region_ptr); 42 | void cia_allocator_free_all(Cia_Allocator *alloc); 43 | void *cia_allocator_resize(Cia_Allocator *alloc, void *old_ptr, u64 old_size, u64 new_size, u64 alignment); 44 | 45 | struct Cia_Arena typedef Cia_Arena; 46 | struct Cia_Arena { 47 | Cia_Allocator allocator; 48 | u64 buffer_size; 49 | u64 used; 50 | u8* buffer; 51 | }; 52 | 53 | void cia_arena_create(Cia_Arena *arena, Cia_Allocator backing_allocator, u64 max_size); 54 | void *cia_arena_alloc(Cia_Arena *arena, u64 size); 55 | void *cia_arena_alloc_aligned(Cia_Arena *arena, u64 size, u64 align); 56 | void cia_arena_free_all(Cia_Arena *arena); 57 | void cia_arena_destroy(Cia_Arena *arena); 58 | 59 | struct Cia_Pool_Bucket typedef Cia_Pool_Bucket; 60 | struct Cia_Pool_Bucket { 61 | Cia_Pool_Bucket *next; 62 | }; 63 | 64 | struct Cia_Pool_Buffer_Header typedef Cia_Pool_Buffer_Header; 65 | struct Cia_Pool_Buffer_Header { 66 | Cia_Pool_Buffer_Header *next; 67 | }; 68 | 69 | struct Cia_Pool typedef Cia_Pool; 70 | struct Cia_Pool { 71 | Cia_Allocator allocator; 72 | Cia_Pool_Buffer_Header *first; 73 | Cia_Pool_Bucket *freelist_head; 74 | u64 buffer_size; 75 | u64 bucket_size; 76 | u64 alignment; 77 | }; 78 | 79 | void cia_pool_create(Cia_Pool *pool, Cia_Allocator backing_allocator, u64 buffer_size, u64 element_size, u64 alignment); 80 | void *cia_pool_alloc(Cia_Pool *pool); 81 | void cia_pool_free(Cia_Pool *pool, void *ptr); 82 | void cia_pool_free_all(Cia_Pool *pool); 83 | void cia_pool_destroy(Cia_Pool *pool); 84 | 85 | -------------------------------------------------------------------------------- /include/linux/signal.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define SIGHUP 1 5 | #define SIGINT 2 6 | #define SIGQUIT 3 7 | #define SIGILL 4 8 | #define SIGTRAP 5 9 | #define SIGABRT 6 10 | #define SIGBUS 7 11 | #define SIGFPE 8 12 | #define SIGKILL 9 13 | #define SIGUSR1 10 14 | #define SIGSEGV 11 15 | #define SIGUSR2 12 16 | #define SIGPIPE 13 17 | #define SIGALRM 14 18 | #define SIGTERM 15 19 | #define SIGSTKFLT 16 20 | #define SIGCHLD 17 21 | #define SIGCONT 18 22 | #define SIGSTOP 19 23 | #define SIGTSTP 20 24 | #define SIGTTIN 21 25 | #define SIGTTOU 22 26 | #define SIGURG 23 27 | #define SIGXCPU 24 28 | #define SIGXFSZ 25 29 | #define SIGVTALRM 26 30 | #define SIGPROF 27 31 | #define SIGWINCH 28 32 | #define SIGPOLL 29 33 | #define SIGPWR 30 34 | #define SIGSYS 31 35 | #define SIGCLD SIGCHLD 36 | #define SIGIO SIGPOLL 37 | #define SIGIOT SIGABRT 38 | 39 | // Custom guy 40 | #define SIGCANCEL 33 41 | 42 | #define SA_NOCLDSTOP 1 43 | #define SA_NOCLDWAIT 2 44 | #define SA_SIGINFO 4 45 | #define SA_ONSTACK 0x08000000 46 | #define SA_RESTART 0x10000000 47 | #define SA_INTERRUPT 0x20000000 48 | #define SA_NODEFER 0x40000000 49 | #define SA_RESETHAND 0x80000000 50 | #define SA_NOMASK SA_NODEFER 51 | #define SA_ONESHOT SA_RESETHAND 52 | #define SA_STACK SA_ONSTACK 53 | 54 | #define SIG_BLOCK 0 55 | #define SIG_SETMASK 2 56 | #define SIG_UNBLOCK 1 57 | 58 | union sigval { 59 | i32 sival_int; 60 | void *sival_ptr; 61 | }; 62 | 63 | struct siginfo_t typedef siginfo_t; 64 | struct siginfo_t { 65 | i32 si_signo; 66 | i32 si_errno; 67 | i32 si_code; 68 | i32 si_trapno; 69 | u32 si_pid; 70 | u32 si_uid; 71 | i32 si_status; 72 | u64 si_utime; 73 | u64 si_stime; 74 | union sigval si_value; 75 | i32 si_int; 76 | void *si_ptr; 77 | i32 si_overrun; 78 | i32 si_timerid; 79 | void *si_addr; 80 | long si_band; 81 | i32 si_fd; 82 | short si_addr_lsb; 83 | void *si_lower; 84 | void *si_upper; 85 | i32 si_pkey; 86 | void *si_call_addr; 87 | i32 si_syscall; 88 | u32 si_arch; 89 | }; 90 | 91 | 92 | struct sigaction { 93 | union { 94 | void (*sa_handler)(i32); 95 | void (*sa_sigaction)(i32, siginfo_t *, void *); 96 | }; 97 | u64 sa_mask; 98 | i32 sa_flags; 99 | void (*sa_restorer)(void); 100 | }; 101 | 102 | static inline i32 sys_sigaction(i32 signum, const struct sigaction *restrict act, struct sigaction *restrict oldact) { 103 | return (i32)syscall(SYS_rt_sigaction, signum, act, oldact, 1); 104 | } 105 | 106 | -------------------------------------------------------------------------------- /src/stdlib-file/file.c: -------------------------------------------------------------------------------- 1 | 2 | static void _fileapi_init() { 3 | cia_pool_create(&_file_pool, cia_allocator_pages(), 0x1000, sizeof(FILE), 16); 4 | stdin = cia_pool_alloc(&_file_pool); 5 | stdout = cia_pool_alloc(&_file_pool); 6 | stderr = cia_pool_alloc(&_file_pool); 7 | _rt_file_std_handles_init(); 8 | stdin->rt_file = _rt_file_stdin; 9 | stdout->rt_file = _rt_file_stdout; 10 | stderr->rt_file = _rt_file_stderr; 11 | cia_mutex_init(&stdin->mutex); 12 | cia_mutex_init(&stdout->mutex); 13 | cia_mutex_init(&stderr->mutex); 14 | } 15 | 16 | FILE *fopen(char const *restrict filename, char const *restrict mode) { 17 | _RT_File rt_file; 18 | int flags = 0; 19 | while(*mode) { 20 | if(*mode == 'r') flags |= _RT_FILE_READ; 21 | if(*mode == 'w') flags |= _RT_FILE_WRITE; 22 | // TODO: other flags 23 | mode += 1; 24 | } 25 | _RT_Status status = _rt_file_open(&rt_file, filename, flags); 26 | if(status != _RT_STATUS_OK) { 27 | return NULL; 28 | } 29 | cia_mutex_lock(&_g_pool_mutex); 30 | FILE *file = cia_pool_alloc(&_file_pool); // TODO: not thread safe 31 | cia_mutex_unlock(&_g_pool_mutex); 32 | file->rt_file = rt_file; 33 | return file; 34 | } 35 | 36 | int fgetc(FILE *file) { 37 | int c = 0; 38 | u64 bytes_read; 39 | cia_mutex_lock(&file->mutex); 40 | _RT_Status status = _rt_file_read(1, &c, &file->rt_file, &bytes_read); 41 | cia_mutex_unlock(&file->mutex); 42 | if(status == _RT_STATUS_FILE_EOF) { 43 | return EOF; 44 | } 45 | else if(status != _RT_STATUS_OK) { 46 | return EOF; 47 | } 48 | return c; 49 | } 50 | 51 | int fputc(int c, FILE *file) { 52 | u64 bytes_written; 53 | cia_mutex_lock(&file->mutex); 54 | _RT_Status status = _rt_file_write(&file->rt_file, 1, &c, &bytes_written); 55 | cia_mutex_unlock(&file->mutex); 56 | if(status != _RT_STATUS_OK) { 57 | return EOF; 58 | } 59 | return c; 60 | } 61 | 62 | size_t fread(void *restrict buf, size_t size, size_t count, FILE *restrict file) { 63 | u64 bytes_read; 64 | cia_mutex_lock(&file->mutex); 65 | _RT_Status status = _rt_file_read(size*count, buf, &file->rt_file, &bytes_read); 66 | cia_mutex_unlock(&file->mutex); 67 | if(status != _RT_STATUS_OK) { 68 | return 0; 69 | } 70 | return bytes_read / size; 71 | } 72 | 73 | size_t fwrite(void const *restrict buf, size_t size, size_t count, FILE *restrict file) { 74 | u64 bytes_written; 75 | cia_mutex_lock(&file->mutex); 76 | _RT_Status status = _rt_file_write(&file->rt_file, size*count, (void *)buf, &bytes_written); 77 | cia_mutex_unlock(&file->mutex); 78 | if(status != _RT_STATUS_OK) { 79 | return 0; 80 | } 81 | return bytes_written / size; 82 | } 83 | 84 | int fclose(FILE *file) { 85 | _RT_Status status = _rt_file_close(&file->rt_file); 86 | if(status != _RT_STATUS_OK) { 87 | return EOF; 88 | } 89 | cia_mutex_lock(&_g_pool_mutex); 90 | cia_pool_free(&_file_pool, file); 91 | cia_mutex_unlock(&_g_pool_mutex); 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /include/linux/futex.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | #define FUTEX_WAIT 0 7 | #define FUTEX_WAKE 1 8 | #define FUTEX_FD 2 9 | #define FUTEX_REQUEUE 3 10 | #define FUTEX_CMP_REQUEUE 4 11 | #define FUTEX_WAKE_OP 5 12 | #define FUTEX_LOCK_PI 6 13 | #define FUTEX_UNLOCK_PI 7 14 | #define FUTEX_TRYLOCK_PI 8 15 | #define FUTEX_WAIT_BITSET 9 16 | #define FUTEX_WAKE_BITSET 10 17 | #define FUTEX_WAIT_REQUEUE_PI 11 18 | #define FUTEX_CMP_REQUEUE_PI 12 19 | #define FUTEX_LOCK_PI2 13 20 | 21 | #define FUTEX_PRIVATE_FLAG 128 22 | #define FUTEX_CLOCK_REALTIME 256 23 | #define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) 24 | 25 | #define FUTEX_WAIT_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_WAIT) 26 | #define FUTEX_WAKE_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_WAKE) 27 | #define FUTEX_REQUEUE_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_REQUEUE) 28 | #define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE) 29 | #define FUTEX_WAKE_OP_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_WAKE_OP) 30 | #define FUTEX_LOCK_PI_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_LOCK_PI) 31 | #define FUTEX_LOCK_PI2_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_LOCK_PI2) 32 | #define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_UNLOCK_PI) 33 | #define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_TRYLOCK_PI) 34 | #define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_WAIT_BITSET) 35 | #define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_WAKE_BITSET) 36 | #define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_WAIT_REQUEUE_PI) 37 | #define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_PRIVATE_FLAG | FUTEX_CMP_REQUEUE_PI) 38 | 39 | #define FUTEX_32 2 40 | #define FUTEX_WAITV_MAX 128 41 | 42 | struct futex_waitv { 43 | u64 val; 44 | u64 uaddr; 45 | u32 flags; 46 | u32 __reserved; 47 | }; 48 | 49 | struct robust_list { 50 | struct robust_list *next; 51 | }; 52 | 53 | struct robust_list_head { 54 | struct robust_list list; 55 | long futex_offset; 56 | struct robust_list *list_op_pending; 57 | }; 58 | 59 | #define FUTEX_WAITERS 0x80000000 60 | #define FUTEX_OWNER_DIED 0x40000000 61 | #define FUTEX_TID_MASK 0x3fffffff 62 | #define ROBUST_LIST_LIMIT 2048 63 | #define FUTEX_BITSET_MATCH_ANY 0xffffffff 64 | 65 | #define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */ 66 | #define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */ 67 | #define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */ 68 | #define FUTEX_OP_ANDN 3 /* *(int *)UADDR2 &= ~OPARG; */ 69 | #define FUTEX_OP_XOR 4 /* *(int *)UADDR2 ^= OPARG; */ 70 | #define FUTEX_OP_OPARG_SHIFT 8 /* Use (1 << OPARG) instead of OPARG. */ 71 | #define FUTEX_OP_CMP_EQ 0 /* if (oldval == CMPARG) wake */ 72 | #define FUTEX_OP_CMP_NE 1 /* if (oldval != CMPARG) wake */ 73 | #define FUTEX_OP_CMP_LT 2 /* if (oldval < CMPARG) wake */ 74 | #define FUTEX_OP_CMP_LE 3 /* if (oldval <= CMPARG) wake */ 75 | #define FUTEX_OP_CMP_GT 4 /* if (oldval > CMPARG) wake */ 76 | #define FUTEX_OP_CMP_GE 5 /* if (oldval >= CMPARG) wake */ 77 | 78 | -------------------------------------------------------------------------------- /os/windows/tinyrt.c: -------------------------------------------------------------------------------- 1 | 2 | // See src/tinyrt.h file for the interface this file implements 3 | 4 | static _RT_Status _rt_file_std_handles_init() { 5 | _rt_file_stdin.handle = GetStdHandle(STD_INPUT_HANDLE); 6 | _rt_file_stdin.flags = _RT_FILE_READ; 7 | _rt_file_stdout.handle = GetStdHandle(STD_OUTPUT_HANDLE); 8 | _rt_file_stdout.flags = _RT_FILE_WRITE; 9 | _rt_file_stderr.handle = GetStdHandle(STD_ERROR_HANDLE); 10 | _rt_file_stdout.flags = _RT_FILE_WRITE; 11 | return _RT_STATUS_OK; 12 | } 13 | 14 | static _RT_Status _rt_file_open(_RT_File *file, char const *name, int _rt_flags) { 15 | u32 access = 0; 16 | if(_rt_flags & _RT_FILE_READ) access |= GENERIC_READ; 17 | if(_rt_flags & _RT_FILE_WRITE) access |= GENERIC_WRITE; 18 | u32 share = 0; 19 | if((_rt_flags & _RT_FILE_READ) == 0) share |= FILE_SHARE_READ; 20 | u32 creation = 0; 21 | if(_rt_flags & _RT_FILE_TRUNCATE) { 22 | creation = TRUNCATE_EXISTING; 23 | } 24 | else if(_rt_flags & _RT_FILE_CREATE) { 25 | if(_rt_flags & _RT_FILE_EXCLUSIVE) creation = CREATE_ALWAYS; 26 | else creation = CREATE_NEW; 27 | } 28 | else { 29 | if(_rt_flags & _RT_FILE_EXCLUSIVE) creation = OPEN_ALWAYS; 30 | else creation = OPEN_EXISTING; 31 | } 32 | HANDLE handle = CreateFileA(name, access, share, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL); 33 | if(file == INVALID_HANDLE_VALUE) { 34 | // ERROR_FILE_NOT_FOUND 35 | // ERROR_PATH_NOT_FOUND 36 | // ERROR_ACCESS_DENIED 37 | // ERROR_NOT_ENOUGH_MEMORY 38 | return _RT_STATUS_FILE_IO_ERROR; 39 | 40 | } 41 | file->handle = handle; 42 | file->flags = _rt_flags; 43 | return _RT_STATUS_OK; 44 | } 45 | 46 | static _RT_Status _rt_file_read(u64 size, void *buffer, _RT_File *from, u64 *out_bytes_read) { 47 | *out_bytes_read = 0; 48 | BOOL ok = ReadFile(from->handle, buffer, size, (unsigned long *)out_bytes_read, NULL); 49 | if(!ok) { 50 | return _RT_STATUS_FILE_IO_ERROR; 51 | } 52 | return _RT_STATUS_OK; 53 | } 54 | 55 | static _RT_Status _rt_file_write(_RT_File *to, u64 size, void *buffer, u64 *out_bytes_written) { 56 | *out_bytes_written = 0; 57 | BOOL ok = WriteFile(to->handle, buffer, size, (unsigned long *)out_bytes_written, NULL); 58 | if(!ok) { 59 | return _RT_STATUS_FILE_IO_ERROR; 60 | } 61 | return _RT_STATUS_OK; 62 | } 63 | 64 | static _RT_Status _rt_file_close(_RT_File *file) { 65 | BOOL ok = CloseHandle(file->handle); 66 | if(!ok) { 67 | return _RT_STATUS_FILE_BAD_FILE; 68 | } 69 | return _RT_STATUS_OK; 70 | } 71 | 72 | _Noreturn static void _rt_program_exit(int code) { 73 | ExitProcess(code); 74 | __builtin_unreachable(); 75 | } 76 | 77 | static _RT_Status _rt_mem_alloc(void *optional_desired_addr, u64 min_size, void **out_addr) { 78 | void *addr = VirtualAlloc(optional_desired_addr, min_size, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); 79 | *out_addr = addr; 80 | if(addr == NULL) { 81 | return _RT_ERROR_GENERIC; 82 | } 83 | return _RT_STATUS_OK; 84 | } 85 | 86 | static _RT_Status _rt_mem_free(void *addr, u64 size) { 87 | BOOL ok = VirtualFree(addr, 0, MEM_RELEASE); 88 | if(!ok) { 89 | return _RT_ERROR_GENERIC; 90 | } 91 | return _RT_STATUS_OK; 92 | } 93 | 94 | -------------------------------------------------------------------------------- /src/cia-mem/pool.c: -------------------------------------------------------------------------------- 1 | 2 | static void _pool_buffer_freelist_add(Cia_Pool *pool, u8 *buffer) { 3 | Cia_Pool_Buffer_Header *header = (Cia_Pool_Buffer_Header *)buffer; 4 | u64 header_size = sizeof(Cia_Pool_Buffer_Header); 5 | u64 header_size_aligned = cia_size_alignf(header_size, pool->alignment); 6 | u8 *buckets = buffer + header_size_aligned; 7 | u64 remaining_size = pool->buffer_size - header_size_aligned; 8 | u64 buckets_count = remaining_size / pool->bucket_size; 9 | u64 buckets_size = buckets_count * pool->bucket_size; 10 | // Initialize every bucket as free 11 | u64 bucket_offset = header_size_aligned + buckets_size; 12 | Cia_Pool_Bucket *next_bucket = pool->freelist_head; 13 | do { 14 | bucket_offset -= pool->bucket_size; 15 | Cia_Pool_Bucket *bucket = (Cia_Pool_Bucket *)(buffer + bucket_offset); 16 | bucket->next = next_bucket; 17 | next_bucket = bucket; 18 | } while(bucket_offset > header_size_aligned); 19 | // Add the head of the newly-created freelist to the existing freelist 20 | pool->freelist_head = next_bucket; 21 | } 22 | 23 | void cia_pool_create(Cia_Pool *pool, Cia_Allocator backing_allocator, u64 buffer_size, u64 bucket_size, u64 alignment) { 24 | pool->allocator = backing_allocator; 25 | pool->buffer_size = buffer_size; 26 | pool->bucket_size = bucket_size; 27 | pool->alignment = alignment; 28 | // If the unallocated element can't hold a bucket, increase the size of the element 29 | if(pool->bucket_size < sizeof(Cia_Pool_Bucket)) { 30 | pool->bucket_size = sizeof(Cia_Pool_Bucket); 31 | } 32 | // Make element size a multiple of the alignment 33 | pool->bucket_size = cia_size_alignf(pool->bucket_size, pool->alignment); 34 | // Allocate and initialize the first buffer 35 | pool->freelist_head = NULL; 36 | pool->first = cia_allocator_alloc(&pool->allocator, pool->buffer_size, pool->alignment); 37 | _pool_buffer_freelist_add(pool, (u8 *)pool->first); 38 | } 39 | 40 | void *cia_pool_alloc(Cia_Pool *pool) { 41 | // If we don't have enough free buckets, create a new buffer 42 | if(pool->freelist_head == NULL) { 43 | void *buffer = cia_allocator_alloc(&pool->allocator, pool->buffer_size, pool->alignment); 44 | _pool_buffer_freelist_add(pool, buffer); 45 | } 46 | // Remove item from free list and return it 47 | void *addr = pool->freelist_head; 48 | pool->freelist_head = pool->freelist_head->next; 49 | return addr; 50 | } 51 | 52 | void cia_pool_free(Cia_Pool *pool, void *ptr) { 53 | // Add bucket to free list 54 | Cia_Pool_Bucket *bucket = ptr; 55 | bucket->next = pool->freelist_head; 56 | pool->freelist_head = bucket; 57 | } 58 | 59 | void cia_pool_free_all(Cia_Pool *pool) { 60 | // Deallocate all buffers except the first one 61 | for(Cia_Pool_Buffer_Header *buffer = pool->first->next; buffer != NULL; buffer = buffer->next) { 62 | cia_allocator_free_size(&pool->allocator, buffer, pool->buffer_size); 63 | } 64 | // Reinit the first buffer 65 | pool->freelist_head = NULL; 66 | _pool_buffer_freelist_add(pool, (u8 *)pool->first); 67 | } 68 | 69 | void cia_pool_destroy(Cia_Pool *pool) { 70 | // Simply deallocate all the buffers 71 | for(Cia_Pool_Buffer_Header *buffer = pool->first; buffer != NULL; buffer = buffer->next) { 72 | cia_allocator_free_size(&pool->allocator, buffer, pool->buffer_size); 73 | } 74 | } -------------------------------------------------------------------------------- /tests/mm_seq_cst.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #if 1 7 | enum memory_order store_memory_order = memory_order_release; 8 | enum memory_order load_memory_order = memory_order_acquire; 9 | #else 10 | enum memory_order store_memory_order = memory_order_seq_cst; 11 | enum memory_order load_memory_order = memory_order_seq_cst; 12 | #endif 13 | 14 | // Scheduler on linux has too coarse granularity 15 | // to allow a thread to kind of a lot of work 16 | // before switching to another thread. If we 17 | // introduce an arbitrary delay, the threads will 18 | // be able to be run in a random order better. 19 | // Without it, the threads seem to be run as they are 20 | // created, i.e. the scheduling is too convenient and 21 | // hides a potential bug that we're testing for here 22 | #define delay_that_works 1000000 23 | #define arbitrary_delay(n) for(volatile int i = 0; i < n; ++i) 24 | 25 | // This is all the explicit shared state between threads. 26 | struct Shared_State typedef Shared_State; 27 | struct Shared_State { 28 | _Atomic(int) x; 29 | _Atomic(int) y; 30 | _Atomic(int) cnt; 31 | }; 32 | static Shared_State g_shared_state = {0}; 33 | 34 | // Sets the atomic flag x 35 | int tx(void *ctx) { 36 | arbitrary_delay(delay_that_works); 37 | Shared_State *ss = ctx; 38 | printf("Thread %s running\n", "tx"); 39 | atomic_store_explicit(&ss->x, 1, store_memory_order); 40 | return 0; 41 | } 42 | 43 | // Set the atomic flag y 44 | int ty(void *ctx) { 45 | arbitrary_delay(delay_that_works); 46 | Shared_State *ss = ctx; 47 | printf("Thread %s running\n", "ty"); 48 | atomic_store_explicit(&ss->y, 1, store_memory_order); 49 | return 0; 50 | } 51 | 52 | // Spinlock until flag x is set, if y is also set, add 1 to cnt 53 | int t1(void *ctx) { 54 | arbitrary_delay(delay_that_works); 55 | Shared_State *ss = ctx; 56 | printf("Thread %s running\n", "t1"); 57 | while(atomic_load_explicit(&ss->x, load_memory_order) == 0) 58 | ; 59 | if(atomic_load_explicit(&ss->y, load_memory_order) == 1) { 60 | atomic_fetch_add_explicit(&ss->cnt, 1, memory_order_relaxed); 61 | } 62 | return 0; 63 | } 64 | 65 | // Spinlock until flag y is set, if x is also set, add 1 to cnt 66 | int t2(void *ctx) { 67 | arbitrary_delay(delay_that_works); 68 | Shared_State *ss = ctx; 69 | printf("Thread %s running\n", "t2"); 70 | while(atomic_load_explicit(&ss->y, load_memory_order) == 0) 71 | ; 72 | if(atomic_load_explicit(&ss->x, load_memory_order) == 1) { 73 | atomic_fetch_add_explicit(&ss->cnt, 1, memory_order_relaxed); 74 | } 75 | return 0; 76 | } 77 | 78 | int main() { 79 | // TODO: rewrite this to run in a loop after I 80 | // fix stack leaking on thread destruction 81 | thrd_start_t thread_funcs[4] = {tx,ty,t1,t2}; 82 | thrd_t threads[4]; 83 | // Spawn the threads 84 | for(int i = 0; i < 4; ++i) { 85 | int status = thrd_create(&threads[i], thread_funcs[i], &g_shared_state); 86 | if(status != thrd_success) { 87 | printf("Thread unable to start\n"); 88 | return 1; 89 | } 90 | } 91 | // Wait for threads to complete 92 | for(int i = 0; i < 4; ++i) { 93 | int _exit_code; 94 | thrd_join(threads[i], &_exit_code); 95 | } 96 | // Check to see the cnt variable 97 | int result = atomic_load_explicit(&g_shared_state.cnt, memory_order_relaxed); 98 | printf("result: %d\n", result); 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /loader/loader.h: -------------------------------------------------------------------------------- 1 | 2 | #define AUX_CNT 32 3 | #define DYN_CNT 37 4 | 5 | #define _mfence() asm volatile("" ::: "memory") 6 | 7 | struct Loader_Info typedef Loader_Info; 8 | struct Loader_Info { 9 | u64 *sp; 10 | u8 *ldso_base; 11 | u64 *dyn; 12 | u64 *aux; 13 | }; 14 | 15 | static void print_string_n(char *str, u64 len) { 16 | sys_write(STDOUT_FILENO, str, len); 17 | } 18 | static void print_char(char c) { 19 | print_string_n(&c, 1); 20 | } 21 | static void print_string(char *str) { 22 | int str_len = 0; 23 | while(str[str_len] != 0) { 24 | str_len += 1; 25 | } 26 | print_string_n(str, str_len); 27 | } 28 | static void print_int(i64 number) { 29 | if(number < 0) { 30 | print_char('-'); 31 | number = -number; 32 | } 33 | char buf[20]; 34 | buf[19] = 0; 35 | char *p = buf + sizeof buf - 1; 36 | do { 37 | *--p = (number%10) + '0'; 38 | number /= 10; 39 | } while(number > 0); 40 | print_string(p); 41 | } 42 | static void print_uint(u64 number) { 43 | char buf[20]; 44 | buf[19] = 0; 45 | char *p = buf + sizeof buf - 1; 46 | do { 47 | *--p = (number%10) + '0'; 48 | number /= 10; 49 | } while(number > 0); 50 | print_string(p); 51 | } 52 | static void print_hex(u64 number) { 53 | print_string("0x"); 54 | char digits[] = "0123456789abcdef"; 55 | char buf[20]; 56 | buf[19] = 0; 57 | char *p = buf + sizeof buf - 1; 58 | for(int i = 0; i < 64; i += 4) { 59 | // if(i != 0 && i % 16 == 0) { 60 | // *--p = '_'; 61 | // } 62 | u8 bits = (number >> i) & 0x0f; 63 | char digit = digits[bits]; 64 | *--p = digit; 65 | } 66 | print_string(p); 67 | } 68 | static void printf(char *fmt, ...) { 69 | va_list args; 70 | va_start(args, fmt); 71 | char str_buf[256]; 72 | i64 buf_i = 0; 73 | while(*fmt != 0) { 74 | while(*fmt != '%' && *fmt != 0 && buf_i != sizeof str_buf-1) { 75 | str_buf[buf_i] = *fmt; 76 | buf_i += 1; 77 | fmt++; 78 | } 79 | str_buf[buf_i] = 0; 80 | print_string_n(str_buf, buf_i); 81 | buf_i = 0; 82 | if(*fmt == '%') { 83 | ++fmt; 84 | if(*fmt == 'd') { 85 | i64 number = va_arg(args, i64); 86 | print_int(number); 87 | } 88 | else if(*fmt == 'u') { 89 | u64 number = va_arg(args, u64); 90 | print_uint(number); 91 | } 92 | else if(*fmt == 'x') { 93 | u64 number = va_arg(args, u64); 94 | print_hex(number); 95 | } 96 | else if(*fmt == 's') { 97 | char *str = va_arg(args, char *); 98 | print_string(str); 99 | } 100 | else if(*fmt == 'c') { 101 | int c = va_arg(args, int); 102 | print_char(c); 103 | } 104 | ++fmt; 105 | } 106 | } 107 | va_end(args); 108 | } 109 | 110 | #if defined(_DEBUG) && defined(_CIA_LD_DEBUG) 111 | #define _dbg_print_char(c) print_char(c) 112 | #define _dbg_print_string(s) print_string(s) 113 | #define _dbg_print_string_n(s,n) print_string_n(s,n) 114 | #define _dbg_print_int(d) print_int(d) 115 | #define _dbg_print_uint(u) print_uint(u) 116 | #define _dbg_print_hex(x) print_hex(x) 117 | #define _dbg_printf(fmt, ...) printf(fmt, ##__VA_ARGS__) 118 | #else 119 | #define _dbg_print_char(c) do {} while(0) 120 | #define _dbg_print_string(s) do {} while(0) 121 | #define _dbg_print_string_n(s,n) do {} while(0) 122 | #define _dbg_print_int(d) do {} while(0) 123 | #define _dbg_print_uint(u) do {} while(0) 124 | #define _dbg_print_hex(x) do {} while(0) 125 | #define _dbg_printf(fmt, ...) do {} while(0) 126 | #endif 127 | 128 | -------------------------------------------------------------------------------- /include/tinyrt.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | // Common status 7 | #define _RT_STATUS_OK 0 // No errors 8 | #define _RT_ERROR_NOT_IMPLEMENTED -1 // Function not implemented 9 | #define _RT_ERROR_BAD_PARAM -2 // One of the function parameters was wrong 10 | #define _RT_ERROR_GENERIC -3 // Just any random error 11 | 12 | // File API status 13 | #define _RT_STATUS_FILE_ACCESS 1 // No access to the file 14 | #define _RT_STATUS_FILE_NO_SPACE 2 // Storage device has no space for the file 15 | #define _RT_STATUS_FILE_EXISTS 3 // File exists when shouldn't 16 | #define _RT_STATUS_FILE_NOT_EXISTS 4 // File doesn't exist when should 17 | #define _RT_STATUS_FILE_DIRECTORY 5 // The file was a directory when shouldn't've been 18 | #define _RT_STATUS_FILE_NOT_DIRECTORY 6 // The file wasn't a directory when should've been 19 | #define _RT_STATUS_FILE_NAME_TOO_LONG 7 // The filename was too long for the Filesystem 20 | #define _RT_STATUS_FILE_LOOP 8 // Too many symlinks followed or a symlink encountered when expected none 21 | #define _RT_STATUS_FILE_BUSY 9 // The device is busy if exclusive access is requested 22 | #define _RT_STATUS_FILE_TOO_MANY_OPEN 10 // Too many open files in the process 23 | #define _RT_STATUS_FILE_NO_MEMORY 11 // No kernel memory or user limit on memory allocation exceeded 24 | #define _RT_STATUS_FILE_IO_ERROR 12 // I/O error 25 | #define _RT_STATUS_FILE_BAD_FILE 13 // Bad file handle 26 | #define _RT_STATUS_FILE_EOF 14 // Read operation reached the end-of-file 27 | 28 | // File API flags 29 | #define _RT_FILE_READ 0x01 30 | #define _RT_FILE_WRITE 0x02 31 | #define _RT_FILE_CREATE 0x04 32 | #define _RT_FILE_EXCLUSIVE 0x08 33 | #define _RT_FILE_TRUNCATE 0x10 34 | 35 | // Sync API sleep constant 36 | #define _RT_SYNC_WAIT_INFINITE 0xffffffffffffffffULL 37 | 38 | typedef i32 _RT_Status; 39 | 40 | // API implementation flags (managed and used by the layers on top of tinyrt) 41 | static bool _rt_api_file; 42 | static bool _rt_api_tmpfile; 43 | 44 | // Initialization & termination of minirt 45 | static _RT_Status _rt_init(); 46 | static _RT_Status _rt_deinit(); 47 | 48 | // Program API 49 | _Noreturn static void _rt_program_exit(int code); 50 | 51 | // Thread API 52 | struct _RT_Thread typedef _RT_Thread; 53 | struct _RT_Thread { 54 | void *handle; 55 | }; 56 | static _RT_Status _rt_thread_current(_RT_Thread *thread); 57 | static _RT_Status _rt_thread_create(_RT_Thread *thread, int (*thread_fn)(void *ctx), void *ctx); 58 | static _RT_Status _rt_thread_join(_RT_Thread *thread, int *out_exit_code); 59 | static _RT_Status _rt_thread_detach(_RT_Thread *thread); 60 | static _RT_Status _rt_thread_terminate(_RT_Thread *thread); 61 | static _RT_Status _rt_thread_yield(); 62 | static _RT_Status _rt_thread_sleep(u64 time); 63 | static _RT_Status _rt_thread_get_timer_freq(u64 *freq); 64 | 65 | // TODO: maybe replace with kill of single thread 66 | static _RT_Status _rt_thread_cancell_all_running(); 67 | 68 | // Environment API 69 | static _RT_Status _rt_shell_exec(char const *cmd); 70 | static _RT_Status _rt_env_get(char const *name); 71 | 72 | // File API 73 | struct _RT_File typedef _RT_File; 74 | struct _RT_File { 75 | union { 76 | void *handle; 77 | u64 fd; 78 | }; 79 | i32 flags; 80 | }; 81 | static _RT_File _rt_file_stdin; 82 | static _RT_File _rt_file_stdout; 83 | static _RT_File _rt_file_stderr; 84 | static _RT_Status _rt_file_std_handles_init(); 85 | static _RT_Status _rt_file_open(_RT_File *file, char const *name, int flags); 86 | static _RT_Status _rt_file_read(u64 size, void *buffer, _RT_File *from, u64 *out_bytes_read); 87 | static _RT_Status _rt_file_write(_RT_File *to, u64 size, void *buffer, u64 *out_bytes_written); 88 | static _RT_Status _rt_file_close(_RT_File *file); 89 | 90 | // Memory API 91 | static _RT_Status _rt_mem_alloc(void *optional_desired_addr, u64 size, void **out_addr); 92 | static _RT_Status _rt_mem_free(void *ptr, u64 size); 93 | 94 | // Synchronization API 95 | static _RT_Status _rt_sync_wait(void *addr, u32 compare_with, u64 time); 96 | static _RT_Status _rt_sync_wake_one(void *addr, u32 *n_woken); 97 | static _RT_Status _rt_sync_wake_all(void *addr, u32 *n_woken); -------------------------------------------------------------------------------- /os/linux/tinyrt.c: -------------------------------------------------------------------------------- 1 | 2 | // See src/tinyrt.h file for the interface this file implements 3 | 4 | _Noreturn static void _rt_program_exit(int code) { 5 | sys_exit(code); 6 | } 7 | 8 | static _RT_Status _rt_file_std_handles_init() { 9 | _rt_file_stdin.fd = 0; 10 | _rt_file_stdin.flags = _RT_FILE_READ; 11 | _rt_file_stdout.fd = 1; 12 | _rt_file_stdout.flags = _RT_FILE_WRITE; 13 | _rt_file_stderr.fd = 2; 14 | _rt_file_stdout.flags = _RT_FILE_WRITE; 15 | return _RT_STATUS_OK; 16 | } 17 | 18 | static _RT_Status _rt_file_open(_RT_File *file, char const *name, int _rt_flags) { 19 | if((_rt_flags & 0x3) == 0) { 20 | return _RT_ERROR_BAD_PARAM; 21 | } 22 | int mode = 0; 23 | int flags = 0; 24 | if((_rt_flags & 0x03) == 0x03) mode = O_RDWR; 25 | else if(_rt_flags & _RT_FILE_READ) mode = O_RDONLY; 26 | else if(_rt_flags & _RT_FILE_WRITE) mode = O_RDWR; 27 | if(_rt_flags & _RT_FILE_CREATE) flags |= O_CREAT; 28 | if(_rt_flags & _RT_FILE_EXCLUSIVE) flags |= O_EXCL; 29 | if(_rt_flags & _RT_FILE_TRUNCATE) flags |= O_TRUNC; 30 | i64 fd = sys_open(name, flags, mode); 31 | if(-fd == EACCES) return _RT_STATUS_FILE_ACCESS; 32 | if(-fd == EEXIST) return _RT_STATUS_FILE_EXISTS; 33 | if(-fd == ENOENT) return _RT_STATUS_FILE_NOT_EXISTS; 34 | if(-fd == EINVAL) return _RT_ERROR_BAD_PARAM; 35 | if(-fd == EISDIR) return _RT_STATUS_FILE_DIRECTORY; 36 | // I'm too lazy to fill in the rest so lets leave it at that for now 37 | if(fd < 0) return _RT_STATUS_FILE_IO_ERROR; 38 | file->fd = (u64)fd; 39 | file->flags = _rt_flags; 40 | return _RT_STATUS_OK; 41 | } 42 | 43 | static _RT_Status _rt_file_read(u64 size, void *buffer, _RT_File *from, u64 *out_bytes_read) { 44 | i64 bytes_read = sys_read(from->fd, buffer, size); 45 | if(bytes_read == 0) { 46 | return _RT_STATUS_FILE_EOF; 47 | } 48 | if(bytes_read < 0) { 49 | return _RT_STATUS_FILE_IO_ERROR; 50 | } 51 | *out_bytes_read = bytes_read; 52 | return _RT_STATUS_OK; 53 | } 54 | 55 | static _RT_Status _rt_file_write(_RT_File *to, u64 size, void *buffer, u64 *out_bytes_written) { 56 | i64 status = sys_write(to->fd, buffer, size); 57 | if(-status == EBADF) return _RT_ERROR_BAD_PARAM; 58 | if(-status == EIO) return _RT_STATUS_FILE_IO_ERROR; 59 | if(-status > 0) return _RT_STATUS_FILE_IO_ERROR; 60 | *out_bytes_written = status; 61 | return _RT_STATUS_OK; 62 | } 63 | 64 | static _RT_Status _rt_file_close(_RT_File *file) { 65 | i64 result = sys_close(file->fd); 66 | if(result < 0) { 67 | return _RT_STATUS_FILE_IO_ERROR; 68 | } 69 | return _RT_STATUS_OK; 70 | } 71 | 72 | static _RT_Status _rt_mem_alloc(void *optional_desired_addr, u64 size, void **out_addr) { 73 | void *addr = sys_mmap((u64)optional_desired_addr, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 74 | if(addr == NULL) { 75 | return _RT_ERROR_GENERIC; 76 | } 77 | *out_addr = addr; 78 | return _RT_STATUS_OK; 79 | } 80 | 81 | static _RT_Status _rt_mem_free(void *ptr, u64 len) { 82 | i64 result = sys_munmap(ptr, len); 83 | if(result == -1) { 84 | return _RT_ERROR_GENERIC; 85 | } 86 | return _RT_STATUS_OK; 87 | } 88 | 89 | static _RT_Status _rt_sync_wait(void *addr, u32 compare_with, u64 sleep) { 90 | i64 result = syscall(SYS_futex, addr, FUTEX_WAIT_PRIVATE, compare_with, NULL, 0, 0); 91 | if(-result == EAGAIN) { 92 | return _RT_STATUS_OK; 93 | } 94 | else if(-result > 0) { 95 | return _RT_ERROR_GENERIC; 96 | } 97 | return _RT_STATUS_OK; 98 | } 99 | 100 | static _RT_Status _rt_sync_wake_one(void *addr, u32 *n_woken) { 101 | i64 result = syscall(SYS_futex, addr, FUTEX_WAKE_PRIVATE, 1, NULL, 0, 0); 102 | if(result < 0) { 103 | return _RT_ERROR_GENERIC; 104 | } 105 | if(n_woken != NULL) { 106 | *n_woken = (u32)result; 107 | } 108 | return _RT_STATUS_OK; 109 | } 110 | 111 | static _RT_Status _rt_sync_wake_all(void *addr, u32 *n_woken) { 112 | i64 result = syscall(SYS_futex, addr, FUTEX_WAKE_PRIVATE, 0x7fffffff, NULL, 0, 0); 113 | if(result < 0) { 114 | return _RT_ERROR_GENERIC; 115 | } 116 | if(n_woken != NULL) { 117 | *n_woken = (u32)result; 118 | } 119 | return _RT_STATUS_OK; 120 | } 121 | -------------------------------------------------------------------------------- /include/errno.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | extern _Thread_local int errno; 5 | 6 | // errno-base.h 7 | #define EPERM 1 8 | #define ENOENT 2 9 | #define ESRCH 3 10 | #define EINTR 4 11 | #define EIO 5 12 | #define ENXIO 6 13 | #define E2BIG 7 14 | #define ENOEXEC 8 15 | #define EBADF 9 16 | #define ECHILD 10 17 | #define EAGAIN 11 18 | #define ENOMEM 12 19 | #define EACCES 13 20 | #define EFAULT 14 21 | #define ENOTBLK 15 22 | #define EBUSY 16 23 | #define EEXIST 17 24 | #define EXDEV 18 25 | #define ENODEV 19 26 | #define ENOTDIR 20 27 | #define EISDIR 21 28 | #define EINVAL 22 29 | #define ENFILE 23 30 | #define EMFILE 24 31 | #define ENOTTY 25 32 | #define ETXTBSY 26 33 | #define EFBIG 27 34 | #define ENOSPC 28 35 | #define ESPIPE 29 36 | #define EROFS 30 37 | #define EMLINK 31 38 | #define EPIPE 32 39 | #define EDOM 33 40 | #define ERANGE 34 41 | 42 | // linux/errno.h 43 | #define EDEADLK 35 44 | #define ENAMETOOLONG 36 45 | #define ENOLCK 37 46 | #define ENOSYS 38 47 | #define ENOTEMPTY 39 48 | #define ELOOP 40 49 | #define EWOULDBLOCK EAGAIN 50 | #define ENOMSG 42 51 | #define EIDRM 43 52 | #define ECHRNG 44 53 | #define EL2NSYNC 45 54 | #define EL3HLT 46 55 | #define EL3RST 47 56 | #define ELNRNG 48 57 | #define EUNATCH 49 58 | #define ENOCSI 50 59 | #define EL2HLT 51 60 | #define EBADE 52 61 | #define EBADR 53 62 | #define EXFULL 54 63 | #define ENOANO 55 64 | #define EBADRQC 56 65 | #define EBADSLT 57 66 | #define EDEADLOCK EDEADLK 67 | #define EBFONT 59 68 | #define ENOSTR 60 69 | #define ENODATA 61 70 | #define ETIME 62 71 | #define ENOSR 63 72 | #define ENONET 64 73 | #define ENOPKG 65 74 | #define EREMOTE 66 75 | #define ENOLINK 67 76 | #define EADV 68 77 | #define ESRMNT 69 78 | #define ECOMM 70 79 | #define EPROTO 71 80 | #define EMULTIHOP 72 81 | #define EDOTDOT 73 82 | #define EBADMSG 74 83 | #define EOVERFLOW 75 84 | #define ENOTUNIQ 76 85 | #define EBADFD 77 86 | #define EREMCHG 78 87 | #define ELIBACC 79 88 | #define ELIBBAD 80 89 | #define ELIBSCN 81 90 | #define ELIBMAX 82 91 | #define ELIBEXEC 83 92 | #define EILSEQ 84 93 | #define ERESTART 85 94 | #define ESTRPIPE 86 95 | #define EUSERS 87 96 | #define ENOTSOCK 88 97 | #define EDESTADDRREQ 89 98 | #define EMSGSIZE 90 99 | #define EPROTOTYPE 91 100 | #define ENOPROTOOPT 92 101 | #define EPROTONOSUPPORT 93 102 | #define ESOCKTNOSUPPORT 94 103 | #define EOPNOTSUPP 95 104 | #define EPFNOSUPPORT 96 105 | #define EAFNOSUPPORT 97 106 | #define EADDRINUSE 98 107 | #define EADDRNOTAVAIL 99 108 | #define ENETDOWN 100 109 | #define ENETUNREACH 101 110 | #define ENETRESET 102 111 | #define ECONNABORTED 103 112 | #define ECONNRESET 104 113 | #define ENOBUFS 105 114 | #define EISCONN 106 115 | #define ENOTCONN 107 116 | #define ESHUTDOWN 108 117 | #define ETOOMANYREFS 109 118 | #define ETIMEDOUT 110 119 | #define ECONNREFUSED 111 120 | #define EHOSTDOWN 112 121 | #define EHOSTUNREACH 113 122 | #define EALREADY 114 123 | #define EINPROGRESS 115 124 | #define ESTALE 116 125 | #define EUCLEAN 117 126 | #define ENOTNAM 118 127 | #define ENAVAIL 119 128 | #define EISNAM 120 129 | #define EREMOTEIO 121 130 | #define EDQUOT 122 131 | #define ENOMEDIUM 123 132 | #define EMEDIUMTYPE 124 133 | #define ECANCELED 125 134 | #define ENOKEY 126 135 | #define EKEYEXPIRED 127 136 | #define EKEYREVOKED 128 137 | #define EKEYREJECTED 129 138 | #define EOWNERDEAD 130 139 | #define ENOTRECOVERABLE 131 140 | #define ERFKILL 132 141 | #define EHWPOISON 133 142 | 143 | // other stuff 144 | #ifndef ENOTSUP 145 | #define ENOTSUP EOPNOTSUPP 146 | #endif 147 | 148 | #ifndef ECANCELED 149 | #define ECANCELED 125 150 | #endif 151 | 152 | #ifndef EOWNERDEAD 153 | #define EOWNERDEAD 130 154 | #endif 155 | 156 | #ifndef ENOTRECOVERABLE 157 | #define ENOTRECOVERABLE 131 158 | #endif 159 | 160 | #ifndef ERFKILL 161 | #define ERFKILL 132 162 | #endif 163 | 164 | #ifndef EHWPOISON 165 | #define EHWPOISON 133 166 | #endif 167 | -------------------------------------------------------------------------------- /src/stdlib-file/fmt.c: -------------------------------------------------------------------------------- 1 | 2 | static int print_string(char *str) { 3 | int str_len = 0; 4 | while(str[str_len] != 0) { 5 | str_len += 1; 6 | } 7 | u64 unused; 8 | _RT_Status status = _rt_file_write(&stdout->rt_file, str_len, str, &unused); 9 | if(status != _RT_STATUS_OK) { 10 | return -1; 11 | }; 12 | return str_len; 13 | } 14 | static int print_int(i64 number) { 15 | bool negative = (number < 0); 16 | if(negative) { 17 | number = -number; 18 | } 19 | char buf[20]; 20 | buf[sizeof buf - 1] = 0; 21 | char *p = buf + sizeof buf - 1; 22 | do { 23 | *--p = (number%10) + '0'; 24 | number /= 10; 25 | } while(number > 0); 26 | if(negative) { 27 | *--p = '-'; 28 | } 29 | u64 unused; 30 | int buf_len = (int)(&buf[0] + sizeof buf - p); 31 | _RT_Status status = _rt_file_write(&stdout->rt_file, buf_len, p, &unused); 32 | if(status != _RT_STATUS_OK) { 33 | return -1; 34 | } 35 | return buf_len; 36 | } 37 | 38 | static int print_uint(u64 number) { 39 | char buf[20]; 40 | buf[sizeof buf - 1] = 0; 41 | char *p = buf + sizeof buf - 1; 42 | do { 43 | *--p = (number%10) + '0'; 44 | number /= 10; 45 | } while(number > 0); 46 | u64 unused; 47 | int buf_len = (int)(&buf[0] + sizeof buf - p); 48 | _RT_Status status = _rt_file_write(&stdout->rt_file, buf_len, p, &unused); 49 | if(status != _RT_STATUS_OK) { 50 | return -1; 51 | } 52 | return buf_len; 53 | } 54 | static int print_hex(u64 number) { 55 | char digits[] = "0123456789abcdef"; 56 | char buf[20]; 57 | buf[sizeof buf - 1] = 0; 58 | char *p = buf + sizeof buf - 1; 59 | for(int i = 0; i < 64; i += 4) { 60 | // if(i != 0 && i % 16 == 0) { 61 | // *--p = '_'; 62 | // } 63 | u8 bits = (number >> i) & 0x0f; 64 | char digit = digits[bits]; 65 | *--p = digit; 66 | } 67 | *--p = 'x'; 68 | *--p = '0'; 69 | u64 unused; 70 | int buf_len = (int)(&buf[0] + sizeof buf - p); 71 | _RT_Status status = _rt_file_write(&stdout->rt_file, buf_len, p, &unused); 72 | if(status != _RT_STATUS_OK) { 73 | return -1; 74 | } 75 | return buf_len; 76 | } 77 | 78 | int printf(const char *restrict fmt, ...) { 79 | i64 ret_printed = 0; 80 | va_list args; 81 | va_start(args, fmt); 82 | i64 buf_start_idx = 0; 83 | i64 buf_end_idx = 0; 84 | u64 unused; 85 | cia_mutex_lock(&stdout->mutex); 86 | for(i64 i = 0; fmt[i] != 0;) { 87 | buf_start_idx = i; 88 | buf_end_idx = i; 89 | while(fmt[i] != '%' && fmt[i] != 0) { 90 | buf_end_idx += 1; 91 | i += 1; 92 | } 93 | i64 buf_size = buf_end_idx - buf_start_idx; 94 | if(buf_size != 0) { 95 | _RT_Status status = _rt_file_write( 96 | &stdout->rt_file 97 | , buf_size 98 | , (void *)&fmt[buf_start_idx] 99 | , &unused 100 | ); 101 | if(status != _RT_STATUS_OK) { 102 | goto _error; 103 | } 104 | ret_printed += buf_size; 105 | } 106 | if(fmt[i] == 0) { 107 | break; 108 | } 109 | // fmt[i] == '%' 110 | i += 1; 111 | // Check int sizes 112 | int int_arg_size = 32; 113 | if(fmt[i] == 'I') { 114 | if(fmt[i+1] == '3' && fmt[i+2] == '2') { 115 | int_arg_size = 32; 116 | } 117 | else if(fmt[i+1] == '6' && fmt[i+2] == '4') { 118 | int_arg_size = 64; 119 | } 120 | else { 121 | goto _error; 122 | } 123 | i += 3; 124 | } 125 | int arg_chars; 126 | if(fmt[i] == 'd') { 127 | i64 arg; 128 | if(int_arg_size == 32) { 129 | arg = (i64)va_arg(args, i32); 130 | } 131 | else if(int_arg_size == 64) { 132 | arg = va_arg(args, i64); 133 | } 134 | else { 135 | goto _error; 136 | } 137 | arg_chars = print_int(arg); 138 | 139 | } 140 | else if(fmt[i] == 'u') { 141 | u64 arg; 142 | if(int_arg_size == 32) { 143 | arg = va_arg(args, u32); 144 | } 145 | else if(int_arg_size == 64) { 146 | arg = va_arg(args, u64); 147 | } 148 | arg_chars = print_uint(arg); 149 | } 150 | else if(fmt[i] == 'x') { 151 | u64 arg; 152 | if(int_arg_size == 32) { 153 | arg = va_arg(args, u32); 154 | } 155 | else if(int_arg_size == 64) { 156 | arg = va_arg(args, u64); 157 | } 158 | print_hex(arg); 159 | } 160 | else if(fmt[i] == 'p') { 161 | void *arg = va_arg(args, void *); 162 | arg_chars = print_hex((u64)arg); 163 | } 164 | else if(fmt[i] == 's') { 165 | char *str = va_arg(args, char *); 166 | arg_chars = print_string(str); 167 | } 168 | else if(fmt[i] == 'c') { 169 | int ch = va_arg(args, int); 170 | _RT_Status status = _rt_file_write(&stdout->rt_file, 1, &ch, &unused); 171 | if(status != _RT_STATUS_OK) { 172 | goto _error; 173 | } 174 | arg_chars = 1; 175 | } 176 | i += 1; 177 | if(arg_chars < 0) { 178 | goto _error; 179 | } 180 | ret_printed += arg_chars; 181 | } 182 | cia_mutex_unlock(&stdout->mutex); 183 | va_end(args); 184 | return ret_printed; 185 | _error: 186 | cia_mutex_unlock(&stdout->mutex); 187 | va_end(args); 188 | return -1; 189 | } 190 | -------------------------------------------------------------------------------- /include/stdint.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | static_assert(sizeof(char) == 1, "Char isn't 1 bytes long"); 7 | static_assert(sizeof(short) == 2, "Short isn't 2 bytes long"); 8 | static_assert(sizeof(int) == 4, "Int isn't 4 bytes long"); 9 | static_assert(sizeof(long long int) == 8, "Long long isn't 8 bytes long"); 10 | #if defined(CIA_DATA_LP64) 11 | static_assert(sizeof(long) == 8, "Long on linux isn't 8 bytes"); 12 | #elif defined(CIA_DATA_LLP64) 13 | static_assert(sizeof(long) == 4, "Long on windows isn't 4 bytes"); 14 | #else 15 | #error "Data model not implemented" 16 | #endif 17 | 18 | typedef signed char int8_t; 19 | typedef unsigned char uint8_t; 20 | typedef signed short int16_t; 21 | typedef unsigned short uint16_t; 22 | typedef signed int int32_t; 23 | typedef unsigned int uint32_t; 24 | #if defined(CIA_DATA_LP64) 25 | typedef signed long int64_t; 26 | typedef unsigned long uint64_t; 27 | #elif defined(CIA_DATA_LLP64) 28 | typedef signed long long int64_t; 29 | typedef unsigned long long uint64_t; 30 | #else 31 | #error "Data model not implemented" 32 | #endif 33 | 34 | typedef int8_t int_fast8_t, int_least8_t; 35 | typedef int16_t int_fast16_t, int_least16_t; 36 | typedef int32_t int_fast32_t, int_least32_t; 37 | typedef int64_t int_fast64_t, int_least64_t; 38 | typedef uint8_t uint_fast8_t, uint_least8_t; 39 | typedef uint16_t uint_fast16_t, uint_least16_t; 40 | typedef uint32_t uint_fast32_t, uint_least32_t; 41 | typedef uint64_t uint_fast64_t, uint_least64_t; 42 | 43 | // TODO: verify what size it is (on windows and linux) 44 | typedef int64_t intmax_t; 45 | typedef int64_t intptr_t; 46 | typedef uint64_t uintmax_t; 47 | typedef uint64_t uintptr_t; 48 | 49 | // Constant expandors 50 | #define INT8_C(n) (n) 51 | #define INT16_C(n) (n) 52 | #define INT32_C(n) (n) 53 | #define UINT8_C(n) (n) 54 | #define UINT16_C(n) (n) 55 | #define UINT32_C(n) (n) 56 | 57 | #if defined(CIA_DATA_LP64) 58 | #define INT64_C(n) (n ## L) 59 | #define INTMAX_C(n) (n ## L) 60 | #define UINT64_C(n) (n ## UL) 61 | #define UINTMAX_C(n) (n ## UL) 62 | #elif defined(CIA_DATA_LLP64) 63 | #define INT64_C(n) (n ## LL) 64 | #define INTMAX_C(n) (n ## LL) 65 | #define UINT64_C(n) (n ## ULL) 66 | #define UINTMAX_C(n) (n ## ULL) 67 | #else 68 | #error "Data model not defined" 69 | #endif 70 | 71 | #define INT8_WIDTH 8 72 | #define INT16_WIDTH 16 73 | #define INT32_WIDTH 32 74 | #define INT64_WIDTH 64 75 | #define UINT8_WIDTH 8 76 | #define UINT16_WIDTH 16 77 | #define UINT32_WIDTH 32 78 | #define UINT64_WIDTH 64 79 | #define INT_FAST8_WIDTH 8 80 | #define INT_FAST16_WIDTH 16 81 | #define INT_FAST32_WIDTH 32 82 | #define INT_FAST64_WIDTH 64 83 | #define UINT_FAST8_WIDTH 8 84 | #define UINT_FAST16_WIDTH 16 85 | #define UINT_FAST32_WIDTH 32 86 | #define UINT_FAST64_WIDTH 64 87 | #define INT_LEAST8_WIDTH 8 88 | #define INT_LEAST16_WIDTH 16 89 | #define INT_LEAST32_WIDTH 32 90 | #define INT_LEAST64_WIDTH 64 91 | #define UINT_LEAST8_WIDTH 8 92 | #define UINT_LEAST16_WIDTH 16 93 | #define UINT_LEAST32_WIDTH 32 94 | #define UINT_LEAST64_WIDTH 64 95 | #define INTPTR_WIDTH 64 96 | #define INTMAX_WIDTH 64 97 | #define UINTPTR_WIDTH 64 98 | #define UINTMAX_WIDTH 64 99 | 100 | // Temporary defines 101 | #define _s8_min -0x80 102 | #define _s8_max 0x7f 103 | #define _u8_max 0xff 104 | #define _s16_min -0x8000 105 | #define _s16_max 0x7fff 106 | #define _u16_max 0xffff 107 | #define _s32_min -0x80000000 108 | #define _s32_max 0x7fffffff 109 | #define _u32_max 0xffffffff 110 | #define _s64_min INT64_C(-0x8000000000000000) 111 | #define _s64_max INT64_C(0x7fffffffffffffff) 112 | #define _u64_max UINT64_C(0xffffffffffffffff) 113 | 114 | // Min/max for all integer types 115 | #define INT8_MIN _s8_min 116 | #define INT_FAST8_MIN _s8_min 117 | #define INT_LEAST8_MIN _s8_min 118 | #define INT16_MIN _s16_min 119 | #define INT_FAST16_MIN _s16_min 120 | #define INT_LEAST16_MIN _s16_min 121 | #define INT32_MIN _s32_min 122 | #define INT_FAST32_MIN _s32_min 123 | #define INT_LEAST32_MIN _s32_min 124 | #define INT64_MIN _s64_min 125 | #define INT_FAST64_MIN _s64_min 126 | #define INT_LEAST64_MIN _s64_min 127 | #define INTPTR_MIN _s64_min 128 | #define INTMAX_MIN _s64_min 129 | 130 | #define INT8_MAX _s8_max 131 | #define INT_FAST8_MAX _s8_max 132 | #define INT_LEAST8_MAX _s8_max 133 | #define INT16_MAX _s16_max 134 | #define INT_FAST16_MAX _s16_max 135 | #define INT_LEAST16_MAX _s16_max 136 | #define INT32_MAX _s32_max 137 | #define INT_FAST32_MAX _s32_max 138 | #define INT_LEAST32_MAX _s32_max 139 | #define INT64_MAX _s64_max 140 | #define INT_FAST64_MAX _s64_max 141 | #define INT_LEAST64_MAX _s64_max 142 | #define INTPTR_MAX _s64_max 143 | #define INTMAX_MAX _s64_max 144 | 145 | #define UINT8_MAX _u8_max 146 | #define UINT_FAST8_MAX _u8_max 147 | #define UINT_LEAST8_MAX _u8_max 148 | #define UINT16_MAX _u16_max 149 | #define UINT_FAST16_MAX _u16_max 150 | #define UINT_LEAST16_MAX _u16_max 151 | #define UINT32_MAX _u32_max 152 | #define UINT_FAST32_MAX _u32_max 153 | #define UINT_LEAST32_MAX _u32_max 154 | #define UINT64_MAX _u64_max 155 | #define UINT_FAST64_MAX _u64_max 156 | #define UINT_LEAST64_MAX _u64_max 157 | #define UINTPTR_MAX _u64_max 158 | #define UINTMAX_MAX _u64_max 159 | 160 | // Undo temporary defines 161 | #undef _s8_max 162 | #undef _s8_min 163 | #undef _u8_max 164 | #undef _s16_max 165 | #undef _s16_min 166 | #undef _u16_max 167 | #undef _s32_max 168 | #undef _s32_min 169 | #undef _u32_max 170 | #undef _s64_max 171 | #undef _s64_min 172 | #undef _u64_max -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | # Ciabatta 3 | 4 | ![Linux](https://github.com/flysand7/ciabatta/actions/workflows/build-linux.yml/badge.svg?event=push) 5 | ![Windows](https://github.com/flysand7/ciabatta/actions/workflows/build-windows.yml/badge.svg?event=push) 6 | 7 | Ciabatta - An implementation of cross-platform C standard library with the 8 | following goals: 9 | 10 | - Providing C standard library that fully implements all C features. Some 11 | standard libraries lack many features of C11 and C23, like threads.h or 12 | aligned_alloc in case of MSVCRT. 13 | - Making standard library that is easy to port to other platforms, for example 14 | an embedded platform or a custom operating system. 15 | - Allowing applications to debug and step into standard library functions 16 | (Hello MSVCRT!) 17 | - Reasonably fast CRT compared to MSVCRT and glibc, e.g. making malloc use 18 | a faster allocator, avoid runtime checks where possible, heavely rely on 19 | inlining. 20 | - Extend the possibilities of C standard library with commonly used 21 | functionality: implementing POSIX standard, capability for unicode 22 | processing, API to traverse directories, hash functions, better strings API, 23 | crash handlers. 24 | 25 | Ciabatta is not binary-compatible with other CRT libraries. That means that any 26 | libraries that your project uses have to also be compiled with Ciabatta, 27 | otherwise you will run into issues. 28 | 29 | Please note that as of today ciabatta is still during development and does not 30 | implement many of the features that need to be implemented. Using it at current 31 | time is discouraged. 32 | 33 | ## Current Status 34 | 35 | ### C23 standard library 36 | 37 | | Header | Description | Status | 38 | | --------------- | ------------------------------------ | ----------- | 39 | | | Diagnostics. | none | 40 | | | Complex arithmetic. | none | 41 | | | Character handling. | none | 42 | | | Errors. | Implemented | 43 | | | Floating-point environment. | none | 44 | | | Characteristics of floating types. | none | 45 | | | Format conversion of integer types. | none | 46 | | | Alternative spellings. | none | 47 | | | Sizes of integer types. | Implemented | 48 | | | Localization. | none | 49 | | | Mathematics. | none | 50 | | | Nonlocal jumps. | [1] | 51 | | | Signal handling. | none | 52 | | | Alignment. | none | 53 | | | Variable arguments. | none | 54 | | | Atomics. | [1] | 55 | | | Bit and byte utilities | none | 56 | | | Boolean type and values. | none | 57 | | | Common definitions. | none | 58 | | | Integer types. | Implemented | 59 | | | Input/output. | Partial | 60 | | | General utilities. | none | 61 | | | `_Noreturn`. | none | 62 | | | String handling. | Partial | 63 | | | Type-generic math. | none | 64 | | | Threads. | Partial | 65 | | | Date and time. | none | 66 | | | Unicode utilities. | none | 67 | | | Wide character utilities. | none | 68 | | | Wide character utilities. | none | 69 | 70 | [1] Implemented by compilers 71 | 72 | ## Support 73 | 74 | Operating System: 75 | - Windows 76 | - Linux 77 | 78 | Processor Architecture: 79 | - x86-64 80 | 81 | This library is supposed to be extensible to other platforms, meaning that 82 | you can write an OS layer for another OS and use the rest of the CRT 83 | functionality. 84 | 85 | ## Building ciabatta 86 | 87 | Before proceeding please note that ciabatta can only be compiled and used 88 | with `clang` and `cuik`. It may be able to work with `gcc` with some minor adjustments 89 | but I never tested it. 90 | 91 | You can get `cuik` in [the GitHub repository](https://github.com/RealNeGate/Cuik) 92 | 93 | On linux you can simply run `./build.py` script. On windows can run 94 | it with `py build.py` command. 95 | 96 | The script accepts some command-line arguments, which you can check by running 97 | 98 | ``` 99 | $ ./build.py -h 100 | ``` 101 | 102 | ## Usage 103 | 104 | Grab the following files into your project's (or any other) directory: 105 | 106 | - The `./include` folder 107 | - The `./lib` folder 108 | - (Windows only) The `./utf8` folder 109 | 110 | In order to compile your project with ciabatta see the following sections, 111 | assuming you put all files mentioned above in the `./ciabatta` folder 112 | 113 | ### Compiling with ciabatta on windows 114 | 115 | 1. Add the following flags to your compilation command: 116 | `-nostdlib -I ./ciabatta/include utf8.obj -mfma` 117 | 2. Add the following sources to the compile command: 118 | `./ciabatta/lib/cia.lib` 119 | 120 | **Note:** The `include` folder refers to the folder you copied from ciabatta. Set the path to it accordingly. 121 | 122 | ### Compiling with ciabatta on linux 123 | 124 | 1. Add the following flags to your compilation command: 125 | - `-nostdlib -I ./ciabatta/include -mfma` 126 | 2. Link to the following libraries 127 | - `./ciabatta/lib/cia.a` 128 | 3. Specify the ciabatta dynamic loader in linker options 129 | - `-Wl,-dynamic-linker,lib/ld-cia.so` 130 | 131 | ## Contributing 132 | 133 | Pull requests welcome and accepted in any form. 134 | 135 | ## License 136 | 137 | See [the license file](license) 138 | -------------------------------------------------------------------------------- /os/linux/tinyrt-threads.c: -------------------------------------------------------------------------------- 1 | 2 | static _LD_Thread_Block *thread_blocks_head = NULL; 3 | 4 | extern i64 _rt_thread_start( 5 | u64 flags, 6 | void *stack_base, 7 | int *parent_tid, 8 | int *child_tid, 9 | void *tls, 10 | int (*thread_fn)(void *ctx), 11 | void *ctx 12 | ); 13 | 14 | static void thread_sigcancel_handler(int sig, siginfo_t *info, void *ucontext) { 15 | _LD_Thread_Block *tcb = (void *)((u64)__builtin_frame_address(0) & ~(cia_stack_size - 1)); 16 | u32 is_cancelled = atomic_load_explicit(&tcb->is_cancelled, memory_order_acquire); 17 | if(is_cancelled) { 18 | u32 tgid = sys_getpid(); 19 | sys_exit(0); 20 | } 21 | } 22 | 23 | static void _rt_threads_setup() { 24 | u64 sigs[3] = {(1ul << SIGCANCEL)}; 25 | struct sigaction handler = { 26 | .sa_sigaction = thread_sigcancel_handler, 27 | .sa_flags = SA_SIGINFO|SA_RESTART, 28 | .sa_mask = 0xfffffffc7ffffffful, 29 | }; 30 | syscall(SYS_rt_sigaction, SIGCANCEL, &handler, NULL, 1 * sizeof(u64)); 31 | } 32 | 33 | static _RT_Status _rt_thread_current(_RT_Thread *thread) { 34 | thread->handle = (void *)((u64)__builtin_frame_address(0) & ~(cia_stack_size - 1)); 35 | return _RT_STATUS_OK; 36 | } 37 | 38 | static _RT_Status _rt_thread_create(_RT_Thread *thread, int (*thread_fn)(void *ctx), void *ctx) { 39 | // Create the memory for stack 40 | u64 mmap_prot = PROT_READ|PROT_WRITE; 41 | u64 mmap_flags = MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE; 42 | void *stack_base = sys_mmap(0, 2*cia_stack_size, mmap_prot, mmap_flags, -1, 0); 43 | if((i64)stack_base < 0) { 44 | return _RT_ERROR_GENERIC; 45 | } 46 | void *stack = (u8*)stack_base + 2*cia_stack_size; 47 | // Find the TCB base and initialize the TCB 48 | _LD_Thread_Block *tcb = (void *)((u64)((u8 *)stack - 1) & ~(cia_stack_size - 1)); 49 | u8 *tls_base = (u8 *)tcb - cia_tls_image_size; 50 | for(int i = 0; i < cia_tls_image_size; ++i) { 51 | tls_base[i] = ((u8 *)cia_tls_image_base)[i]; 52 | } 53 | tcb->stack_canary = 0x12345678deadbeef; 54 | tcb->next_tcb = NULL; 55 | tcb->prev_tcb = thread_blocks_head; 56 | atomic_store_explicit(&tcb->is_cancelled, 0, memory_order_relaxed); 57 | if(thread_blocks_head != NULL) { 58 | thread_blocks_head->next_tcb = tcb; 59 | } 60 | thread_blocks_head = tcb; 61 | // This futex is reset on thread finish 62 | tcb->state_finish = 1; 63 | // Initialize the _RT_Thread handle, which would point to the TCB 64 | thread->handle = tcb; 65 | // Create the new thread 66 | u64 flags = 0; 67 | flags |= CLONE_CHILD_CLEARTID; 68 | flags |= CLONE_PARENT_SETTID; 69 | flags |= CLONE_FS; 70 | flags |= CLONE_FILES; 71 | flags |= CLONE_SIGHAND; 72 | flags |= CLONE_THREAD; 73 | flags |= CLONE_VM; 74 | flags |= CLONE_SYSVSEM; 75 | i64 ret = _rt_thread_start(flags, stack, &tcb->thread_id, &tcb->state_finish, 0, thread_fn, ctx); 76 | if(ret < 0) { 77 | return _RT_ERROR_GENERIC; 78 | } 79 | return _RT_STATUS_OK; 80 | } 81 | 82 | int _rt_thread_setup(int (*thread_fn)(void *ctx), void *ctx) { 83 | // struct sigaction handler = { 84 | // .sa_sigaction = thread_sigcancel_handler, 85 | // .sa_flags = SA_SIGINFO|SA_RESTART, 86 | // .sa_mask = 0, 87 | // }; 88 | // i32 result = sys_sigaction(SIGCANCEL, &handler, NULL); 89 | return thread_fn(ctx); 90 | } 91 | 92 | void _rt_thread_finish(int exit_code) { 93 | _LD_Thread_Block *tcb = (void *)((u64)__builtin_frame_address(0) & ~(cia_stack_size - 1)); 94 | // Wait until the main thread decides what to do with the child thread 95 | u32 thread_state = atomic_load_explicit(&tcb->state_detach, memory_order_relaxed); 96 | while(thread_state == _LD_THREAD_STATE_NOT_YET) { 97 | syscall(SYS_futex, &tcb->state_detach, FUTEX_WAIT, _LD_THREAD_STATE_NOT_YET, NULL, 0, 0); 98 | thread_state = atomic_load_explicit(&tcb->state_detach, memory_order_relaxed); 99 | } 100 | if(_LD_THREAD_STATE_DETACHED) { 101 | // TODO: clean up the thread resources 102 | } 103 | tcb->exit_code = exit_code; 104 | sys_exit(exit_code); 105 | } 106 | 107 | static _RT_Status _rt_thread_join(_RT_Thread *thread, int *out_exit_code) { 108 | _LD_Thread_Block *tcb = thread->handle; 109 | // Signal the thread that we want it to be joined 110 | atomic_store_explicit(&tcb->state_detach, _LD_THREAD_STATE_JOINED, memory_order_relaxed); 111 | syscall(SYS_futex, &tcb->state_detach, FUTEX_WAKE, 0, NULL, 0, 0); 112 | // Wait until the thread signals that it has completed the execution 113 | while(tcb->state_finish != 0) { 114 | syscall(SYS_futex, &tcb->state_finish, FUTEX_WAIT, 0, NULL, 0, 0); 115 | } 116 | // Set the exit code 117 | // NOTE(bumbread): this is not a bug, because calling thrd_detach from one thread 118 | // and thrd_join on the same thrd_t, from a different thread is supposed to be UB. 119 | *out_exit_code = tcb->exit_code; 120 | // TODO(bumbread): thread cleanup: destroy the TCB and thread-local storage 121 | return _RT_STATUS_OK; 122 | } 123 | 124 | static _RT_Status _rt_thread_detach(_RT_Thread *thread) { 125 | _LD_Thread_Block *tcb = thread->handle; 126 | atomic_store_explicit(&tcb->state_detach, _LD_THREAD_STATE_DETACHED, memory_order_relaxed); 127 | return _RT_STATUS_OK; 128 | } 129 | 130 | static _RT_Status _rt_thread_yield() { 131 | i64 status = syscall(SYS_sched_yield); 132 | if(status != 0) { 133 | // shouldn't happen on linux 134 | return _RT_ERROR_GENERIC; 135 | } 136 | return _RT_STATUS_OK; 137 | } 138 | 139 | static _RT_Status _rt_thread_terminate(_RT_Thread *thread) { 140 | u32 tgid = sys_getpid(); 141 | _LD_Thread_Block *tcb = thread->handle; 142 | atomic_store_explicit(&tcb->is_cancelled, 1, memory_order_release); 143 | sys_tkill(tcb->thread_id, SIGCANCEL); 144 | // syscall(SYS_rt_tgsigqueueinfo, tgid, tcb->thread_id, SIGCANCEL, NULL); 145 | return _RT_STATUS_OK; 146 | } 147 | 148 | static _RT_Status _rt_thread_sleep(u64 time) { 149 | return _RT_ERROR_NOT_IMPLEMENTED; 150 | } 151 | 152 | static _RT_Status _rt_thread_get_timer_freq(u64 *freq) { 153 | return _RT_ERROR_NOT_IMPLEMENTED; 154 | } 155 | 156 | static _RT_Status _rt_thread_cancell_all_running() { 157 | u32 tgid = sys_getpid(); 158 | _LD_Thread_Block *tcb_cur = thread_blocks_head; 159 | while(tcb_cur != NULL) { 160 | _LD_Thread_Block *tcb_next = tcb_cur->next_tcb; 161 | u32 thread_id = tcb_cur->thread_id; 162 | atomic_store_explicit(&tcb_cur->is_cancelled, 1, memory_order_release); 163 | //sys_tgkill(tgid, thread_id, SIGCANCEL); 164 | //SYS_rt_tgsigqueueinfo(tgid) 165 | tcb_cur = tcb_next; 166 | } 167 | return _RT_STATUS_OK; 168 | } 169 | -------------------------------------------------------------------------------- /loader/stack.c: -------------------------------------------------------------------------------- 1 | 2 | #define VM_READ 0x00000001 3 | #define VM_WRITE 0x00000002 4 | #define VM_EXEC 0x00000004 5 | #define VM_SHARED 0x00000008 6 | 7 | struct File_Buffer typedef File_Buffer; 8 | struct File_Buffer { 9 | int fd; 10 | char *data; 11 | u64 data_size; 12 | u64 last_read_size; 13 | u64 offset; 14 | int last_char; 15 | }; 16 | 17 | struct Stack_Info typedef Stack_Info; 18 | struct Stack_Info { 19 | bool stack_found; 20 | u64 start_addr; 21 | u64 end_addr; 22 | u32 flags; 23 | }; 24 | 25 | static Stack_Info stack_info; 26 | 27 | static int read_char(File_Buffer *buffer) { 28 | // If we need to read more stuff, fetch it from the file 29 | if(buffer->offset >= buffer->last_read_size) { 30 | int result = sys_read(buffer->fd, buffer->data, buffer->data_size); 31 | if(result < 0) { 32 | _dbg_printf("result < 0"); 33 | return -1; 34 | } 35 | if(result == 0) { 36 | buffer->last_char = -1; 37 | return buffer->last_char; 38 | } 39 | int read_size = result; 40 | buffer->data[read_size] = 0; 41 | buffer->last_read_size = read_size; 42 | buffer->offset = 0; 43 | } 44 | // Return the character from a buffer 45 | u64 cur_offset = buffer->offset; 46 | buffer->offset += 1; 47 | buffer->last_char = buffer->data[cur_offset]; 48 | _dbg_printf("%c", buffer->last_char); 49 | return buffer->last_char; 50 | } 51 | 52 | static int char_is_hex(int ch) { 53 | if('0' <= ch && ch <= '9') return 1; 54 | if('a' <= ch && ch <= 'f') return 1; 55 | if('A' <= ch && ch <= 'F') return 1; 56 | return 0; 57 | } 58 | 59 | static int char_to_hex(int ch) { 60 | if(ch <= '9') { 61 | return ch - '0'; 62 | } 63 | return ch - 'a' + 10; 64 | } 65 | 66 | static int read_hex(File_Buffer *buffer, u64 *out_result) { 67 | u64 result = 0; 68 | int n_digits = 0; 69 | for(;;) { 70 | int ch = buffer->last_char; 71 | if(!char_is_hex(ch)) { 72 | break; 73 | } 74 | result *= 16; 75 | result += char_to_hex(ch); 76 | read_char(buffer); 77 | n_digits += 1; 78 | } 79 | *out_result = result; 80 | if(n_digits == 0) { 81 | return -1; 82 | } 83 | return 0; 84 | } 85 | 86 | static int read_dec(File_Buffer *buffer, u64 *out_result) { 87 | u64 result = 0; 88 | int n_digits = 0; 89 | for(;;) { 90 | int ch = buffer->last_char; 91 | if(!('0' <= ch && ch <= '9')) { 92 | break; 93 | } 94 | result *= 10; 95 | result += ch - '0'; 96 | read_char(buffer); 97 | n_digits += 1; 98 | } 99 | *out_result = result; 100 | if(n_digits == 0) { 101 | return -1; 102 | } 103 | return 0; 104 | } 105 | 106 | static int linux_read_stack_info() { 107 | bool stack_found = false; 108 | // Initialize the buffer for buffered read 109 | char line_buf[1024]; 110 | File_Buffer buffer; 111 | buffer.data = line_buf; 112 | buffer.data_size = sizeof line_buf; 113 | buffer.last_read_size = 0; 114 | buffer.offset = 0; 115 | // Open the file 116 | buffer.fd = (i32)(u32)sys_open("/proc/self/maps", 0, O_RDONLY); 117 | _dbg_printf("/proc/self/maps fd: %d\n", (i64)(i32)buffer.fd); 118 | if((i64)(i32)buffer.fd < 0) { 119 | return -1; 120 | } 121 | // Read the first character 122 | if(read_char(&buffer) < 0) { 123 | _dbg_printf("\nERROR: (/proc/self/maps) Failed reading char at offset %x\n", buffer.offset); 124 | return -1; 125 | } 126 | // Start reading the lines until we hit the stack 127 | char desired_name[] = "[stack]"; 128 | while(!stack_found && buffer.last_char != -1) { 129 | // If we're doing n-th iteration, consume the newline 130 | if(buffer.last_char == '\n') { 131 | read_char(&buffer); 132 | } 133 | // Read the start and end addr of the section 134 | u64 start_addr = 0; 135 | u64 end_addr = 0; 136 | if(read_hex(&buffer, &start_addr)) { 137 | _dbg_printf("|\nERROR: read_hex failed to read start_addr\n"); 138 | return -1; 139 | } 140 | if(buffer.last_char != '-') { 141 | _dbg_printf("|\nERROR: expected '-', didn't see it\n"); 142 | return -1; 143 | } 144 | if(read_char(&buffer) < 0) { 145 | _dbg_printf("|\nERROR: read_char failed after saw '-'\n"); 146 | return -1; 147 | } 148 | if(read_hex(&buffer, &end_addr) < 0) { 149 | _dbg_printf("|\nERROR: read_hex failed to read end_addr\n"); 150 | return -1; 151 | } 152 | // Skip whitespace 153 | if(read_char(&buffer) < 0) { 154 | _dbg_printf("|\nERROR: read_char failed skipping whitespace after addrs\n"); 155 | return -1; 156 | } 157 | // Read the flags 158 | u32 flags = 0; 159 | if(buffer.last_char == 'r') { 160 | flags |= VM_READ; 161 | } 162 | read_char(&buffer); 163 | if(buffer.last_char == 'w') { 164 | flags |= VM_WRITE; 165 | } 166 | read_char(&buffer); 167 | if(buffer.last_char == 'x') { 168 | flags |= VM_EXEC; 169 | } 170 | read_char(&buffer); 171 | if(buffer.last_char == 's') { 172 | flags |= VM_SHARED; 173 | } 174 | read_char(&buffer); 175 | // Skip 15 characters corresponding to `offset` and `device` fields 176 | for(int i = 0; i != 16; ++i) { 177 | read_char(&buffer); 178 | } 179 | // Read `inode` field 180 | u64 inode = 0; 181 | if(read_dec(&buffer, &inode)) { 182 | _dbg_printf("|\nERROR reading inode field: %c\n", buffer.last_char); 183 | return -1; 184 | } 185 | // If the line terminates here, skip this line 186 | if(buffer.last_char == '\n' || buffer.last_char == -1) { 187 | continue; 188 | } 189 | // Skip whitespace 190 | while(buffer.last_char == ' ') { 191 | read_char(&buffer); 192 | } 193 | // Read the name of the mapping 194 | char name_buf[256]; 195 | u64 name_buf_size = sizeof name_buf; 196 | int name_len = 0; 197 | while(name_len < name_buf_size && buffer.last_char != '\n' && buffer.last_char != -1) 198 | { 199 | name_buf[name_len] = buffer.last_char; 200 | read_char(&buffer); 201 | ++name_len; 202 | } 203 | name_buf[name_len] = 0; 204 | // If the name is '[stack]' we pass the check and save the info 205 | if(name_len != 7) { 206 | continue; 207 | } 208 | for(int i = 0; i < 7; ++i) { 209 | if(name_buf[i] != desired_name[i]) { 210 | continue; 211 | } 212 | } 213 | // We found the stack! 214 | stack_info.stack_found = true; 215 | stack_info.start_addr = start_addr; 216 | stack_info.end_addr = end_addr; 217 | stack_info.flags = flags; 218 | sys_close(buffer.fd); 219 | _dbg_printf("\nFound stack: %x-%x\n", start_addr, end_addr); 220 | return 0; 221 | } 222 | sys_close(buffer.fd); 223 | return 1; 224 | } 225 | -------------------------------------------------------------------------------- /loader/loader-self-reloc.c: -------------------------------------------------------------------------------- 1 | 2 | // Stage 2 of the dynamic loader 3 | // the purpose of this module is to relocate itself 4 | // and jump to the main body of the loader. 5 | 6 | // Note that loader-entry.asm doesn't "jump" into 7 | // the entry point of this module, but rather 8 | // "falls-through". Which means the sections 9 | // of this module and the module above must be 10 | // contiguous, which we do by doing linker magic 11 | 12 | // This also means that this module CANNOT have 13 | // any externally-defined functions (static functions 14 | // are fine with gcc and clang (I think)) 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "loader.h" 26 | 27 | extern void ld_stage2_entry(Loader_Info *ld_info); 28 | 29 | void ld_stage1_entry(u64 *sp, Elf64_Dyn *dynv) { 30 | _dbg_print_string("Entered dynamic loader\n"); 31 | // Find argc, argv in stack 32 | int argc = *sp; 33 | char **argv = (void *)(sp+1); 34 | _dbg_printf("ARGV:\n"); 35 | for(int i = 0; i < argc; ++i) { 36 | _dbg_printf("[%d]: %s\n", (i64)i, argv[i]); 37 | } 38 | // Skip over environment 39 | char **envp = argv+argc+1; 40 | int envc = 0; 41 | for(int i = 0; envp[i]; i += 1) { 42 | envc += 1; 43 | } 44 | // Load aux vector, which is responsible 45 | // for holding information for the loader such as 46 | // the location of phdrs or its load address 47 | u64 aux[AUX_CNT]; 48 | Elf64_Aux *auxv = (Elf64_Aux *)(envp + envc + 1); 49 | for(int i = 0; i < AUX_CNT; ++i) { 50 | aux[i] = 0; 51 | } 52 | for(int i = 0; auxv[i].a_type != AT_NULL; ++i) { 53 | int aux_type = auxv[i].a_type; 54 | if(aux_type < AUX_CNT) { 55 | aux[aux_type] = auxv[i].a_val; 56 | } 57 | } 58 | // Read the _DYNAMIC vector 59 | u64 dyn[DYN_CNT]; 60 | for(int i = 0; i < DYN_CNT; ++i) { 61 | dyn[i] = 0; 62 | } 63 | _dbg_printf("Dynamic section contents:\n"); 64 | for(int i = 0; dynv[i].d_tag != DT_NULL; ++i) { 65 | u64 dyn_tag = dynv[i].d_tag; 66 | _dbg_printf(" %x: %x\n", dyn_tag, dynv[i].d_un.d_val); 67 | if(dyn_tag < DYN_CNT) { 68 | dyn[dyn_tag] = dynv[i].d_un.d_val; 69 | } 70 | } 71 | // Find the dynamic section 72 | if(dynv == NULL) { 73 | _dbg_printf("_DYNAMIC section wasn't found in dynamic loader\n"); 74 | } 75 | // If the dynamic linker is not invoked as a command 76 | // It's load address can't be found in the aux vector 77 | // Therefore we compute the base as the difference 78 | // between &_DYNAMIC and it's p_vaddr 79 | u8 *base = (void *)aux[AT_BASE]; 80 | if(base == NULL) { 81 | _dbg_printf("trying to find base\n"); 82 | u8 *phdrs = (void *)aux[AT_PHDR]; 83 | u64 ph_ent = aux[AT_PHENT]; 84 | u64 ph_num = aux[AT_PHNUM]; 85 | for(int i = 1; i < ph_num; ++i) { 86 | u64 ph_off = i * ph_ent; 87 | Elf64_Phdr *ph = (void *)(phdrs + ph_off); 88 | if(ph->p_type == PT_DYNAMIC) { 89 | _dbg_printf("_DYNAMIC vaddr: %x\n", ph->p_vaddr); 90 | base = (void *)(dynv - ph->p_vaddr); 91 | } 92 | } 93 | } 94 | _dbg_printf("ld-cia.so base: %x\n", base); 95 | _dbg_printf("ld-cia.so _dynamic: %x\n", dynv); 96 | Elf64_Sym *symtab = symtab = (void *)(base + dyn[DT_SYMTAB]); 97 | if(symtab == NULL) { 98 | _dbg_printf("ERROR: No .dynsym found\n"); 99 | } 100 | // Find the string table 101 | char *strtab = (void *)(base + dyn[DT_STRTAB]); 102 | if(dyn[DT_STRTAB] == 0) { 103 | strtab = NULL; 104 | } 105 | // Use memory fences, to MAKE SURE the compiler won't reorder code and 106 | // accidentally use relocations when they are not ready. The code before 107 | // this point is carefully written to avoid generating relocations. 108 | _mfence(); 109 | // Apply relocations 110 | if(dyn[DT_REL] != 0) { 111 | _dbg_printf("REL Relocations found. This part isn't implemented\n"); 112 | u8 *rel_ents = (void *)(base + dyn[DT_REL]); 113 | u64 rel_ent = dyn[DT_RELENT]; 114 | u64 rel_size = dyn[DT_RELSZ]; 115 | u64 rel_offs = 0; 116 | while(rel_offs < rel_size) { 117 | Elf64_Rel *rel = (void *)(rel_ents + rel_offs); 118 | u64 offs = rel->r_offset; 119 | u32 sym = ELF64_R_SYM(rel->r_info); 120 | u32 type = ELF64_R_TYPE(rel->r_info); 121 | _dbg_printf(" %d @ %d (%d)\n", sym, offs, type); 122 | // TODO: if needed 123 | rel_offs += rel_ent; 124 | } 125 | } 126 | if(dyn[DT_RELA] != 0) { 127 | _dbg_printf("RELA:\n"); 128 | u8 *rela_ents = (void *)(base + dyn[DT_RELA]); 129 | u64 rela_ent = dyn[DT_RELAENT]; 130 | u64 rela_size = dyn[DT_RELASZ]; 131 | u64 rela_offs = 0; 132 | while(rela_offs < rela_size) { 133 | Elf64_Rela *rela = (void *)(rela_ents + rela_offs); 134 | u64 reloc_offs = rela->r_offset; 135 | u64 addend = rela->r_addend; 136 | Elf64_Sym *sym = &symtab[ELF64_R_SYM(rela->r_info)]; 137 | u32 type = ELF64_R_TYPE(rela->r_info); 138 | void *sym_addr = (void *)(base + sym->st_value); 139 | void **reloc_addr = (void *)(base + reloc_offs); 140 | { 141 | u32 sym_name_offset = sym->st_name; 142 | if(sym_name_offset == 0) { 143 | _dbg_printf(" %x+%d, @%x (%d)", sym_addr, addend, reloc_offs, type); 144 | } 145 | else { 146 | char *sym_name = &strtab[sym_name_offset]; 147 | _dbg_printf(" %s+%d, @%x (%d)", sym_name, addend, reloc_offs, type); 148 | } 149 | } 150 | if(type == R_X86_64_GLOB_DAT) { 151 | *reloc_addr = sym_addr; 152 | } 153 | else if(type == R_X86_64_RELATIVE) { 154 | *reloc_addr = (void *)(base + addend); 155 | } 156 | else { 157 | printf("ERROR: unhandled relocation type: %d\n", type); 158 | sys_exit(1); 159 | } 160 | _dbg_printf(" -> %x\n", *reloc_addr); 161 | rela_offs += rela_ent; 162 | } 163 | } 164 | if(dyn[DT_PLTGOT] != 0) { 165 | _dbg_printf("PLT relocations found\n"); 166 | if(dyn[DT_PLTREL] == DT_REL) { 167 | _dbg_printf(" PLT relocations use relocations of type REL\n"); 168 | printf("ERROR: .plt relocations of type REL not implemented\n"); 169 | sys_exit(1); 170 | } 171 | else if(dyn[DT_PLTREL] == DT_RELA) { 172 | _dbg_printf(" PLT relocations use relocations of type RELA\n"); 173 | } 174 | void *plt = (void *)(base + dyn[DT_PLTGOT]); 175 | void *rela_plt = (void *)(base + dyn[DT_JMPREL]); 176 | u64 rela_ent = sizeof(Elf64_Rela); 177 | u64 rela_size = dyn[DT_PLTRELSZ]; 178 | u64 rela_offs = 0; 179 | while(rela_offs < rela_size) { 180 | Elf64_Rela *rela = (void *)(rela_plt + rela_offs); 181 | u64 reloc_offs = rela->r_offset; 182 | u64 addend = rela->r_addend; 183 | u32 sym_idx = ELF64_R_SYM(rela->r_info); 184 | u32 type = ELF64_R_TYPE(rela->r_info); 185 | _dbg_printf(" %x+%d, @%x (%d)\n", sym_idx, addend, reloc_offs, type); 186 | if(type == R_X86_64_JUMP_SLOT) { 187 | Elf64_Sym *sym = &symtab[sym_idx]; 188 | void *sym_addr = (void *)(base + sym->st_value); 189 | void **reloc_addr = (void *)(base + reloc_offs); 190 | _dbg_printf(" -> resolving with %x\n", sym_addr); 191 | *reloc_addr = sym_addr; 192 | } 193 | rela_offs += rela_ent; 194 | } 195 | } 196 | _mfence(); 197 | Loader_Info ld_info; 198 | ld_info.sp = sp; 199 | ld_info.ldso_base = base; 200 | ld_info.dyn = dyn; 201 | ld_info.aux = aux; 202 | _dbg_printf("Self-relocation finished. Entering the loader\n"); 203 | ld_stage2_entry(&ld_info); 204 | sys_exit(0); 205 | } 206 | 207 | -------------------------------------------------------------------------------- /loader/loader.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include "loader.h" 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "../os/linux/tinyrt.c" 17 | 18 | #include 19 | 20 | #include 21 | #include "../src/cia-mem/util.c" 22 | #include "../src/cia-mem/allocator.c" 23 | #include "../src/cia-mem/arena.c" 24 | #include "../src/cia-mem/pool.c" 25 | 26 | #include "stack.c" 27 | 28 | struct Elf_Image typedef Elf_Image; 29 | struct Elf_Image { 30 | Cia_Arena arena; 31 | char *name; 32 | u8 *base; 33 | u8 *phdr; 34 | u64 ph_num; 35 | u64 ph_ent; 36 | u8 *shdr; 37 | u64 sh_num; 38 | u64 sh_ent; 39 | u64 *dyn; 40 | }; 41 | 42 | #define elf_addr(elf, off) (void *)((elf)->base + (u64)off) 43 | 44 | static Cia_Pool image_pool; 45 | static Cia_Arena tmp_arena; 46 | 47 | static u32 elf_sym_gnu_hash(char *name) { 48 | unsigned char *s = (void *)name; 49 | u32 h = 5381; 50 | for(int i = 0; s[i] != 0; ++i) { 51 | char c = s[i]; 52 | h = ((h << 5) + h) + c; 53 | } 54 | return h; 55 | } 56 | 57 | static u64 elf_sym_hash(char *name) { 58 | unsigned char *s = (void *)name; 59 | u64 h = 0; 60 | u64 g; 61 | for(int i = 0; s[i] != 0; ++i) { 62 | h = (h<<4) + s[i]; 63 | g = (h & 0xf0000000); 64 | if(g) { 65 | h ^= g >> 24; 66 | } 67 | h &= 0x0fffffff; 68 | } 69 | return h; 70 | } 71 | 72 | static void elf_load(Elf_Image *image, int fd) { 73 | printf("ERROR: image loading from file not implemented\n"); 74 | sys_exit(1); 75 | } 76 | 77 | static Elf64_Sym *elf_symbol_by_name(Elf_Image *image, char *name) { 78 | Elf64_Ehdr *eh = (void *)image->base; 79 | u8 *shdr = elf_addr(image, eh->e_shoff); 80 | u64 sh_num = eh->e_shnum; 81 | u64 sh_ent = eh->e_shentsize; 82 | // Get the GNU symbol hash table 83 | Elf64_Shdr *sh_gnu_hash = NULL; 84 | for(int i = 0; i < sh_num; ++i) { 85 | u64 sh_off = i * sh_ent; 86 | Elf64_Shdr *sh = (void *)(shdr + sh_off); 87 | if(sh->sh_type == SHT_GNU_HASH) { 88 | sh_gnu_hash = sh; 89 | } 90 | } 91 | // Check if we got gnu hash table 92 | _dbg_printf("gnu hash section: %x\n", sh_gnu_hash->sh_addr); 93 | if(sh_gnu_hash != NULL) { 94 | } 95 | return NULL; 96 | } 97 | 98 | struct Stage3_Info_Struct typedef Stage3_Info_Struct; 99 | struct Stage3_Info_Struct { 100 | Elf_Image *app; 101 | Elf_Image *ldso; 102 | void *stack_base; 103 | u64 stack_size; 104 | void *tls_image; 105 | u64 tls_size; 106 | }; 107 | 108 | static void ld_stage3_entry(u64 has_new_stack, void *ctx); 109 | 110 | void ld_stack_trampoline( 111 | void *stack_base 112 | , void *old_stack_base 113 | , u64 stack_size 114 | , u64 old_stack_size 115 | , void (*fn)(u64 has_new_stack, void *ctx) 116 | , void *ctx 117 | ); 118 | 119 | void ld_stage2_entry(Loader_Info *ld_info) { 120 | _dbg_printf("Loader entry point reached!\n"); 121 | // Get our loader data back 122 | u64 *sp = ld_info->sp; 123 | u8 *ldso_base = ld_info->ldso_base; 124 | u64 *dyn = ld_info->dyn; 125 | u64 *aux = ld_info->aux; 126 | cia_pool_create(&image_pool, cia_allocator_pages(), 1*KB, sizeof(Elf_Image), 0x10); 127 | Elf_Image *ldso = cia_pool_alloc(&image_pool); 128 | Elf_Image *app = cia_pool_alloc(&image_pool); 129 | // Save some stuff for stage3 to eat 130 | cia_arena_create(&tmp_arena, cia_allocator_pages(), 1*MB); 131 | Stage3_Info_Struct *stage3 = cia_arena_alloc(&tmp_arena, sizeof(Stage3_Info_Struct)); 132 | stage3->app = app; 133 | stage3->ldso = ldso; 134 | ldso->base = ldso_base; 135 | ldso->dyn = dyn; 136 | // Read ldso elf header 137 | { 138 | Elf64_Ehdr *eh = (void *)ldso->base; 139 | ldso->phdr = elf_addr(ldso, eh->e_phoff); 140 | ldso->ph_num = eh->e_phnum; 141 | ldso->ph_ent = eh->e_phentsize; 142 | ldso->name = "ld-cia.so"; 143 | } 144 | int fd = 0; 145 | app->name = (void *)aux[AT_EXECFN]; 146 | if(aux[AT_PHDR] != (u64)ldso->base) { 147 | _dbg_printf("Linux loaded the image with phdrs at: %x\n", aux[AT_PHDR]); 148 | // Figure out executable base from its phdrs 149 | u8 *phdr = (void *)aux[AT_PHDR]; 150 | u64 ph_ent = aux[AT_PHENT]; 151 | u64 ph_num = aux[AT_PHNUM]; 152 | for(u64 i = 0; i < ph_num; ++i) { 153 | u64 ph_off = i * ph_ent; 154 | Elf64_Phdr *ph = (void *)(phdr + ph_off); 155 | if(ph->p_type == PT_PHDR) { 156 | app->base = (void *)(aux[AT_PHDR] - ph->p_vaddr); 157 | } 158 | } 159 | _dbg_printf("app base: %x\n", app->base); 160 | app->phdr = phdr; 161 | app->ph_ent = ph_ent; 162 | app->ph_num = ph_num; 163 | } 164 | else { 165 | _dbg_printf("Exec filename: %x\n", aux[AT_EXECFN]); 166 | char *filename = (void *)aux[AT_EXECFN]; 167 | app->name = filename; 168 | if(filename == NULL) { 169 | printf("ERROR: no data about the executable to load dynamically\n"); 170 | sys_exit(1); 171 | } 172 | int fd = sys_open(filename, O_CLOEXEC, O_RDWR); 173 | if(fd < 0) { 174 | printf("ERROR: cannot open file %s\n", filename); 175 | sys_exit(1); 176 | } 177 | elf_load(app, fd); 178 | } 179 | if(fd != 0) { 180 | sys_close(fd); 181 | } 182 | // Find .dynamic section 183 | { 184 | u8 *phdr = (void *)aux[AT_PHDR]; 185 | u64 ph_ent = aux[AT_PHENT]; 186 | u64 ph_num = aux[AT_PHNUM]; 187 | Elf64_Phdr *ph_dynamic = NULL; 188 | for(u64 i = 0; i < ph_num; ++i) { 189 | u64 ph_off = i * ph_ent; 190 | Elf64_Phdr *ph = (void *)(phdr + ph_off); 191 | if(ph->p_type == PT_DYNAMIC) { 192 | ph_dynamic = ph; 193 | } 194 | } 195 | // Read and decode dynamic vector 196 | Elf64_Dyn *dynv = elf_addr(app, ph_dynamic->p_vaddr); 197 | u64 dyn[DYN_CNT]; 198 | for(int i = 0; i < DYN_CNT; ++i) { 199 | dyn[i] = 0; 200 | } 201 | for(int i = 0; dynv[i].d_tag != DT_NULL; ++i) { 202 | i64 d_tag = dynv[i].d_tag; 203 | if(d_tag < DYN_CNT) { 204 | dyn[0] |= 1ul << d_tag; 205 | dyn[d_tag] = dynv[i].d_un.d_val; 206 | } 207 | } 208 | app->dyn = &dyn[0]; 209 | } 210 | // Load section headers for app 211 | _dbg_printf("Loading section headers\n"); 212 | { 213 | } 214 | // Relocate app 215 | { 216 | _dbg_printf("Relocating app\n"); 217 | Elf64_Ehdr *eh = (void *)app->base; 218 | // Resolve relocations 219 | Elf64_Sym *symtab = elf_addr(app, (void *)app->dyn[DT_SYMTAB]); 220 | char *strtab = elf_addr(app, app->dyn[DT_STRTAB]); 221 | _dbg_printf("APP STRTAB: %x\n", strtab); 222 | if(app->dyn[DT_REL] != 0) { 223 | printf("REL Relocations found. This part isn't implemented\n"); 224 | u8 *rel_ents = elf_addr(app, app->dyn[DT_REL]); 225 | u64 rel_ent = app->dyn[DT_RELENT]; 226 | u64 rel_size = app->dyn[DT_RELSZ]; 227 | u64 rel_offs = 0; 228 | while(rel_offs < rel_size) { 229 | Elf64_Rel *rel = (void *)(rel_ents + rel_offs); 230 | u64 offs = rel->r_offset; 231 | u32 sym = ELF64_R_SYM(rel->r_info); 232 | u32 type = ELF64_R_TYPE(rel->r_info); 233 | _dbg_printf(" %d @ %d (%d)\n", sym, offs, type); 234 | sys_exit(0); 235 | // TODO: if needed 236 | rel_offs += rel_ent; 237 | } 238 | } 239 | if(app->dyn[DT_RELA] != 0) { 240 | _dbg_printf("RELA:\n"); 241 | u8 *rela_ents = elf_addr(app, app->dyn[DT_RELA]); 242 | u64 rela_ent = app->dyn[DT_RELAENT]; 243 | u64 rela_size = app->dyn[DT_RELASZ]; 244 | u64 rela_offs = 0; 245 | while(rela_offs < rela_size) { 246 | Elf64_Rela *rela = (void *)(rela_ents + rela_offs); 247 | u64 reloc_offs = rela->r_offset; 248 | u64 addend = rela->r_addend; 249 | u32 type = ELF64_R_TYPE(rela->r_info); 250 | Elf64_Sym *sym = &symtab[ELF64_R_SYM(rela->r_info)]; 251 | void *sym_addr = elf_addr(app, (u64)sym->st_value); 252 | void **reloc_addr = elf_addr(app, reloc_offs); 253 | { 254 | u32 sym_name_offset = sym->st_name; 255 | if(sym_name_offset == 0) { 256 | _dbg_printf(" %x+%d, @%x (%d)", sym_addr, addend, reloc_offs, type); 257 | } 258 | else { 259 | char *sym_name = &strtab[sym_name_offset]; 260 | _dbg_printf(" %s+%d, @%x (%d)", sym_name, addend, reloc_offs, type); 261 | } 262 | } 263 | if(type == R_X86_64_GLOB_DAT) { 264 | *reloc_addr = sym_addr; 265 | } 266 | else if(type == R_X86_64_RELATIVE) { 267 | *reloc_addr = elf_addr(app, addend); 268 | } 269 | else { 270 | printf("ERROR: unhandled relocation type: %d\n", type); 271 | sys_exit(1); 272 | } 273 | _dbg_printf(" -> %x\n", *reloc_addr); 274 | rela_offs += rela_ent; 275 | } 276 | } 277 | if(app->dyn[DT_PLTGOT] != 0) { 278 | _dbg_printf("PLT relocations found\n"); 279 | if(app->dyn[DT_PLTREL] == DT_REL) { 280 | _dbg_printf(" PLT relocations use relocations of type REL\n"); 281 | printf("ERROR: .plt relocations of type REL not implemented\n"); 282 | sys_exit(1); 283 | } 284 | else if(app->dyn[DT_PLTREL] == DT_RELA) { 285 | _dbg_printf(" PLT relocations use relocations of type RELA\n"); 286 | } 287 | void *plt = elf_addr(app, app->dyn[DT_PLTGOT]); 288 | void *rela_plt = elf_addr(app, app->dyn[DT_JMPREL]); 289 | u64 rela_ent = sizeof(Elf64_Rela); 290 | u64 rela_size = app->dyn[DT_PLTRELSZ]; 291 | u64 rela_offs = 0; 292 | while(rela_offs < rela_size) { 293 | Elf64_Rela *rela = (void *)(rela_plt + rela_offs); 294 | u64 reloc_offs = rela->r_offset; 295 | u64 addend = rela->r_addend; 296 | u32 sym_idx = ELF64_R_SYM(rela->r_info); 297 | u32 type = ELF64_R_TYPE(rela->r_info); 298 | _dbg_printf(" %x+%d, @%x (%d)\n", sym_idx, addend, reloc_offs, type); 299 | if(type == R_X86_64_JUMP_SLOT) { 300 | Elf64_Sym *sym = &symtab[sym_idx]; 301 | void *sym_addr = elf_addr(app, sym->st_value); 302 | void **reloc_addr = elf_addr(app, reloc_offs); 303 | _dbg_printf(" -> resolving with %x\n", sym_addr); 304 | *reloc_addr = sym_addr; 305 | } 306 | rela_offs += rela_ent; 307 | } 308 | } 309 | _dbg_printf("%x\n", 0); 310 | // Get the size of the TLS initialization image for the main modules 311 | u64 tls_size = 0; 312 | { 313 | Elf64_Phdr *ph_tls = NULL; 314 | for(u64 i = 0; i < app->ph_num; ++i) { 315 | Elf64_Phdr *ph = (void *)(app->phdr + i*app->ph_ent); 316 | if(ph->p_type == PT_TLS) { 317 | ph_tls = ph; 318 | break; 319 | } 320 | } 321 | if(ph_tls != NULL) { 322 | tls_size += ph_tls->p_memsz; 323 | } 324 | } 325 | _dbg_printf("TLS image size: %x\n", tls_size); 326 | // Get the information about the main thread stack 327 | if(linux_read_stack_info()) { 328 | printf("ERROR: failed to read /proc/self/maps to get the stack info\n"); 329 | sys_exit(1); 330 | } 331 | _dbg_printf("Found default stack at: %x-%x\n", stack_info.start_addr, stack_info.end_addr); 332 | void *old_stack_base = (void *)stack_info.start_addr; 333 | u64 old_stack_size = (u64)stack_info.end_addr - (u64)stack_info.start_addr; 334 | u64 stack_size = 2*MB; 335 | void *stack_base = sys_mmap(0, stack_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); 336 | stage3->stack_size = stack_size; 337 | stage3->stack_base = stack_base; 338 | stage3->tls_size = tls_size; 339 | _dbg_printf("stage3 info struct: %x\n", stage3); 340 | // Will jump to ld_stage3_entry 341 | ld_stack_trampoline(stack_base, old_stack_base, stack_size, old_stack_size, &ld_stage3_entry, stage3); 342 | } 343 | sys_exit(0); 344 | } 345 | 346 | static void ld_stage3_entry(u64 has_new_stack, void *ctx) { 347 | if(!has_new_stack) { 348 | printf("ERROR: failed to switch the stack\n"); 349 | sys_exit(1); 350 | } 351 | Stage3_Info_Struct *info = ctx; 352 | _dbg_printf("Stack: %x-%x\n", info->stack_base, (u8 *)info->stack_base+info->stack_size); 353 | // Set up the thread control block 354 | _LD_Thread_Block *tcb = cia_ptr_alignf((u8*)info->stack_base + info->tls_size, info->stack_size/2); 355 | tcb->thread_id = 0; 356 | tcb->stack_canary = 0x12345678fedcba98; 357 | // Copy TLS initialization image below TCB 358 | { 359 | Elf_Image *app = info->app; 360 | Elf64_Phdr *ph_tls = NULL; 361 | for(u64 i = 0; i < app->ph_num; ++i) { 362 | Elf64_Phdr *ph = (void *)(app->phdr + i*app->ph_ent); 363 | if(ph->p_type == PT_TLS) { 364 | ph_tls = ph; 365 | break; 366 | } 367 | } 368 | if(ph_tls != NULL) { 369 | u8 *tls_image_base = elf_addr(app, ph_tls->p_vaddr); 370 | u64 tls_image_size = ph_tls->p_memsz; 371 | u8 *tls_image = (u8*)tcb - tls_image_size; 372 | for(int i = 0; i < tls_image_size; ++i) { 373 | tls_image[i] = tls_image_base[i]; 374 | } 375 | info->tls_image = tls_image_base; 376 | } 377 | } 378 | // Set up the thread pointer 379 | int err = sys_arch_prctl(ARCH_SET_FS, (u64)tcb); 380 | if(err < 0) { 381 | printf("ERROR: failed to set up the thread pointer\n"); 382 | sys_exit(1); 383 | } 384 | _dbg_printf("Entered loader stage 3. Entering main executable\n"); 385 | _LD_CRT_Params params; 386 | params.stack_size = info->stack_size/2; 387 | params.tls_image_size = info->tls_size; 388 | params.tls_image_base = info->tls_image; 389 | void (*crt_entry)(_LD_CRT_Params *params) = elf_addr(info->app, ((Elf64_Ehdr *)info->app->base)->e_entry); 390 | crt_entry(¶ms); 391 | } 392 | -------------------------------------------------------------------------------- /tests/testing.h: -------------------------------------------------------------------------------- 1 | 2 | // Framework for testing of the CRT library. This file is supposed to be linked 3 | // to the ciabatta, so there is a possibility that the runtime that the testing 4 | // suite relies on is broken, which is why to decrease the chance of it crashing 5 | // because of that, I minimize that dependency. Therefore this testing suite 6 | // avoids the following: 7 | // - Heap allocations 8 | // - Calls to high-level functions like printf, preferring low-level fwrite instead 9 | // - Calling other CRT functions other than for the purpose of testing them 10 | 11 | // Dependencies 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | // Tested 20 | #include 21 | #include 22 | #include 23 | 24 | // MEMORY 25 | 26 | #define TEST_MEMORY_SIZE 8*1024*1024 27 | static uint8_t test_memory[TEST_MEMORY_SIZE]; 28 | static uint64_t test_memory_head = TEST_MEMORY_SIZE; 29 | 30 | static void *mem_alloc(uint64_t size) { 31 | if(test_memory_head < size) { 32 | fputs("Out of memory. Can't continue testing!!", stderr); 33 | return NULL; 34 | } 35 | test_memory_head -= size; 36 | return &test_memory[test_memory_head]; 37 | } 38 | 39 | // RANDOM NUMBER GENERATOR (RNG) 40 | 41 | static unsigned long random_seed = 0; 42 | 43 | unsigned long random(void) { 44 | random_seed = random_seed * 2147001325 + 715136305; 45 | return 0x31415926 ^ ((random_seed >> 16) + (random_seed << 16)); 46 | } 47 | 48 | unsigned long random_between(int lo, int hi) { 49 | return (random() % (1+hi - lo)) + lo; 50 | } 51 | 52 | // FORMATTING AND IO 53 | 54 | bool fmt_xml_escapes = false; 55 | 56 | static void fprintc(FILE *file, char c) { 57 | fputc(c, file); 58 | } 59 | 60 | static void fprints(FILE *file, char *str) { 61 | while(*str != 0) { 62 | fputc(*str++, file); 63 | } 64 | } 65 | 66 | static void fprintc_maybe_xml(FILE *file, char c) { 67 | if(c == '"' && fmt_xml_escapes) { 68 | fprints(file, """); 69 | } 70 | else if(c == '&' && fmt_xml_escapes) { 71 | fprints(file, "&"); 72 | } 73 | else if(c == '<' && fmt_xml_escapes) { 74 | fprints(file, "<"); 75 | } 76 | else if(c == '>' && fmt_xml_escapes) { 77 | fprints(file, ">"); 78 | } 79 | else if(c == '\'' && fmt_xml_escapes) { 80 | fprints(file, "'"); 81 | } 82 | else { 83 | fprintc(file, c); 84 | } 85 | } 86 | 87 | static void fprintd(FILE *file, int32_t number, int width) { 88 | if(number < 0) { 89 | fprintc(file, '-'); 90 | number = -number; 91 | } 92 | char buffer[20] = {0}; 93 | char *str = buffer + sizeof buffer - 1; 94 | do { 95 | *--str = number%10+'0'; 96 | number /= 10; 97 | } while(number != 0); 98 | int num_digits = (int)((buffer + sizeof buffer - 1) - str); 99 | int pad_width = width - num_digits; 100 | while(pad_width-- > 0) { 101 | fprintc(file, '0'); 102 | } 103 | fprints(file, str); 104 | } 105 | 106 | static void fprintu(FILE *file, uint32_t number, int width) { 107 | char buffer[20] = {0}; 108 | char *str = buffer + sizeof buffer; 109 | do { 110 | *--str = number%10+'0'; 111 | number /= 10; 112 | } while(number != 0); 113 | int num_digits = (int)((buffer + sizeof buffer - 1) - str); 114 | int pad_width = width - num_digits; 115 | while(pad_width-- > 0) { 116 | fprintc(file, '0'); 117 | } 118 | fprints(file, str); 119 | } 120 | 121 | static void fvprint_fmt(FILE *file, char *fmt, va_list args) { 122 | while(*fmt != 0) { 123 | if(*fmt != '%') { 124 | fprintc(file, *fmt); 125 | } 126 | else { 127 | ++fmt; 128 | int width = 0; 129 | while('0' <= *fmt && *fmt <= '9') { 130 | width = 10*width + *fmt-'0'; 131 | ++fmt; 132 | } 133 | if(*fmt == 'c') { 134 | int ch = va_arg(args, int); 135 | fprintc_maybe_xml(file, ch); 136 | } 137 | else if(*fmt == '%') { 138 | fprintc(file, '%'); 139 | } 140 | else if(*fmt == 's') { 141 | char *str = va_arg(args, char*); 142 | while(*str != 0) { 143 | fprintc_maybe_xml(file, *str); 144 | ++str; 145 | } 146 | } 147 | else if(*fmt == 'd') { 148 | int32_t i = va_arg(args, int32_t); 149 | fprintd(file, i, width); 150 | } 151 | else if(*fmt == 'u') { 152 | uint32_t u = va_arg(args, uint32_t); 153 | fprintu(file, u, width); 154 | } 155 | } 156 | ++fmt; 157 | } 158 | } 159 | 160 | static void fprint_fmt(FILE *file, char *fmt, ...) { 161 | va_list args; 162 | va_start(args, fmt); 163 | fvprint_fmt(file, fmt, args); 164 | va_end(args); 165 | } 166 | 167 | static void printc(char c) { 168 | fprintc(stdout, c); 169 | } 170 | 171 | static void prints(char *str) { 172 | fprints(stdout, str); 173 | } 174 | 175 | static void printd(int32_t number, int width) { 176 | fprintd(stdout, number, width); 177 | } 178 | 179 | static void printu(uint32_t number, int width) { 180 | fprintu(stdout, number, width); 181 | } 182 | 183 | static void print_fmt(char *fmt, ...) { 184 | va_list args; 185 | va_start(args, fmt); 186 | fvprint_fmt(stdout, fmt, args); 187 | va_end(args); 188 | } 189 | 190 | static void sprint_fmt(char *dst, char *fmt, ...) { 191 | va_list args; 192 | va_start(args, fmt); 193 | while(*fmt != 0) { 194 | if(*fmt != '%') { 195 | *dst++ = *fmt; 196 | } 197 | else { 198 | ++fmt; 199 | int width = 0; 200 | while('0' <= *fmt && *fmt <= '9') { 201 | width = 10*width + *fmt-'0'; 202 | ++fmt; 203 | } 204 | if(*fmt == 'c') { 205 | int ch = va_arg(args, int); 206 | *dst++ = ch; 207 | } 208 | else if(*fmt == 's') { 209 | char *str = va_arg(args, char*); 210 | while((*dst++ = *str++)); 211 | } 212 | else if(*fmt == 'd') { 213 | int32_t i = va_arg(args, int32_t); 214 | if(i < 0) { 215 | i = -i; 216 | *dst++ = '-'; 217 | } 218 | char buffer[20] = {0}; 219 | char *str = buffer + sizeof buffer; 220 | do { 221 | *--str = i%10+'0'; 222 | i /= 10; 223 | } while(i != 0); 224 | int num_digits = (int)((buffer + sizeof buffer - 1) - str); 225 | int pad_width = width - num_digits; 226 | while(pad_width-- > 0) { 227 | *dst++ = '0'; 228 | } 229 | while((*dst++ = *str++)); 230 | } 231 | else if(*fmt == 'u') { 232 | uint32_t u = va_arg(args, uint32_t); 233 | char buffer[20] = {0}; 234 | char *str = buffer + sizeof buffer; 235 | do { 236 | *--str = u%10+'0'; 237 | u /= 10; 238 | } while(u != 0); 239 | int num_digits = (int)((buffer + sizeof buffer - 1) - str); 240 | int pad_width = width - num_digits; 241 | while(pad_width-- > 0) { 242 | *dst++ = '0'; 243 | } 244 | while((*dst++ = *str++)); 245 | } 246 | } 247 | ++fmt; 248 | } 249 | *dst = 0; 250 | va_end(fmt); 251 | } 252 | 253 | static void term_color_green() { 254 | prints("\x1b[32m"); 255 | } 256 | 257 | static void term_color_red() { 258 | prints("\x1b[31m"); 259 | } 260 | 261 | static void term_color_yellow() { 262 | prints("\x1b[33m"); 263 | } 264 | 265 | static void term_color_reset() { 266 | prints("\x1b[0m"); 267 | } 268 | 269 | // TEST SUITE FUNCTIONS 270 | 271 | // This stuff is for saving results of tests to be a bit more flexible with printing 272 | // test results 273 | struct Test typedef Test; 274 | struct Test_Feature typedef Test_Feature; 275 | 276 | struct Test_Feature { 277 | Test_Feature *next; 278 | char *name; 279 | int test_count; 280 | int success_count; 281 | Test *test_head; 282 | }; 283 | 284 | struct Test { 285 | Test *next; 286 | char *condition_str; 287 | char *error_msg; 288 | int line; 289 | bool is_succeeded; 290 | }; 291 | 292 | static Test_Feature *reverse_test_lists(Test_Feature *features_reversed) { 293 | Test_Feature *new_head = NULL; 294 | while(features_reversed != NULL) { 295 | Test_Feature *reversed_next = features_reversed->next; 296 | Test_Feature *new_prev = features_reversed; 297 | new_prev->next = new_head; 298 | new_head = new_prev; 299 | features_reversed = reversed_next; 300 | } 301 | for(Test_Feature *feature = new_head; feature != NULL; feature = feature->next) { 302 | Test *reversed_head = feature->test_head; 303 | Test *head = NULL; 304 | while(reversed_head != NULL) { 305 | Test *reversed_next = reversed_head->next; 306 | Test *head_prev = reversed_head; 307 | head_prev->next = head; 308 | head = head_prev; 309 | reversed_head = reversed_next; 310 | } 311 | feature->test_head = head; 312 | } 313 | return new_head; 314 | } 315 | 316 | static void print_test_results(Test_Feature *features) { 317 | prints(":: Printing test results\n"); 318 | // Iterate features 319 | int total_test_count = 0; 320 | int total_success_count = 0; 321 | for(Test_Feature *feature = features; feature != NULL; feature = feature->next) { 322 | // Update counters 323 | total_test_count += feature->test_count; 324 | total_success_count += feature->success_count; 325 | // Print feature name 326 | term_color_green(); 327 | print_fmt("==> Feature "); 328 | term_color_reset(); 329 | print_fmt("%s: (%d/%d)\n", feature->name, feature->success_count, feature->test_count); 330 | if(feature->success_count < feature->test_count) { 331 | int test_index = 0; 332 | for(Test *test = feature->test_head; test != NULL; test = test->next) { 333 | if(!test->is_succeeded) { 334 | term_color_red(); 335 | print_fmt(" Test #%d", 1+test_index); 336 | term_color_reset(); 337 | print_fmt(" failed (line %d): %s\n", test->line, test->error_msg); 338 | } 339 | test_index += 1; 340 | } 341 | } 342 | } 343 | float success_percentage = (float) total_success_count / (float)total_test_count; 344 | if(success_percentage < 0.5) { 345 | term_color_red(); 346 | } 347 | else if(success_percentage != 1.0) { 348 | term_color_yellow(); 349 | } 350 | else { 351 | term_color_green(); 352 | } 353 | time_t timestamp = time(NULL); 354 | struct tm tm = *localtime(×tamp); 355 | print_fmt("[%4d-%2d-%2d %2d:%2d:%2d] ", 1900+tm.tm_year, 1+tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); 356 | prints("TESTS COMPLETED: "); 357 | printd(total_success_count, 0); 358 | printc('/'); 359 | printd(total_test_count, 0); 360 | term_color_reset(); 361 | printc('\n'); 362 | } 363 | 364 | // JUNIT OUTPUT 365 | 366 | static void junit_write(char *path, Test_Feature *features) { 367 | fmt_xml_escapes = true; 368 | FILE *xml = fopen(path, "wb"); 369 | // TODO: store tests and failures in an object instead of calculating it like that 370 | int total_test_count = 0; 371 | int total_success_count = 0; 372 | for(Test_Feature *feature = features; feature != NULL; feature = feature->next) { 373 | total_test_count += feature->test_count; 374 | total_success_count += feature->success_count; 375 | } 376 | fprint_fmt(xml, "\n"); 377 | fprint_fmt(xml, "\n", 378 | "Ciabatta CRT functions test suite", total_test_count, total_test_count - total_success_count); 379 | int feature_id = 0; 380 | for(Test_Feature *feature = features; feature != NULL; feature = feature->next) { 381 | fprint_fmt(xml, " \n", 382 | feature_id, feature->name, feature->test_count, feature->test_count - feature->success_count); 383 | int test_id = 0; 384 | for(Test *test = feature->test_head; test != NULL; test = test->next) { 385 | fprint_fmt(xml, " \n", 386 | test_id, test->condition_str); 387 | if(!test->is_succeeded) { 388 | fprint_fmt(xml, " \n", 389 | test->line, test->error_msg); 390 | fprint_fmt(xml, "crt.c(%d):\n %s\n", test->line, test->error_msg); 391 | fprint_fmt(xml, " \n"); 392 | } 393 | test_id += 1; 394 | fprint_fmt(xml, " \n"); 395 | } 396 | feature_id += 1; 397 | fprint_fmt(xml, " \n"); 398 | } 399 | fprint_fmt(xml, "\n"); 400 | fclose(xml); 401 | fmt_xml_escapes = false; 402 | } 403 | 404 | // TEST MACROS 405 | 406 | #define XSTR(expr) #expr 407 | #define STR(expr) XSTR(expr) 408 | 409 | Test_Feature *current_feature = NULL; 410 | bool junit_output = false; 411 | char *junit_output_path = NULL; 412 | 413 | #define JUNIT_START(XML_PATH) \ 414 | junit_output = true; \ 415 | junit_output_path = XML_PATH 416 | 417 | #define JUNIT_END() \ 418 | if(junit_output) { \ 419 | junit_write(junit_output_path, current_feature); \ 420 | } 421 | 422 | #define FEATURE_START__(NAME, NUMBER) \ 423 | { \ 424 | print_fmt(":: Running tests for %s\n", NAME); \ 425 | Test_Feature *feature = mem_alloc(sizeof(Test_Feature)); \ 426 | feature->next = current_feature; \ 427 | current_feature = feature; \ 428 | current_feature->name = NAME; \ 429 | current_feature->test_head = NULL; \ 430 | current_feature->success_count = 0; \ 431 | current_feature->test_count = 0; \ 432 | } 433 | 434 | #define FEATURE_START_(NAME, NUMBER) \ 435 | FEATURE_START__(NAME, NUMBER) 436 | 437 | #define FEATURE_START(NAME) \ 438 | FEATURE_START_(NAME, __COUNTER__) 439 | 440 | #define FEATURE_END() 441 | 442 | #define TEST__(EXPR, ERROR_FMT, NUMBER, LINE, ...) \ 443 | { \ 444 | Test *test = mem_alloc(sizeof(Test)); \ 445 | test->next = current_feature->test_head; \ 446 | current_feature->test_head = test; \ 447 | current_feature->test_head->condition_str = STR(EXPR); \ 448 | current_feature->test_head->is_succeeded = EXPR; \ 449 | current_feature->test_head->line = LINE; \ 450 | if(current_feature->test_head->is_succeeded) {\ 451 | current_feature->success_count += 1; \ 452 | }\ 453 | else { \ 454 | current_feature->test_head->error_msg = mem_alloc(256); \ 455 | sprint_fmt(current_feature->test_head->error_msg, ERROR_FMT, __VA_ARGS__); \ 456 | }\ 457 | current_feature->test_count += 1; \ 458 | } 459 | 460 | #define TEST_(EXPR, ERROR_MSG, NUMBER, LINE, ...) \ 461 | TEST__(EXPR, ERROR_MSG, NUMBER, LINE, __VA_ARGS__) 462 | 463 | #define TEST(EXPR, ERROR_MSG, ...) \ 464 | TEST_(EXPR, ERROR_MSG, __COUNTER__, __LINE__, __VA_ARGS__) 465 | 466 | #define TESTS_PREPARE() \ 467 | current_feature = reverse_test_lists(current_feature) 468 | 469 | #define TESTS_PRINT_RESULT() \ 470 | print_test_results(current_feature) 471 | 472 | -------------------------------------------------------------------------------- /include/linux/sys/syscall.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | // For now these definitions will live here 7 | #if !defined(STDIN_FILENO) 8 | #define STDIN_FILENO 0 9 | #define STDOUT_FILENO 1 10 | #define STDERR_FILENO 2 11 | #endif 12 | 13 | #define _SYSCALL0(n) _syscall0(n) 14 | #define _SYSCALL1(n,p1) _syscall1(n, (i64)p1) 15 | #define _SYSCALL2(n,p1,p2) _syscall2(n, (i64)p1, (i64)p2) 16 | #define _SYSCALL3(n,p1,p2,p3) _syscall3(n, (i64)p1, (i64)p2, (i64)p3) 17 | #define _SYSCALL4(n,p1,p2,p3,p4) _syscall4(n, (i64)p1, (i64)p2, (i64)p3, (i64)p4) 18 | #define _SYSCALL5(n,p1,p2,p3,p4,p5) _syscall5(n, (i64)p1, (i64)p2, (i64)p3, (i64)p4, (i64)p5) 19 | #define _SYSCALL6(n,p1,p2,p3,p4,p5,p6) _syscall6(n, (i64)p1, (i64)p2, (i64)p3, (i64)p4, (i64)p5, (i64)p6) 20 | 21 | #define _SYSCALL_NARGS(...) _SYSCALL_NARGS_(0, ## __VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) 22 | #define _SYSCALL_NARGS_(_0, _1_, _2_, _3_, _4_, _5_, _6_, count, ...) count 23 | #define _SYSCALL_CONCAT(a, b) _SYSCALL_CONCAT_(a,b) 24 | #define _SYSCALL_CONCAT_(a,b) a ## b 25 | 26 | // Creates an expression of the sort `_SYSCALL()` 27 | #define syscall(n, ...) _SYSCALL_CONCAT(_SYSCALL, _SYSCALL_NARGS(__VA_ARGS__))(n, ## __VA_ARGS__) 28 | 29 | static inline i64 _syscall0(i64 n) { 30 | i64 ret = 0; 31 | asm volatile("syscall" : "=a"(ret) : "a"(n) : "rcx", "r11", "memory"); 32 | return ret; 33 | } 34 | 35 | static inline i64 _syscall1(i64 n, i64 a1) { 36 | i64 ret = 0; 37 | asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1) : "rcx", "r11", "memory"); 38 | return ret; 39 | } 40 | 41 | static inline i64 _syscall2(i64 n, i64 a1, i64 a2) { 42 | i64 ret = 0; 43 | asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2) 44 | : "rcx", "r11", "memory"); 45 | return ret; 46 | } 47 | 48 | static inline i64 _syscall3(i64 n, i64 a1, i64 a2, i64 a3) { 49 | i64 ret = 0; 50 | asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), 51 | "d"(a3) : "rcx", "r11", "memory"); 52 | return ret; 53 | } 54 | 55 | static inline i64 _syscall4(i64 n, i64 a1, i64 a2, i64 a3, i64 a4) { 56 | i64 ret = 0; 57 | register i64 r10 asm("r10") = a4; 58 | asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), 59 | "d"(a3), "r"(r10): "rcx", "r11", "memory"); 60 | return ret; 61 | } 62 | 63 | static inline i64 _syscall5(i64 n, i64 a1, i64 a2, i64 a3, i64 a4, i64 a5) { 64 | i64 ret = 0; 65 | register i64 r10 asm("r10") = a4; 66 | register i64 r8 asm("r8") = a5; 67 | asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), 68 | "d"(a3), "r"(r10), "r"(r8) : "rcx", "r11", "memory"); 69 | return ret; 70 | } 71 | 72 | static inline i64 _syscall6(i64 n, i64 a1, i64 a2, i64 a3, i64 a4, i64 a5, i64 a6) { 73 | i64 ret = 0; 74 | register i64 r10 asm("r10") = a4; 75 | register i64 r8 asm("r8") = a5; 76 | register i64 r9 asm("r9") = a6; 77 | asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), 78 | "d"(a3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory"); 79 | return ret; 80 | } 81 | 82 | // Syscall numbers 83 | #define SYS_read 0 84 | #define SYS_write 1 85 | #define SYS_open 2 86 | #define SYS_close 3 87 | #define SYS_stat 4 88 | #define SYS_fstat 5 89 | #define SYS_lstat 6 90 | #define SYS_poll 7 91 | #define SYS_lseek 8 92 | #define SYS_mmap 9 93 | #define SYS_mprotect 10 94 | #define SYS_munmap 11 95 | #define SYS_brk 12 96 | #define SYS_rt_sigaction 13 97 | #define SYS_rt_sigprocmask 14 98 | #define SYS_rt_sigreturn 15 99 | #define SYS_ioctl 16 100 | #define SYS_pread64 17 101 | #define SYS_pwrite64 18 102 | #define SYS_readv 19 103 | #define SYS_writev 20 104 | #define SYS_access 21 105 | #define SYS_pipe 22 106 | #define SYS_select 23 107 | #define SYS_sched_yield 24 108 | #define SYS_mremap 25 109 | #define SYS_msync 26 110 | #define SYS_mincore 27 111 | #define SYS_madvise 28 112 | #define SYS_shmget 29 113 | #define SYS_shmat 30 114 | #define SYS_shmctl 31 115 | #define SYS_dup 32 116 | #define SYS_dup2 33 117 | #define SYS_pause 34 118 | #define SYS_nanosleep 35 119 | #define SYS_getitimer 36 120 | #define SYS_alarm 37 121 | #define SYS_setitimer 38 122 | #define SYS_getpid 39 123 | #define SYS_sendfile 40 124 | #define SYS_socket 41 125 | #define SYS_connect 42 126 | #define SYS_accept 43 127 | #define SYS_sendto 44 128 | #define SYS_recvfrom 45 129 | #define SYS_sendmsg 46 130 | #define SYS_recvmsg 47 131 | #define SYS_shutdown 48 132 | #define SYS_bind 49 133 | #define SYS_listen 50 134 | #define SYS_getsockname 51 135 | #define SYS_getpeername 52 136 | #define SYS_socketpair 53 137 | #define SYS_setsockopt 54 138 | #define SYS_getsockopt 55 139 | #define SYS_clone 56 140 | #define SYS_fork 57 141 | #define SYS_vfork 58 142 | #define SYS_execve 59 143 | #define SYS_exit 60 144 | #define SYS_wait4 61 145 | #define SYS_kill 62 146 | #define SYS_uname 63 147 | #define SYS_semget 64 148 | #define SYS_semop 65 149 | #define SYS_semctl 66 150 | #define SYS_shmdt 67 151 | #define SYS_msgget 68 152 | #define SYS_msgsnd 69 153 | #define SYS_msgrcv 70 154 | #define SYS_msgctl 71 155 | #define SYS_fcntl 72 156 | #define SYS_flock 73 157 | #define SYS_fsync 74 158 | #define SYS_fdatasync 75 159 | #define SYS_truncate 76 160 | #define SYS_ftruncate 77 161 | #define SYS_getdents 78 162 | #define SYS_getcwd 79 163 | #define SYS_chdir 80 164 | #define SYS_fchdir 81 165 | #define SYS_rename 82 166 | #define SYS_mkdir 83 167 | #define SYS_rmdir 84 168 | #define SYS_creat 85 169 | #define SYS_link 86 170 | #define SYS_unlink 87 171 | #define SYS_symlink 88 172 | #define SYS_readlink 89 173 | #define SYS_chmod 90 174 | #define SYS_fchmod 91 175 | #define SYS_chown 92 176 | #define SYS_fchown 93 177 | #define SYS_lchown 94 178 | #define SYS_umask 95 179 | #define SYS_gettimeofday 96 180 | #define SYS_getrlimit 97 181 | #define SYS_getrusage 98 182 | #define SYS_sysinfo 99 183 | #define SYS_times 100 184 | #define SYS_ptrace 101 185 | #define SYS_getuid 102 186 | #define SYS_syslog 103 187 | #define SYS_getgid 104 188 | #define SYS_setuid 105 189 | #define SYS_setgid 106 190 | #define SYS_geteuid 107 191 | #define SYS_getegid 108 192 | #define SYS_setpgid 109 193 | #define SYS_getppid 110 194 | #define SYS_getpgrp 111 195 | #define SYS_setsid 112 196 | #define SYS_setreuid 113 197 | #define SYS_setregid 114 198 | #define SYS_getgroups 115 199 | #define SYS_setgroups 116 200 | #define SYS_setresuid 117 201 | #define SYS_getresuid 118 202 | #define SYS_setresgid 119 203 | #define SYS_getresgid 120 204 | #define SYS_getpgid 121 205 | #define SYS_setfsuid 122 206 | #define SYS_setfsgid 123 207 | #define SYS_getsid 124 208 | #define SYS_capget 125 209 | #define SYS_capset 126 210 | #define SYS_rt_sigpending 127 211 | #define SYS_rt_sigtimedwait 128 212 | #define SYS_rt_sigqueueinfo 129 213 | #define SYS_rt_sigsuspend 130 214 | #define SYS_sigaltstack 131 215 | #define SYS_utime 132 216 | #define SYS_mknod 133 217 | #define SYS_uselib 134 218 | #define SYS_personality 135 219 | #define SYS_ustat 136 220 | #define SYS_statfs 137 221 | #define SYS_fstatfs 138 222 | #define SYS_sysfs 139 223 | #define SYS_getpriority 140 224 | #define SYS_setpriority 141 225 | #define SYS_sched_setparam 142 226 | #define SYS_sched_getparam 143 227 | #define SYS_sched_setscheduler 144 228 | #define SYS_sched_getscheduler 145 229 | #define SYS_sched_get_priority_max 146 230 | #define SYS_sched_get_priority_min 147 231 | #define SYS_sched_rr_get_interval 148 232 | #define SYS_mlock 149 233 | #define SYS_munlock 150 234 | #define SYS_mlockall 151 235 | #define SYS_munlockall 152 236 | #define SYS_vhangup 153 237 | #define SYS_modify_ldt 154 238 | #define SYS_pivot_root 155 239 | #define SYS__sysctl 156 240 | #define SYS_prctl 157 241 | #define SYS_arch_prctl 158 242 | #define SYS_adjtimex 159 243 | #define SYS_setrlimit 160 244 | #define SYS_chroot 161 245 | #define SYS_sync 162 246 | #define SYS_acct 163 247 | #define SYS_settimeofday 164 248 | #define SYS_mount 165 249 | #define SYS_umount2 166 250 | #define SYS_swapon 167 251 | #define SYS_swapoff 168 252 | #define SYS_reboot 169 253 | #define SYS_sethostname 170 254 | #define SYS_setdomainname 171 255 | #define SYS_iopl 172 256 | #define SYS_ioperm 173 257 | #define SYS_create_module 174 258 | #define SYS_init_module 175 259 | #define SYS_delete_module 176 260 | #define SYS_get_kernel_syms 177 261 | #define SYS_query_module 178 262 | #define SYS_quotactl 179 263 | #define SYS_nfsservctl 180 264 | #define SYS_getpmsg 181 265 | #define SYS_putpmsg 182 266 | #define SYS_afs_syscall 183 267 | #define SYS_tuxcall 184 268 | #define SYS_security 185 269 | #define SYS_gettid 186 270 | #define SYS_readahead 187 271 | #define SYS_setxattr 188 272 | #define SYS_lsetxattr 189 273 | #define SYS_fsetxattr 190 274 | #define SYS_getxattr 191 275 | #define SYS_lgetxattr 192 276 | #define SYS_fgetxattr 193 277 | #define SYS_listxattr 194 278 | #define SYS_llistxattr 195 279 | #define SYS_flistxattr 196 280 | #define SYS_removexattr 197 281 | #define SYS_lremovexattr 198 282 | #define SYS_fremovexattr 199 283 | #define SYS_tkill 200 284 | #define SYS_time 201 285 | #define SYS_futex 202 286 | #define SYS_sched_setaffinity 203 287 | #define SYS_sched_getaffinity 204 288 | #define SYS_set_thread_area 205 289 | #define SYS_io_setup 206 290 | #define SYS_io_destroy 207 291 | #define SYS_io_getevents 208 292 | #define SYS_io_submit 209 293 | #define SYS_io_cancel 210 294 | #define SYS_get_thread_area 211 295 | #define SYS_lookup_dcookie 212 296 | #define SYS_epoll_create 213 297 | #define SYS_epoll_ctl_old 214 298 | #define SYS_epoll_wait_old 215 299 | #define SYS_remap_file_pages 216 300 | #define SYS_getdents64 217 301 | #define SYS_set_tid_address 218 302 | #define SYS_restart_syscall 219 303 | #define SYS_semtimedop 220 304 | #define SYS_fadvise64 221 305 | #define SYS_timer_create 222 306 | #define SYS_timer_settime 223 307 | #define SYS_timer_gettime 224 308 | #define SYS_timer_getoverrun 225 309 | #define SYS_timer_delete 226 310 | #define SYS_clock_settime 227 311 | #define SYS_clock_gettime 228 312 | #define SYS_clock_getres 229 313 | #define SYS_clock_nanosleep 230 314 | #define SYS_exit_group 231 315 | #define SYS_epoll_wait 232 316 | #define SYS_epoll_ctl 233 317 | #define SYS_tgkill 234 318 | #define SYS_utimes 235 319 | #define SYS_vserver 236 320 | #define SYS_mbind 237 321 | #define SYS_set_mempolicy 238 322 | #define SYS_get_mempolicy 239 323 | #define SYS_mq_open 240 324 | #define SYS_mq_unlink 241 325 | #define SYS_mq_timedsend 242 326 | #define SYS_mq_timedreceive 243 327 | #define SYS_mq_notify 244 328 | #define SYS_mq_getsetattr 245 329 | #define SYS_kexec_load 246 330 | #define SYS_waitid 247 331 | #define SYS_add_key 248 332 | #define SYS_request_key 249 333 | #define SYS_keyctl 250 334 | #define SYS_ioprio_set 251 335 | #define SYS_ioprio_get 252 336 | #define SYS_inotify_init 253 337 | #define SYS_inotify_add_watch 254 338 | #define SYS_inotify_rm_watch 255 339 | #define SYS_migrate_pages 256 340 | #define SYS_openat 257 341 | #define SYS_mkdirat 258 342 | #define SYS_mknodat 259 343 | #define SYS_fchownat 260 344 | #define SYS_futimesat 261 345 | #define SYS_newfstatat 262 346 | #define SYS_unlinkat 263 347 | #define SYS_renameat 264 348 | #define SYS_linkat 265 349 | #define SYS_symlinkat 266 350 | #define SYS_readlinkat 267 351 | #define SYS_fchmodat 268 352 | #define SYS_faccessat 269 353 | #define SYS_pselect6 270 354 | #define SYS_ppoll 271 355 | #define SYS_unshare 272 356 | #define SYS_set_robust_list 273 357 | #define SYS_get_robust_list 274 358 | #define SYS_splice 275 359 | #define SYS_tee 276 360 | #define SYS_sync_file_range 277 361 | #define SYS_vmsplice 278 362 | #define SYS_move_pages 279 363 | #define SYS_utimensat 280 364 | #define SYS_epoll_pwait 281 365 | #define SYS_signalfd 282 366 | #define SYS_timerfd_create 283 367 | #define SYS_eventfd 284 368 | #define SYS_fallocate 285 369 | #define SYS_timerfd_settime 286 370 | #define SYS_timerfd_gettime 287 371 | #define SYS_accept4 288 372 | #define SYS_signalfd4 289 373 | #define SYS_eventfd2 290 374 | #define SYS_epoll_create1 291 375 | #define SYS_dup3 292 376 | #define SYS_pipe2 293 377 | #define SYS_inotify_init1 294 378 | #define SYS_preadv 295 379 | #define SYS_pwritev 296 380 | #define SYS_rt_tgsigqueueinfo 297 381 | #define SYS_perf_event_open 298 382 | 383 | static inline i32 sys_read(u32 fd, char *buf, u64 count) { 384 | return syscall(SYS_read, fd, buf, count); 385 | } 386 | 387 | static inline i32 sys_write(u32 fd, char const *buf, u64 count) { 388 | return syscall(SYS_write, fd, buf, count); 389 | } 390 | 391 | static inline i32 sys_open(char const *filename, int flags, int mode) { 392 | return syscall(SYS_open, filename, flags, mode); 393 | } 394 | 395 | static inline i64 sys_close(u32 fd) { 396 | return syscall(SYS_close, fd); 397 | } 398 | 399 | static inline void *sys_mmap(u64 addr, u64 len, u64 prot, u64 flags, u64 fd, u64 offset) { 400 | return (void *)syscall(SYS_mmap, addr, len, prot, flags, fd, offset); 401 | } 402 | 403 | static inline i64 sys_munmap(void *addr, u64 len) { 404 | return syscall(SYS_munmap, addr, len); 405 | } 406 | 407 | static inline i64 sys_clone(u64 flags, void *stack, int *parent_tid, int *child_tid, u64 tls) { 408 | return syscall(SYS_clone, flags, stack, parent_tid, child_tid, tls); 409 | } 410 | 411 | _Noreturn static inline void sys_exit(int code) { 412 | syscall(SYS_exit, code); 413 | __builtin_unreachable(); 414 | } 415 | 416 | static inline i64 sys_arch_prctl(int code, u64 value) { 417 | return syscall(SYS_arch_prctl, code, value); 418 | } 419 | 420 | static inline u32 sys_gettid() { 421 | return syscall(SYS_gettid); 422 | } 423 | 424 | static inline u32 sys_getpid() { 425 | return syscall(SYS_getpid); 426 | } 427 | 428 | static inline i32 sys_tkill(u32 tid, i32 sig) { 429 | return syscall(SYS_tkill, tid, sig); 430 | } 431 | 432 | static inline i32 sys_tgkill(u32 tgid, u32 tid, i32 sig) { 433 | return syscall(SYS_tgkill, tgid, tid, sig); 434 | } 435 | 436 | -------------------------------------------------------------------------------- /include/bin/elf.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | typedef u64 Elf64_Addr; 7 | typedef u64 Elf64_Off; 8 | typedef u16 Elf64_Half; 9 | typedef u32 Elf64_Word; 10 | typedef i32 Elf64_Sword; 11 | typedef u64 Elf64_Xword; 12 | typedef i64 Elf64_Sxword; 13 | 14 | // e_type definitions 15 | #define ET_NONE 0x0000 16 | #define ET_REL 0x0001 17 | #define ET_EXEC 0x0002 18 | #define ET_DYN 0x0003 19 | #define ET_CORE 0x0004 20 | #define ET_LOOS 0xfe00 21 | #define ET_HIOS 0xfeff 22 | #define ET_LOPROC 0xff00 23 | #define ET_HIPROC 0xffff 24 | 25 | // e_machine definitions 26 | #define EM_NONE 0 27 | #define EM_M32 1 28 | #define EM_SPARC 2 29 | #define EM_386 3 30 | #define EM_68K 4 31 | #define EM_88K 5 32 | #define EM_IAMCU 6 33 | #define EM_860 7 34 | #define EM_MIPS 8 35 | #define EM_S370 9 36 | #define EM_MIPS_RS3_LE 10 37 | #define EM_PARISC 15 38 | #define EM_VPP500 17 39 | #define EM_SPARC32PLUS 18 40 | #define EM_960 19 41 | #define EM_PPC 20 42 | #define EM_PPC64 21 43 | #define EM_S390 22 44 | #define EM_SPU 23 45 | #define EM_V800 36 46 | #define EM_FR20 37 47 | #define EM_RH32 38 48 | #define EM_RCE 39 49 | #define EM_ARM 40 50 | #define EM_ALPHA 41 51 | #define EM_SH 42 52 | #define EM_SPARCV9 43 53 | #define EM_TRICORE 44 54 | #define EM_ARC 45 55 | #define EM_H8_300 46 56 | #define EM_H8_300H 47 57 | #define EM_H8S 48 58 | #define EM_H8_500 49 59 | #define EM_IA_64 50 60 | #define EM_MIPS_X 51 61 | #define EM_COLDFIRE 52 62 | #define EM_68HC12 53 63 | #define EM_MMA 54 64 | #define EM_PCP 55 65 | #define EM_NCPU 56 66 | #define EM_NDR1 57 67 | #define EM_STARCORE 58 68 | #define EM_ME16 59 69 | #define EM_ST100 60 70 | #define EM_TINYJ 61 71 | #define EM_X86_64 62 72 | #define EM_PDSP 63 73 | #define EM_PDP10 64 74 | #define EM_PDP11 65 75 | #define EM_FX66 66 76 | #define EM_ST9PLUS 67 77 | #define EM_ST7 68 78 | #define EM_68HC16 69 79 | #define EM_68HC11 70 80 | #define EM_68HC08 71 81 | #define EM_68HC05 72 82 | #define EM_SVX 73 83 | #define EM_ST19 74 84 | #define EM_VAX 75 85 | #define EM_CRIS 76 86 | #define EM_JAVELIN 77 87 | #define EM_FIREPATH 78 88 | #define EM_ZSP 79 89 | #define EM_MMIX 80 90 | #define EM_HUANY 81 91 | #define EM_PRISM 82 92 | #define EM_AVR 83 93 | #define EM_FR30 84 94 | #define EM_D10V 85 95 | #define EM_D30V 86 96 | #define EM_V850 87 97 | #define EM_M32R 88 98 | #define EM_MN10300 89 99 | #define EM_MN10200 90 100 | #define EM_PJ 91 101 | #define EM_OPENRISC 92 102 | #define EM_ARC_COMPACT 93 103 | #define EM_XTENSA 94 104 | #define EM_VIDEOCORE 95 105 | #define EM_TMM_GPP 96 106 | #define EM_NS32K 97 107 | #define EM_TPC 98 108 | #define EM_SNP1K 99 109 | #define EM_ST200 100 110 | #define EM_IP2K 101 111 | #define EM_MAX 102 112 | #define EM_CR 103 113 | #define EM_F2MC16 104 114 | #define EM_MSP430 105 115 | #define EM_BLACKFIN 106 116 | #define EM_SE_C33 107 117 | #define EM_SEP 108 118 | #define EM_ARCA 109 119 | #define EM_UNICORE 110 120 | #define EM_EXCESS 111 121 | #define EM_DXP 112 122 | #define EM_ALTERA_NIOS2 113 123 | #define EM_CRX 114 124 | #define EM_XGATE 115 125 | #define EM_C166 116 126 | #define EM_M16C 117 127 | #define EM_DSPIC30F 118 128 | #define EM_CE 119 129 | #define EM_M32C 120 130 | #define EM_TSK3000 131 131 | #define EM_RS08 132 132 | #define EM_SHARC 133 133 | #define EM_ECOG2 134 134 | #define EM_SCORE7 135 135 | #define EM_DSP24 136 136 | #define EM_VIDEOCORE3 137 137 | #define EM_LATTICEMICO32 138 138 | #define EM_SE_C17 139 139 | #define EM_TI_C6000 140 140 | #define EM_TI_C2000 141 141 | #define EM_TI_C5500 142 142 | #define EM_TI_ARP32 143 143 | #define EM_TI_PRU 144 144 | #define EM_MMDSP_PLUS 160 145 | #define EM_MMDSP_PLUS 160 146 | #define EM_CYPRESS_M8C 161 147 | #define EM_R32C 162 148 | #define EM_TRIMEDIA 163 149 | #define EM_QDSP6 164 150 | #define EM_8051 165 151 | #define EM_STXP7X 166 152 | #define EM_NDS32 167 153 | #define EM_ECOG1 168 154 | #define EM_ECOG1X 168 155 | #define EM_MAXQ30 169 156 | #define EM_XIMO16 170 157 | #define EM_MANIK 171 158 | #define EM_CRAYNV2 172 159 | #define EM_RX 173 160 | #define EM_METAG 174 161 | #define EM_MCST_ELBRUS 175 162 | #define EM_ECOG16 176 163 | #define EM_CR16 177 164 | #define EM_ETPU 178 165 | #define EM_SLE9X 179 166 | #define EM_L10M 180 167 | #define EM_K10M 181 168 | #define EM_AARCH64 183 169 | #define EM_AVR32 185 170 | #define EM_STM8 186 171 | #define EM_TILE64 187 172 | #define EM_TILEPRO 188 173 | #define EM_MICROBLAZE 189 174 | #define EM_CUDA 190 175 | #define EM_TILEGX 191 176 | #define EM_CLOUDSHIELD 192 177 | #define EM_COREA_1ST 193 178 | #define EM_COREA_2ND 194 179 | #define EM_ARC_COMPACT2 195 180 | #define EM_OPEN8 196 181 | #define EM_RL78 197 182 | #define EM_VIDEOCORE5 198 183 | #define EM_78KOR 199 184 | #define EM_56800EX 200 185 | #define EM_BA1 201 186 | #define EM_BA2 202 187 | #define EM_XCORE 203 188 | #define EM_MCHP_PIC 204 189 | #define EM_INTEL205 205 190 | #define EM_INTEL206 206 191 | #define EM_INTEL207 207 192 | #define EM_INTEL208 208 193 | #define EM_INTEL209 209 194 | #define EM_KM32 210 195 | #define EM_KMX32 211 196 | #define EM_KMX16 212 197 | #define EM_KMX8 213 198 | #define EM_KVARC 214 199 | #define EM_CDP 215 200 | #define EM_COGE 216 201 | #define EM_COOL 217 202 | #define EM_NORC 218 203 | #define EM_CSR_KALIMBA 219 204 | #define EM_Z80 220 205 | #define EM_VISIUM 221 206 | #define EM_FT32 222 207 | #define EM_MOXIE 223 208 | #define EM_AMDGPU 224 209 | #define EM_RISCV 243 210 | 211 | // e_version identifiers 212 | #define EV_NONE 0 213 | #define EV_CURRENT 1 214 | 215 | // e_ident indices 216 | #define EI_MAG0 0 217 | #define EI_MAG1 1 218 | #define EI_MAG2 2 219 | #define EI_MAG3 3 220 | #define EI_CLASS 4 221 | #define EI_DATA 5 222 | #define EI_VERSION 6 223 | #define EI_OSABI 7 224 | #define EI_ABIVERSION 8 225 | #define EI_PAD 9 226 | #define EI_NIDENT 16 227 | 228 | // e_ident values 229 | #define ELFMAG0 0x7f 230 | #define ELFMAG1 'E' 231 | #define ELFMAG2 'L' 232 | #define ELFMAG3 'F' 233 | #define ELFCLASSNONE 0 234 | #define ELFCLASS32 1 235 | #define ELFCLASS64 2 236 | #define ELFDATANONE 0 237 | #define ELFDATA2LSB 1 238 | #define ELFDATA2MSB 2 239 | #define ELFOSABI_NONE 0 240 | #define ELFOSABI_HPUX 1 241 | #define ELFOSABI_NETBSD 2 242 | #define ELFOSABI_GNU 3 243 | #define ELFOSABI_LINUX 3 244 | #define ELFOSABI_SOLARIS 6 245 | #define ELFOSABI_AIX 7 246 | #define ELFOSABI_IRIX 8 247 | #define ELFOSABI_FREEBSD 9 248 | #define ELFOSABI_TRU64 10 249 | #define ELFOSABI_MODESTO 11 250 | #define ELFOSABI_OPENBSD 12 251 | #define ELFOSABI_OPENVMS 13 252 | #define ELFOSABI_NSK 14 253 | #define ELFOSABI_AROS 15 254 | #define ELFOSABI_FENIXOS 16 255 | #define ELFOSABI_CLOUDABI 17 256 | #define ELFOSABI_OPENVOS 18 257 | 258 | // special section header indices 259 | #define SHN_UNDEF 0x0000 260 | #define SHN_LORESERVE 0xff00 261 | #define SHN_LOPROC 0xff00 262 | #define SHN_HIPROC 0xff1f 263 | #define SHN_LOOS 0xff20 264 | #define SHN_HIOS 0xff3f 265 | #define SHN_ABS 0xfff1 266 | #define SHN_COMMON 0xfff2 267 | #define SHN_XINDEX 0xffff 268 | #define SHN_HIRESERVE 0xffff 269 | 270 | // sh_type values 271 | #define SHT_NULL 0 272 | #define SHT_PROGBITS 1 273 | #define SHT_SYMTAB 2 274 | #define SHT_STRTAB 3 275 | #define SHT_RELA 4 276 | #define SHT_HASH 5 277 | #define SHT_DYNAMIC 6 278 | #define SHT_NOTE 7 279 | #define SHT_NOBITS 8 280 | #define SHT_REL 9 281 | #define SHT_SHLIB 10 282 | #define SHT_DYNSYM 11 283 | #define SHT_INIT_ARRAY 14 284 | #define SHT_FINI_ARRAY 15 285 | #define SHT_PREINIT_ARRAY 16 286 | #define SHT_GROUP 17 287 | #define SHT_SYMTAB_SHNDX 18 288 | #define SHT_LOOS 0x60000000 289 | #define SHT_GNU_HASH 0x6ffffff6 290 | #define SHT_HIOS 0x6fffffff 291 | #define SHT_LOPROC 0x70000000 292 | #define SHT_X86_64_UNWIND 0x70000001 293 | #define SHT_HIPROC 0x7fffffff 294 | #define SHT_LOUSER 0x80000000 295 | #define SHT_HIUSER 0xffffffff 296 | 297 | // sh_flags values 298 | #define SHF_WRITE 0x1 299 | #define SHF_ALLOC 0x2 300 | #define SHF_EXECINSTR 0x4 301 | #define SHF_MERGE 0x10 302 | #define SHF_STRINGS 0x20 303 | #define SHF_INFO_LINK 0x40 304 | #define SHF_LINK_ORDER 0x80 305 | #define SHF_OS_NONCONFORMING 0x100 306 | #define SHF_GROUP 0x200 307 | #define SHF_TLS 0x400 308 | #define SHF_COMPRESSED 0x800 309 | #define SHF_MASKOS 0x0ff00000 310 | #define SHF_MASKPROC 0xf0000000 311 | #define SHF_X86_64_LARGE 0x10000000 312 | 313 | // ch_type values 314 | #define ELFCOMPRESS_ZLIB 1 315 | #define ELFCOMPRESS_LOOS 0x60000000 316 | #define ELFCOMPRESS_HIOS 0x6fffffff 317 | #define ELFCOMPRESS_LOPROC 0x70000000 318 | #define ELFCOMPRESS_HIPROC 0x7fffffff 319 | 320 | // section group flags 321 | #define GRP_COMDAT 0x1 322 | #define GRP_MASKOS 0x0ff00000 323 | #define GRP_MASKPROC 0xf0000000 324 | 325 | // special symbol table indices 326 | #define STN_UNDEF 0 327 | 328 | // st_info fields 329 | #define ELF64_ST_BIND(i) ((i)>>4) 330 | #define ELF64_ST_TYPE(i) ((i)&0xf) 331 | #define ELF64_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) 332 | 333 | // st_other fields 334 | #define ELF64_ST_VISIBILITY(o) ((o)&0x3) 335 | 336 | // st_info binding 337 | #define STB_LOCAL 0 338 | #define STB_GLOBAL 1 339 | #define STB_WEAK 2 340 | #define STB_LOOS 10 341 | #define STB_HIOS 12 342 | #define STB_LOPROC 13 343 | #define STB_HIPROC 15 344 | 345 | // st_info type 346 | #define STT_NOTYPE 0 347 | #define STT_OBJECT 1 348 | #define STT_FUNC 2 349 | #define STT_SECTION 3 350 | #define STT_FILE 4 351 | #define STT_COMMON 5 352 | #define STT_TLS 6 353 | #define STT_LOOS 10 354 | #define STT_HIOS 12 355 | #define STT_LOPROC 13 356 | #define STT_HIPROC 15 357 | 358 | // st_info visibility 359 | #define STV_DEFAULT 0 360 | #define STV_INTERNAL 1 361 | #define STV_HIDDEN 2 362 | #define STV_PROTECTED 3 363 | 364 | // r_info field extraction 365 | #define ELF64_R_SYM(i) ((i)>>32) 366 | #define ELF64_R_TYPE(i) ((i)&0xffffffffL) 367 | #define ELF64_R_INFO(s,t) (((s)<<32)+((t)&0xffffffffL)) 368 | 369 | // x86-64 relocation types 370 | #define R_X86_64_NONE 0 // none none 371 | #define R_X86_64_64 1 // word64 S + A 372 | #define R_X86_64_PC32 2 // word32 S + A - P 373 | #define R_X86_64_GOT32 3 // word32 G + A 374 | #define R_X86_64_PLT32 4 // word32 L + A - P 375 | #define R_X86_64_COPY 5 // none none 376 | #define R_X86_64_GLOB_DAT 6 // word64 S 377 | #define R_X86_64_JUMP_SLOT 7 // word64 S 378 | #define R_X86_64_RELATIVE 8 // word64 B + A 379 | #define R_X86_64_GOTPCREL 9 // word32 G + GOT + A - P 380 | #define R_X86_64_32 10 // word32 S + A 381 | #define R_X86_64_32S 11 // word32 S + A 382 | #define R_X86_64_16 12 // word16 S + A 383 | #define R_X86_64_PC16 13 // word16 S + A - P 384 | #define R_X86_64_8 14 // word8 S + A 385 | #define R_X86_64_PC8 15 // word8 S + A - P 386 | #define R_X86_64_DTPMOD64 16 // word64 387 | #define R_X86_64_DTPOFF64 17 // word64 388 | #define R_X86_64_TPOFF64 18 // word64 389 | #define R_X86_64_TLSGD 19 // word32 390 | #define R_X86_64_TLSLD 20 // word32 391 | #define R_X86_64_DTPOFF32 21 // word32 392 | #define R_X86_64_GOTTPOFF 22 // word32 393 | #define R_X86_64_TPOFF32 23 // word32 394 | #define R_X86_64_PC64 24 // word64 S + A - P 395 | #define R_X86_64_GOTOFF64 25 // word64 S + A - GOT 396 | #define R_X86_64_GOTPC32 26 // word32 GOT + A - P 397 | #define R_X86_64_GOT64 27 // word64 G + A 398 | #define R_X86_64_GOTPCREL64 28 // word64 G + GOT - P + A 399 | #define R_X86_64_GOTPC64 29 // word64 GOT - P + A 400 | #define R_X86_64_GOTPLT64 30 // word64 G + A 401 | #define R_X86_64_PLTOFF64 31 // word64 L - GOT + A 402 | #define R_X86_64_SIZE32 32 // word32 Z + A 403 | #define R_X86_64_SIZE64 33 // word64 Z + A 404 | #define R_X86_64_GOTPC32_TLSDESC 34 // word32 405 | #define R_X86_64_TLSDESC_CALL 35 // none 406 | #define R_X86_64_TLSDESC 36 // word64×2 407 | #define R_X86_64_IRELATIVE 37 // word64 indirect (B + A) 408 | 409 | // p_type values 410 | #define PT_NULL 0 411 | #define PT_LOAD 1 412 | #define PT_DYNAMIC 2 413 | #define PT_INTERP 3 414 | #define PT_NOTE 4 415 | #define PT_SHLIB 5 416 | #define PT_PHDR 6 417 | #define PT_TLS 7 418 | #define PT_LOOS 0x60000000 419 | #define PT_HIOS 0x6fffffff 420 | #define PT_LOPROC 0x70000000 421 | #define PT_HIPROC 0x7fffffff 422 | 423 | // p_flags values 424 | #define PF_X 0x00000001 425 | #define PF_W 0x00000002 426 | #define PF_R 0x00000004 427 | #define PF_MASKOS 0x0ff00000 428 | #define PF_MASKPROC 0xf0000000 429 | 430 | // d_tag values 431 | #define DT_NULL 0 432 | #define DT_NEEDED 1 433 | #define DT_PLTRELSZ 2 434 | #define DT_PLTGOT 3 435 | #define DT_HASH 4 436 | #define DT_STRTAB 5 437 | #define DT_SYMTAB 6 438 | #define DT_RELA 7 439 | #define DT_RELASZ 8 440 | #define DT_RELAENT 9 441 | #define DT_STRSZ 10 442 | #define DT_SYMENT 11 443 | #define DT_INIT 12 444 | #define DT_FINI 13 445 | #define DT_SONAME 14 446 | #define DT_RPATH 15 447 | #define DT_SYMBOLIC 16 448 | #define DT_REL 17 449 | #define DT_RELSZ 18 450 | #define DT_RELENT 19 451 | #define DT_PLTREL 20 452 | #define DT_DEBUG 21 453 | #define DT_TEXTREL 22 454 | #define DT_JMPREL 23 455 | #define DT_BIND_NOW 24 456 | #define DT_INIT_ARRAY 25 457 | #define DT_FINI_ARRAY 26 458 | #define DT_INIT_ARRAYSZ 27 459 | #define DT_FINI_ARRAYSZ 28 460 | #define DT_RUNPATH 29 461 | #define DT_FLAGS 30 462 | #define DT_ENCODING 32 463 | #define DT_PREINIT_ARRAY 32 464 | #define DT_PREINIT_ARRAYSZ 33 465 | #define DT_SYMTAB_SHNDX 34 466 | #define DT_LOOS 0x6000000D 467 | #define DT_HIOS 0x6ffff000 468 | #define DT_LOPROC 0x70000000 469 | #define DT_HIPROC 0x7fffffff 470 | 471 | // DT_FLAGS values 472 | #define DF_ORIGIN 0x01 473 | #define DF_SYMBOLIC 0x02 474 | #define DF_TEXTREL 0x04 475 | #define DF_BIND_NOW 0x08 476 | #define DF_STATIC_TLS 0x10 477 | 478 | // aux entries 479 | #define AT_NULL 0 480 | #define AT_IGNORE 1 481 | #define AT_EXECFD 2 482 | #define AT_PHDR 3 483 | #define AT_PHENT 4 484 | #define AT_PHNUM 5 485 | #define AT_PAGESZ 6 486 | #define AT_BASE 7 487 | #define AT_FLAGS 8 488 | #define AT_ENTRY 9 489 | #define AT_NOTELF 10 490 | #define AT_UID 11 491 | #define AT_EUID 12 492 | #define AT_GID 13 493 | #define AT_EGID 14 494 | #define AT_CLKTCK 17 495 | #define AT_PLATFORM 15 496 | #define AT_HWCAP 16 497 | #define AT_FPUCW 18 498 | #define AT_DCACHEBSIZE 19 499 | #define AT_ICACHEBSIZE 20 500 | #define AT_UCACHEBSIZE 21 501 | #define AT_IGNOREPPC 22 502 | #define AT_SECURE 23 503 | #define AT_BASE_PLATFORM 24 504 | #define AT_RANDOM 25 505 | #define AT_HWCAP2 26 506 | #define AT_EXECFN 31 507 | #define AT_SYSINFO 32 508 | #define AT_SYSINFO_EHDR 33 509 | #define AT_L1I_CACHESHAPE 34 510 | #define AT_L1D_CACHESHAPE 35 511 | #define AT_L2_CACHESHAPE 36 512 | #define AT_L3_CACHESHAPE 37 513 | #define AT_L1I_CACHESIZE 40 514 | #define AT_L1I_CACHEGEOMETRY 41 515 | #define AT_L1D_CACHESIZE 42 516 | #define AT_L1D_CACHEGEOMETRY 43 517 | #define AT_L2_CACHESIZE 44 518 | #define AT_L2_CACHEGEOMETRY 45 519 | #define AT_L3_CACHESIZE 46 520 | #define AT_L3_CACHEGEOMETRY 47 521 | #define AT_MINSIGSTKSZ 51 522 | 523 | struct Elf64_Ehdr typedef Elf64_Ehdr; 524 | struct Elf64_Ehdr { 525 | unsigned char e_ident[EI_NIDENT]; 526 | Elf64_Half e_type; 527 | Elf64_Half e_machine; 528 | Elf64_Word e_version; 529 | Elf64_Addr e_entry; 530 | Elf64_Off e_phoff; 531 | Elf64_Off e_shoff; 532 | Elf64_Word e_flags; 533 | Elf64_Half e_ehsize; 534 | Elf64_Half e_phentsize; 535 | Elf64_Half e_phnum; 536 | Elf64_Half e_shentsize; 537 | Elf64_Half e_shnum; 538 | Elf64_Half e_shstrndx; 539 | }; 540 | 541 | struct Elf64_Shdr typedef Elf64_Shdr; 542 | struct Elf64_Shdr { 543 | Elf64_Word sh_name; 544 | Elf64_Word sh_type; 545 | Elf64_Xword sh_flags; 546 | Elf64_Addr sh_addr; 547 | Elf64_Off sh_offset; 548 | Elf64_Xword sh_size; 549 | Elf64_Word sh_link; 550 | Elf64_Word sh_info; 551 | Elf64_Xword sh_addralign; 552 | Elf64_Xword sh_entsize; 553 | }; 554 | 555 | struct Elf64_Chdr typedef Elf64_Chdr; 556 | struct Elf64_Chdr { 557 | Elf64_Word ch_type; 558 | Elf64_Word ch_reserved; 559 | Elf64_Xword ch_size; 560 | Elf64_Xword ch_addralign; 561 | }; 562 | 563 | struct Elf64_Sym typedef Elf64_Sym; 564 | struct Elf64_Sym { 565 | Elf64_Word st_name; 566 | unsigned char st_info; 567 | unsigned char st_other; 568 | Elf64_Half st_shndx; 569 | Elf64_Addr st_value; 570 | Elf64_Xword st_size; 571 | }; 572 | 573 | struct Elf64_Rel typedef Elf64_Rel; 574 | struct Elf64_Rel { 575 | Elf64_Addr r_offset; 576 | Elf64_Xword r_info; 577 | }; 578 | 579 | struct Elf64_Rela typedef Elf64_Rela; 580 | struct Elf64_Rela { 581 | Elf64_Addr r_offset; 582 | Elf64_Xword r_info; 583 | Elf64_Sxword r_addend; 584 | }; 585 | 586 | struct Elf64_Phdr typedef Elf64_Phdr; 587 | struct Elf64_Phdr { 588 | Elf64_Word p_type; 589 | Elf64_Word p_flags; 590 | Elf64_Off p_offset; 591 | Elf64_Addr p_vaddr; 592 | Elf64_Addr p_paddr; 593 | Elf64_Xword p_filesz; 594 | Elf64_Xword p_memsz; 595 | Elf64_Xword p_align; 596 | }; 597 | 598 | struct Elf64_Dyn typedef Elf64_Dyn; 599 | struct Elf64_Dyn { 600 | Elf64_Sxword d_tag; 601 | union { 602 | Elf64_Xword d_val; 603 | Elf64_Addr d_ptr; 604 | } d_un; 605 | }; 606 | 607 | extern Elf64_Dyn _DYNAMIC[]; 608 | 609 | struct Elf64_Aux typedef Elf64_Aux; 610 | struct Elf64_Aux { 611 | int a_type; 612 | union { 613 | long a_val; 614 | void *a_ptr; 615 | void (*a_fcn)(); 616 | }; 617 | }; 618 | 619 | 620 | --------------------------------------------------------------------------------