hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/sysroot/usr/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'sysroot/usr/lib/libc')
-rw-r--r--sysroot/usr/lib/libc/crt0.c28
-rw-r--r--sysroot/usr/lib/libc/stdio.c211
-rw-r--r--sysroot/usr/lib/libc/stdlib.c185
-rw-r--r--sysroot/usr/lib/libc/string.c92
-rw-r--r--sysroot/usr/lib/libc/syscalls.c38
5 files changed, 554 insertions, 0 deletions
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 <stdlib.h>
+
+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 <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+
+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 <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#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 <string.h>
+
+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 <unistd.h>
+#include <fcntl.h>
+#include <sys/syscall.h>
+
+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);
+}