// VOXIS FORGE // RUMPK L0 // libc_stubs.zig // We are the standard library now. // // These C ABI functions are exported so Nim's generated C code // can link against them. No glibc. No musl. Pure sovereignty. // ========================================================= // Memory Operations (Nim needs these) // ========================================================= export fn memcpy(dest: [*]u8, src: [*]const u8, len: usize) [*]u8 { var i: usize = 0; while (i < len) : (i += 1) { dest[i] = src[i]; } return dest; } export fn memset(dest: [*]u8, val: c_int, len: usize) [*]u8 { const v: u8 = @intCast(val & 0xFF); var i: usize = 0; while (i < len) : (i += 1) { dest[i] = v; } return dest; } export fn memmove(dest: [*]u8, src: [*]const u8, len: usize) [*]u8 { if (@intFromPtr(dest) < @intFromPtr(src)) { return memcpy(dest, src, len); } // Copy backwards for overlapping regions var i: usize = len; while (i > 0) { i -= 1; dest[i] = src[i]; } return dest; } export fn memcmp(s1: [*]const u8, s2: [*]const u8, len: usize) c_int { var i: usize = 0; while (i < len) : (i += 1) { if (s1[i] != s2[i]) { return if (s1[i] < s2[i]) @as(c_int, -1) else @as(c_int, 1); } } return 0; } // ========================================================= // String Operations // ========================================================= export fn strlen(s: [*]const u8) usize { var len: usize = 0; while (s[len] != 0) : (len += 1) {} return len; } export fn strcpy(dest: [*]u8, src: [*]const u8) [*]u8 { var i: usize = 0; while (src[i] != 0) : (i += 1) { dest[i] = src[i]; } dest[i] = 0; return dest; } export fn strcmp(s1: [*]const u8, s2: [*]const u8) c_int { var i: usize = 0; while (s1[i] != 0 and s1[i] == s2[i]) : (i += 1) {} if (s1[i] == s2[i]) return 0; return if (s1[i] < s2[i]) @as(c_int, -1) else @as(c_int, 1); } // ========================================================= // Heap Stubs (Bump Allocator) // ========================================================= var heap_base: [64 * 1024]u8 = undefined; var heap_offset: usize = 0; export fn malloc(size: usize) ?*anyopaque { if (heap_offset + size > heap_base.len) { return null; } const ptr = &heap_base[heap_offset]; heap_offset += size; // Align to 8 bytes heap_offset = (heap_offset + 7) & ~@as(usize, 7); return ptr; } export fn free(ptr: ?*anyopaque) void { // Bump allocator - no deallocation _ = ptr; } export fn realloc(ptr: ?*anyopaque, size: usize) ?*anyopaque { // Simple realloc - just allocate new (wasteful but works for bootstrap) _ = ptr; return malloc(size); } export fn calloc(nmemb: usize, size: usize) ?*anyopaque { const total = nmemb * size; const ptr = malloc(total); if (ptr) |p| { _ = memset(@ptrCast(p), 0, total); } return ptr; } // ========================================================= // Stdio Stubs (Route to UART) // ========================================================= const uart = @import("uart.zig"); export fn puts(s: [*]const u8) c_int { const len = strlen(s); uart.write_bytes(s[0..len]); uart.putc('\n'); return 0; } export fn putchar(c: c_int) c_int { uart.putc(@intCast(c & 0xFF)); return c; } export fn printf(fmt: [*]const u8, ...) c_int { // Minimal printf - just output format string const len = strlen(fmt); uart.write_bytes(fmt[0..len]); return @intCast(len); } export fn fprintf(stream: ?*anyopaque, fmt: [*]const u8, ...) c_int { _ = stream; return printf(fmt); } export fn fflush(stream: ?*anyopaque) c_int { _ = stream; return 0; } export fn fwrite(ptr: [*]const u8, size: usize, nmemb: usize, stream: ?*anyopaque) usize { _ = stream; uart.write_bytes(ptr[0 .. size * nmemb]); return nmemb; } // ========================================================= // Signal Stubs (No signals in freestanding) // ========================================================= export fn signal(signum: c_int, handler: ?*anyopaque) ?*anyopaque { _ = signum; _ = handler; return null; } export fn raise(sig: c_int) c_int { _ = sig; return 0; } // ========================================================= // Exit Stubs // ========================================================= fn halt() noreturn { while (true) { asm volatile ("wfi"); } } export fn exit(status: c_int) noreturn { _ = status; uart.puts("[RUMPK] exit() called - halt\n"); halt(); } export fn abort() noreturn { uart.puts("[RUMPK] abort() called - halt\n"); halt(); } export fn _Exit(status: c_int) noreturn { exit(status); }