My toy stop/copy GC and allocation routines just have this:
%define HEAP_SIZE (4 * 1024 * 1024 * 1024)
.section bss
;;
;; Two heaps so we can flip-flop between them
;;
heap_a:
resb HEAP_SIZE
heap_a_end:
heap_b:
resb HEAP_SIZE
heap_b_end:
Of course there are other syscalls involved in my compiler/runtime, but for memory allocations the static area sufficed for me.Nobody in their right mind (except musl) use brk(2) nowadays; mmap(2) is pretty much universally accessible, and brk() has been non-portable for more than 20 years already (POSIX ditched it in 2001) anyhow. For goodness sake, stop keeping this stupid API from VM-lacking PDP-7 alive, and let it go away!
Edit: also, I have no idea how musl even uses it:
uintptr_t new = ctx.brk + pagesize;
int need_guard = 0;
if (!ctx.brk) {
need_guard = 1;
ctx.brk = brk(0);
// some ancient kernels returned _ebss
// instead of next page as initial brk.
ctx.brk += -ctx.brk & (pagesize-1);
new = ctx.brk + 2*pagesize;
}
if (brk(new) != new) {
ctx.brk = -1;
} else {
if (need_guard) mmap((void *)ctx.brk, pagesize,
PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
ctx.brk = new;
ctx.avail_meta_areas = (void *)(new - pagesize);
ctx.avail_meta_area_count = pagesize>>12;
need_unprotect = 0;
}
That's... not what brk() returns; it returns 0 on success and -1 on failure. Huh?See the NOTES section in man brk(2):
> C library/kernel differences
> The return value described above for brk() is the behavior provided by the glibc wrapper function for the Linux brk() system call. (On most other implementations, the return value from brk() is the same; this return value was also specified in SUSv2.) However, the actual Linux system call returns the new program break on success. On failure, the system call returns the current break. The glibc wrapper function does some work (i.e., checks whether the new break is less than addr) to provide the 0 and -1 return values described above.