hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/sysroot/usr/lib/libc/stdlib.c
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-10-12 23:08:48 +0200
committerhachem <im@hachem.wtf>2026-10-12 23:08:48 +0200
commit6a5543bb8f1f535ca49737bcd7be0cafca3b2a08 (patch)
treebb137b732a1d122aeace46c550733f4793d84601 /sysroot/usr/lib/libc/stdlib.c
parent59794d0b999e544a94230d9562bf2b99d2ed74c7 (diff)
feat: lib seaHEADmain
Diffstat (limited to 'sysroot/usr/lib/libc/stdlib.c')
-rw-r--r--sysroot/usr/lib/libc/stdlib.c185
1 files changed, 185 insertions, 0 deletions
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;
+}