From 6a5543bb8f1f535ca49737bcd7be0cafca3b2a08 Mon Sep 17 00:00:00 2001 From: hachem Date: Mon, 12 Oct 2026 23:08:48 +0200 Subject: feat: lib sea --- sysroot/usr/lib/libc/crt0.c | 28 ++++++ sysroot/usr/lib/libc/stdio.c | 211 ++++++++++++++++++++++++++++++++++++++++ sysroot/usr/lib/libc/stdlib.c | 185 +++++++++++++++++++++++++++++++++++ sysroot/usr/lib/libc/string.c | 92 ++++++++++++++++++ sysroot/usr/lib/libc/syscalls.c | 38 ++++++++ 5 files changed, 554 insertions(+) create mode 100644 sysroot/usr/lib/libc/crt0.c create mode 100644 sysroot/usr/lib/libc/stdio.c create mode 100644 sysroot/usr/lib/libc/stdlib.c create mode 100644 sysroot/usr/lib/libc/string.c create mode 100644 sysroot/usr/lib/libc/syscalls.c (limited to 'sysroot/usr/lib/libc') diff --git a/sysroot/usr/lib/libc/crt0.c b/sysroot/usr/lib/libc/crt0.c new file mode 100644 index 0000000..16c3a94 --- /dev/null +++ b/sysroot/usr/lib/libc/crt0.c @@ -0,0 +1,28 @@ +#include + +extern int main(int argc, char** argv); + +void _start(const char* arg, unsigned long arglen) +{ + static char arg_buffer[256]; + char* argv[3]; + int argc = 1; + argv[0] = ""; + + if (arglen > 0) + { + unsigned long count = arglen; + if (count > sizeof(arg_buffer) - 1) + count = sizeof(arg_buffer) - 1; + for (unsigned long i = 0; i < count; i++) + arg_buffer[i] = arg[i]; + arg_buffer[count] = 0; + argv[1] = arg_buffer; + argc = 2; + } + else + argv[1] = NULL; + + argv[argc] = NULL; + exit(main(argc, argv)); +} diff --git a/sysroot/usr/lib/libc/stdio.c b/sysroot/usr/lib/libc/stdio.c new file mode 100644 index 0000000..d0e7ad7 --- /dev/null +++ b/sysroot/usr/lib/libc/stdio.c @@ -0,0 +1,211 @@ +#include +#include +#include +#include + +int putchar(int character) +{ + char byte = (char)character; + if (write(1, &byte, 1) != 1) + return EOF; + return (unsigned char)byte; +} + +int getchar(void) +{ + char byte; + if (read(0, &byte, 1) <= 0) + return EOF; + return (unsigned char)byte; +} + +int puts(const char* string) +{ + (void)write(1, string, strlen(string)); + (void)write(1, "\n", 1); + return 0; +} + +static int format_unsigned(char* buffer, unsigned long value, int base, int upper) +{ + const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + char temp[32]; + int count = 0; + if (value == 0) + temp[count++] = '0'; + while (value > 0) + { + temp[count++] = digits[value % (unsigned)base]; + value /= (unsigned)base; + } + for (int i = 0; i < count; i++) + buffer[i] = temp[count - 1 - i]; + return count; +} + +static int format_signed(char* buffer, long value) +{ + int negative = value < 0; + unsigned long magnitude = negative ? (unsigned long)(-value) : (unsigned long)value; + int count = 0; + if (negative) + buffer[count++] = '-'; + return count + format_unsigned(buffer + count, magnitude, 10, 0); +} + +#define PRINTF_BUFFER 256 + +// yoinked straight off open source +int printf(const char* format, ...) +{ + char out[PRINTF_BUFFER]; + int filled = 0; + int total = 0; + va_list args; + va_start(args, format); + +#define FLUSH() \ + do { \ + if (filled > 0) \ + { \ + (void)write(1, out, filled); \ + filled = 0; \ + } \ + } while (0) +#define EMIT(ch) \ + do { \ + if (filled == PRINTF_BUFFER) \ + FLUSH(); \ + out[filled++] = (char)(ch); \ + total++; \ + } while (0) + + for (const char* cursor = format; *cursor; cursor++) + { + if (*cursor != '%') + { + EMIT(*cursor); + continue; + } + + cursor++; + if (*cursor == '%') + { + EMIT('%'); + continue; + } + + int zero_pad = 0; + if (*cursor == '0') + { + zero_pad = 1; + cursor++; + } + int width = 0; + while (*cursor >= '0' && *cursor <= '9') + { + width = width * 10 + (*cursor - '0'); + cursor++; + } + int is_long = 0; + while (*cursor == 'l') + { + is_long = 1; + cursor++; + } + + char conversion = *cursor; + if (conversion == 's') + { + const char* string = va_arg(args, const char*); + if (!string) + string = "(null)"; + int length = (int)strlen(string); + for (int i = length; i < width; i++) + EMIT(' '); + for (int i = 0; i < length; i++) + EMIT(string[i]); + continue; + } + if (conversion == 'c') + { + int character = va_arg(args, int); + for (int i = 1; i < width; i++) + EMIT(' '); + EMIT(character); + continue; + } + + char number[34]; + int length = 0; + if (conversion == 'd' || conversion == 'i') + { + long value = is_long ? va_arg(args, long) : (long)va_arg(args, int); + length = format_signed(number, value); + } + else if (conversion == 'u') + { + unsigned long value = is_long ? va_arg(args, unsigned long) : (unsigned long)va_arg(args, unsigned int); + length = format_unsigned(number, value, 10, 0); + } + else if (conversion == 'x' || conversion == 'X') + { + unsigned long value = is_long ? va_arg(args, unsigned long) : (unsigned long)va_arg(args, unsigned int); + length = format_unsigned(number, value, 16, conversion == 'X'); + } + else if (conversion == 'p') + { + unsigned long value = (unsigned long)va_arg(args, void*); + EMIT('0'); + EMIT('x'); + length = format_unsigned(number, value, 16, 0); + } + else + { + EMIT('%'); + EMIT(conversion); + continue; + } + + for (int i = length; i < width; i++) + EMIT(zero_pad ? '0' : ' '); + for (int i = 0; i < length; i++) + EMIT(number[i]); + } + + FLUSH(); + va_end(args); + return total; + +#undef EMIT +#undef FLUSH +} + +int readline(char* buffer, int max_length) +{ + int length = 0; + for (;;) + { + char character; + if (read(0, &character, 1) <= 0) + break; + if (character == '\n') + break; + if (character == '\b') + { + if (length > 0) + { + length--; + (void)write(1, "\b \b", 3); + } + continue; + } + if (length < max_length - 1) + { + buffer[length++] = character; + (void)write(1, &character, 1); + } + } + buffer[length] = 0; + return length; +} diff --git a/sysroot/usr/lib/libc/stdlib.c b/sysroot/usr/lib/libc/stdlib.c new file mode 100644 index 0000000..a0a86b9 --- /dev/null +++ b/sysroot/usr/lib/libc/stdlib.c @@ -0,0 +1,185 @@ +#include +#include +#include + +#define HEAP_HEADER 16UL +#define HEAP_ALIGN 16UL +#define HEAP_MIN 32UL +#define HEAP_CHUNK (64UL * 1024UL) + +static unsigned long heap_start = 0; +static unsigned long heap_end = 0; +static unsigned long heap_rover = 0; + +static unsigned long heap_block_size(unsigned long block) +{ + return *(unsigned long*)block & ~15UL; +} + +static int heap_block_used(unsigned long block) +{ + return (int)(*(unsigned long*)block & 1UL); +} + +static void heap_set(unsigned long block, unsigned long size, int used) +{ + *(unsigned long*)block = size | (used ? 1UL : 0UL); +} + +static unsigned long heap_align(unsigned long value) +{ + return (value + HEAP_ALIGN - 1UL) & ~(HEAP_ALIGN - 1UL); +} + +// pull another hunk off sbrk and drop a free block over it +static int heap_grow(unsigned long need) +{ + unsigned long want = heap_align(need); + if (want < HEAP_CHUNK) + want = HEAP_CHUNK; + unsigned long got = (unsigned long)sbrk((long)want); + if ((long)got < 0) + return 0; + if (heap_start == 0) + { + heap_start = got; + heap_end = got; + heap_rover = got; + } + heap_set(heap_end, want, 0); + heap_end += want; + return 1; +} + +// fire O(n) malloc implementation frfr +void* malloc(size_t length) +{ + if (length == 0) + return NULL; + unsigned long need = heap_align(HEAP_HEADER + length); + if (need < HEAP_MIN) + need = HEAP_MIN; + + for (;;) + { + if (heap_rover < heap_start || heap_rover >= heap_end) + heap_rover = heap_start; + unsigned long block = heap_rover; + unsigned long limit = heap_end; + for (int pass = 0; pass < 2; pass++) + { + while (block < limit) + { + if (!heap_block_used(block)) + { + // lazily coalesce the free run starting here + unsigned long size = heap_block_size(block); + while (block + size < heap_end && !heap_block_used(block + size)) + size += heap_block_size(block + size); + heap_set(block, size, 0); + if (size >= need) + { + if (size >= need + HEAP_MIN) + { + heap_set(block, need, 1); + heap_set(block + need, size - need, 0); + heap_rover = block + need; + } + else + { + heap_set(block, size, 1); + heap_rover = block + size; + } + if (heap_rover >= heap_end) + heap_rover = heap_start; + return (void*)(block + HEAP_HEADER); + } + } + block += heap_block_size(block); + } + block = heap_start; + limit = heap_rover; + } + if (!heap_grow(need)) + return NULL; + } +} + +void free(void* pointer) +{ + if (pointer == NULL) + return; + unsigned long block = (unsigned long)pointer - HEAP_HEADER; + heap_set(block, heap_block_size(block), 0); +} + +void* calloc(size_t count, size_t size) +{ + unsigned long total = (unsigned long)count * (unsigned long)size; + unsigned char* bytes = malloc(total); + if (bytes) + for (unsigned long i = 0; i < total; i++) + bytes[i] = 0; + return bytes; +} + +void* realloc(void* pointer, size_t length) +{ + if (pointer == NULL) + return malloc(length); + if (length == 0) + { + free(pointer); + return NULL; + } + unsigned long block = (unsigned long)pointer - HEAP_HEADER; + unsigned long have = heap_block_size(block) - HEAP_HEADER; + if (length <= have) + return pointer; + unsigned char* grown = malloc(length); + if (!grown) + return NULL; + unsigned char* source = pointer; + for (unsigned long i = 0; i < have; i++) + grown[i] = source[i]; + free(pointer); + return grown; +} + +void exit(int code) +{ + __syscall1(SYS_exit, code); + for (;;) + ; +} + +long atol(const char* string) +{ + while (*string == ' ' || *string == '\t') + string++; + int negative = 0; + if (*string == '-') + { + negative = 1; + string++; + } + else if (*string == '+') + string++; + long value = 0; + while (*string >= '0' && *string <= '9') + { + value = value * 10 + (*string - '0'); + string++; + } + return negative ? -value : value; +} + +int atoi(const char* string) +{ + return (int)atol(string); +} + +int abs(int value) +{ + return value < 0 ? -value : value; +} diff --git a/sysroot/usr/lib/libc/string.c b/sysroot/usr/lib/libc/string.c new file mode 100644 index 0000000..7bbc0c2 --- /dev/null +++ b/sysroot/usr/lib/libc/string.c @@ -0,0 +1,92 @@ +#include + +size_t strlen(const char* string) +{ + size_t length = 0; + while (string[length]) + length++; + return length; +} + +int strcmp(const char* a, const char* b) +{ + while (*a && *a == *b) + { + a++; + b++; + } + + return (int)(unsigned char)*a - (int)(unsigned char)*b; +} + +int strncmp(const char* a, const char* b, size_t length) +{ + for (size_t i = 0; i < length; i++) + { + unsigned char ca = (unsigned char)a[i]; + unsigned char cb = (unsigned char)b[i]; + if (ca != cb) + return (int)ca - (int)cb; + if (ca == 0) + return 0; + } + return 0; +} + +char* strcpy(char* destination, const char* source) +{ + char* out = destination; + while ((*out++ = *source++)) + ; + return destination; +} + +char* strncpy(char* destination, const char* source, size_t length) +{ + size_t i = 0; + for (; i < length && source[i]; i++) + destination[i] = source[i]; + for (; i < length; i++) + destination[i] = 0; + return destination; +} + +void* memcpy(void* destination, const void* source, size_t length) +{ + unsigned char* out = destination; + const unsigned char* in = source; + for (size_t i = 0; i < length; i++) + out[i] = in[i]; + return destination; +} + +void* memmove(void* destination, const void* source, size_t length) +{ + unsigned char* out = destination; + const unsigned char* in = source; + if (out < in) + for (size_t i = 0; i < length; i++) + out[i] = in[i]; + else + for (size_t i = length; i > 0; i--) + out[i - 1] = in[i - 1]; + return destination; +} + +void* memset(void* destination, int value, size_t length) +{ + unsigned char* out = destination; + for (size_t i = 0; i < length; i++) + out[i] = (unsigned char)value; + return destination; +} + +int memcmp(const void* a, const void* b, size_t length) +{ + const unsigned char* aa = a; + const unsigned char* bb = b; + for (size_t i = 0; i < length; i++) + if (aa[i] != bb[i]) + return (int)aa[i] - (int)bb[i]; + return 0; +} diff --git a/sysroot/usr/lib/libc/syscalls.c b/sysroot/usr/lib/libc/syscalls.c new file mode 100644 index 0000000..ad959b9 --- /dev/null +++ b/sysroot/usr/lib/libc/syscalls.c @@ -0,0 +1,38 @@ +#include +#include +#include + +long read(int fd, void* buffer, size_t length) +{ + return __syscall3(SYS_read, fd, (long)buffer, (long)length); +} + +long write(int fd, const void* buffer, size_t length) +{ + return __syscall3(SYS_write, fd, (long)buffer, (long)length); +} + +int open(const char* path, int flags) +{ + return (int)__syscall2(SYS_open, (long)path, flags); +} + +int close(int fd) +{ + return (int)__syscall1(SYS_close, fd); +} + +long lseek(int fd, long offset, int whence) +{ + return __syscall3(SYS_lseek, fd, offset, whence); +} + +void* sbrk(long increment) +{ + return (void*)__syscall1(SYS_sbrk, increment); +} + +int brk(void* address) +{ + return (int)__syscall1(SYS_brk, (long)address); +} -- cgit v1.3