// Bump allocator over the kernel's brk/sbrk syscalls — the heap layer // of flibc. State-free by design: every malloc(n) is a thin // sys_sbrk(+aligned_n) wrapper that returns the previous break as the // pointer to the freshly-allocated region. No internal bookkeeping // means flibc itself emits no `.bss` / `.data`, which keeps consuming // ELF demos at one PT_LOAD. // // The kernel's sys_brk rounds every break to PAGE_SIZE, so this // allocator wastes (PAGE_SIZE - aligned_n) bytes per call when the // caller asks for less than a page. That's intentional for the demo- // scale userland flibc targets today; a proper free-list / per-page // sub-allocator is future work once `fsh` and the demo programs need // many small allocations. use "syscalls" as sys const ALIGN u64 = 8 /// malloc(n) — return a pointer to a freshly-allocated region of at /// least `n` bytes (rounded up to 8). Returns null on failure /// (kernel rejects out-of-bounds break, propagated as a negative sbrk /// return). The memory is zeroed by the kernel's get_free_page on first /// touch via the do_data_abort demand-alloc path. /// /// C `malloc(0)` is implementation-defined; flibc returns null. /// Callers must distinguish `len == 0` themselves before treating /// null as failure. pub fn malloc(n u64) ?[*]mut u8 { if n == 0 { return null } const aligned u64 = (n + ALIGN - 1) & ~(ALIGN - 1) const prev = sys.sbrk(#intCast(aligned)) if prev < 0 { return null } return #ptrFromInt(#as(u64, #bitCast(prev))) } /// free — no-op. The bump allocator never reclaims individual /// allocations; the kernel reaps the entire heap on process exit /// (do_wait clears every page in `mm.user_pages`). Provided so consumers /// can keep the alloc/free pairing readable even though the call is /// inert. pub fn free(_ ?[*]mut u8) void {}