// heap — flibc's bump allocator over the kernel's brk/sbrk syscalls, ported // to Flash from the hand-written Zig. 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. `free` is an inert no-op — the kernel reaps the whole heap on // process exit. // // The port that surfaces the unary bitwise-NOT `~`, used to build the 8-byte // alignment mask `~(ALIGN - 1)`. Imports `syscalls.zig` through the sibling // file form. The `///` doc comments carry through verbatim; the `//` header is // dropped, and the two single-statement `if`s lower with mandatory braces. 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) 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) {}