Context
Part of the BYO-OS lean-MCU dissolve pipeline (gale#89):
gale app + kernel-primitive components
→ meld fuse --memory shared
→ loom → synth (native ELF, no memory.grow)
Grow-free components are built with the forked wit-bindgen cabi-realloc-extern feature (pulseengine/wit-bindgen#4): cabi_realloc stays exported but its body routes to an embedder-provided env::__cabi_arena_realloc import, so no memory.grow is pulled in on realloc's account.
What wasm-tools now produces (contract)
The pulseengine/wasm-tools fork now supports component new --import-passthrough env::__cabi_arena_realloc (pulseengine/wasm-tools#2). Instead of rejecting the unmapped env import, it produces a valid component that:
- imports a world-root function whose extern name is the kebab-case of the core symbol field name —
__cabi_arena_realloc → cabi-arena-realloc — typed func(p0: u32, p1: u32, p2: u32, p3: u32) -> u32 (derived from the core signature (i32,i32,i32,i32) -> i32);
canon lowers that import and wires it as the core module's env::__cabi_arena_realloc import;
- keeps
cabi_realloc exported and used as the canonical realloc.
Resulting world surface:
world root {
import cabi-arena-realloc: func(p0: u32, p1: u32, p2: u32, p3: u32) -> u32;
export greet: func() -> string;
}
The component import is deliberately left unsatisfied — it's an embedder/host symbol to be bound at native link / dissolve, not by the component model.
Ask (synth)
At dissolve / native link, bind the passed-through import (after meld, see the meld companion issue) to the TCB's native arena allocator symbol __cabi_arena_realloc, honoring the full canonical-ABI realloc contract:
- signature
(old_ptr, old_len, align, new_len) -> ptr (i32×4 → i32);
old_len == 0 && new_len == 0 → return align;
- bounded arena, traps on exhaustion rather than calling
memory.grow.
The naming rule is kebab_case(core_field_name); synth should map the component import cabi-arena-realloc back to the native symbol __cabi_arena_realloc. If we'd rather preserve the exact symbol verbatim (avoid the kebab transform), let's decide that here and adjust the wasm-tools fork — the transform is only there because component extern names must be kebab-case.
Refs
pulseengine/wasm-tools#2 (the --import-passthrough flag, implemented), pulseengine/wit-bindgen#4 (cabi-realloc-extern), meld companion issue (pass-through during fuse), synth#383, gale#89.
Nothing here goes upstream to bytecodealliance — this is the pulseengine fork pipeline only.
Context
Part of the BYO-OS lean-MCU dissolve pipeline (gale#89):
Grow-free components are built with the forked wit-bindgen
cabi-realloc-externfeature (pulseengine/wit-bindgen#4):cabi_reallocstays exported but its body routes to an embedder-providedenv::__cabi_arena_reallocimport, so nomemory.growis pulled in on realloc's account.What wasm-tools now produces (contract)
The pulseengine/wasm-tools fork now supports
component new --import-passthrough env::__cabi_arena_realloc(pulseengine/wasm-tools#2). Instead of rejecting the unmappedenvimport, it produces a valid component that:__cabi_arena_realloc→cabi-arena-realloc— typedfunc(p0: u32, p1: u32, p2: u32, p3: u32) -> u32(derived from the core signature(i32,i32,i32,i32) -> i32);canon lowers that import and wires it as the core module'senv::__cabi_arena_reallocimport;cabi_reallocexported and used as the canonical realloc.Resulting world surface:
The component import is deliberately left unsatisfied — it's an embedder/host symbol to be bound at native link / dissolve, not by the component model.
Ask (synth)
At dissolve / native link, bind the passed-through import (after meld, see the meld companion issue) to the TCB's native arena allocator symbol
__cabi_arena_realloc, honoring the full canonical-ABI realloc contract:(old_ptr, old_len, align, new_len) -> ptr(i32×4 → i32);old_len == 0 && new_len == 0→ returnalign;memory.grow.The naming rule is
kebab_case(core_field_name); synth should map the component importcabi-arena-reallocback to the native symbol__cabi_arena_realloc. If we'd rather preserve the exact symbol verbatim (avoid the kebab transform), let's decide that here and adjust the wasm-tools fork — the transform is only there because component extern names must be kebab-case.Refs
pulseengine/wasm-tools#2 (the
--import-passthroughflag, implemented), pulseengine/wit-bindgen#4 (cabi-realloc-extern), meld companion issue (pass-through during fuse), synth#383, gale#89.