Flash 45 lines
// 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) {}