Skip to content

dissolve: bind passed-through embedder import cabi-arena-realloc to the native TCB arena allocator #418

Description

@avrabe

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_realloccabi-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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions