Hare's canonical runtime allocator is rt::malloc with linker symbol
rt.malloc (ref/hare/rt/malloc.ha:27,78). ww kept the dot→underscore
Plan 9 convention (CLAUDE.md rule 4) so the linker symbol becomes
rt_malloc; the lib/rt exported function name becomes malloc; ww
callers say rt.malloc(...).
The language builtin keyword stays `alloc(T)!` — unchanged from Hare
(ref/hare/hare/lex/token.ha:21 ltok::ALLOC, parse/expr.ha:398
builtin()). The rename only touches the lowered linker symbol and the
exported function name behind it; the user-facing syntax for
heap-allocation is identical to Hare.
Surface:
- rt/alloc.s: TEXT rt_alloc → TEXT rt_malloc, labels updated
- lib/rt/malloc.ww: @symbol("rt_malloc") fn malloc(...) (was rt_alloc/alloc)
- rt/ensure.ww: local FFI decl + call site updated to malloc; `!` dropped
on the direct FFI call (rt_malloc returns *void, not a tagged union)
- 18 .ww callers: rt.alloc(...) → rt.malloc(...)
- cstage cmd/wcc/check.c + wwstage selfhost/cmd/wcc/check.ww
alloc-builtin suppression gate routes through ffi_resolve("malloc")
for the lowering; the user-shadow check still keys on the BUILTIN
KEYWORD "alloc" since that is what `alloc(...)` parses as. Adding
"malloc" to the user-shadow check was unnecessary and was reverted
during pre-commit review.
- cstage cmd/w6c/cgen.c: 2× ffi_resolve("alloc") → ffi_resolve("malloc")
- wwstage cgenexpr/cgenstmt: 2× ffiresolve(c, "alloc") → ffiresolve(c, "malloc")
- Test fixtures (700_e2e, 758_cgalloc_str_field, 990_selfhost, 992_w6l_ww,
selfhost/test/tagged_ptr_ret.ww): updated inline ww sources to the new
decl + call form
This is commit 2 of 3 in the lib/rt extraction (#38). Commit 3 closes
the OOM contract — return type becomes nullable *void and the builtin
lowering null-checks + propagates nomem.
Verified 132/132 + 995_self_rebuild byte-identity (5 wwstage tools
round-trip identical) + make clean cold rebuild.
49 lines
2.1 KiB
ArmAsm
49 lines
2.1 KiB
ArmAsm
// rt/start.s — process entry. Linux sets up the stack so that on
|
|
// entry [SP] holds argc, [SP+8] starts argv (NULL-terminated array
|
|
// of *u8), [SP+8+(argc+1)*8] starts envp (also NULL-terminated).
|
|
//
|
|
// We pull argc into DI and the argv pointer into SI, then jump to
|
|
// `main`. ww programs that declare `fn main(argc: i32, argv: **u8)
|
|
// i32` see them; programs declaring `fn main() i32` simply ignore
|
|
// the regs. Either way, main's return value is fed to the exit
|
|
// syscall.
|
|
//
|
|
// envp is captured into the rt_envp_slot DATAW cell before CALL main
|
|
// so lib/os.getenv (via the rt_envp getter below) can walk it. We
|
|
// compute envp = SP + 16 + argc*8 in AX using three doublings and
|
|
// adds — w6a's syntax doesn't ship SIB-style indexed addressing
|
|
// (no `LEAQ 16(SP)(DI*8), AX`), so the explicit shift-by-three is
|
|
// the portable form. AX/DI/SI are scratch on entry; no callee-
|
|
// saved discipline applies until we reach main.
|
|
TEXT _start,$0
|
|
MOVQ (SP), DI // argc → DI (1st arg to main)
|
|
LEAQ 8(SP), SI // &argv[0] → SI (2nd arg to main)
|
|
MOVQ DI, AX // AX = argc
|
|
ADDQ AX, AX // AX = argc * 2
|
|
ADDQ AX, AX // AX = argc * 4
|
|
ADDQ AX, AX // AX = argc * 8
|
|
ADDQ SP, AX // AX = SP + argc*8
|
|
ADDQ $16, AX // AX = SP + argc*8 + 16 = &argv[argc+1] = envp
|
|
MOVQ AX, rt_envp_slot(SB)
|
|
CALL main(SB)
|
|
MOVQ AX, DI
|
|
MOVQ $60, AX
|
|
SYSCALL
|
|
|
|
// rt_envp — getter that returns the envp pointer captured at process
|
|
// entry. Bound from lib/os via `@symbol("rt_envp") fn rtenvp() **u8;`,
|
|
// matching the rt_syscall / rt_malloc / rt_abort pattern. Read-only
|
|
// view of the kernel-supplied table; the bytes live for the process
|
|
// lifetime. A future setenv that grows the table re-points the slot
|
|
// (separate task).
|
|
TEXT rt_envp,$0
|
|
MOVQ rt_envp_slot(SB), AX
|
|
RET
|
|
|
|
// rt_envp_slot — 8-byte writable cell holding the envp pointer.
|
|
// Initialised to zero in .data; _start overwrites it before
|
|
// transferring control to main. DATAW gives us the writable .data
|
|
// slot (w6a has no GLOBL; same shape as lib/log's silent/default/
|
|
// global cells in lib/log/log.s).
|
|
DATAW rt_envp_slot(SB),"\x00\x00\x00\x00\x00\x00\x00\x00"
|