You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Evaluate PIC / shared-everything dynamic linking as an input ABI for meld,
as an alternative (or complement) to the relocatable-inputs contract decided in
ADR-6. Raised by Christof re: #352 — with PIC inputs, address "rebasing" becomes
"set one __memory_base global per module", which structurally dissolves the
entire #351/#340 stale-reloc.CODE failure class: there are no absolute i32.const address literals to rewrite, so there is nothing for a producer's
LEB-relaxation to desync.
PIC eliminates absolute addresses.clang --target=wasm32 -fPIC -O2 -c + wasm-ld --experimental-pic -shared turns dataB into (data (global.get $__memory_base) …) and ptr_b into global.get $__memory_base + offset. No i32.const <addr> literals exist.
An AOT linker exists and works:wasm-tools component link (and wac 0.6.0) link two dylink.0 modules into a valid component — one $main
module owns a shared memory and exports it; each dylib is instantiated (with "env" …) with that memory + a disjoint __memory_base; an $__init module applies relocations at instantiation. This is the
SharedEverythingDynamicLinking model, working out of the box.
synth (native AOT) / loom (whole-program opt): a single static core with
fixed addresses is the cleanest input; better than component link's
instantiation-time relocation.
meld's thesis ("static fusion, no runtime linking, single monolithic
module"): the hard constraint. meld must NOT shell out to component link —
that produces the linked-but-separate graph meld positions against (= wac). The
meld-shaped design is: consume PIC/-shared dylibs and resolve __memory_base per module STATICALLY at fuse time, emitting one flat core —
keeping meld's static-single-core output while adopting the PIC input ABI.
Decisive spike (feasibility question to answer next)
Can meld consume PIC/-shared dylibs (or a component link-style shared-
everything graph) and statically flatten them into one core module —
resolving $__init's instantiation-time relocations at build time, assigning
disjoint bases itself? If yes, this is a cleaner ADR-6 successor. If the
instantiation-time relocation can't be statically resolved, PIC stays an
input-format improvement only.
Summary
Evaluate PIC / shared-everything dynamic linking as an input ABI for meld,
as an alternative (or complement) to the relocatable-inputs contract decided in
ADR-6. Raised by Christof re: #352 — with PIC inputs, address "rebasing" becomes
"set one
__memory_baseglobal per module", which structurally dissolves theentire #351/#340 stale-
reloc.CODEfailure class: there are no absolutei32.constaddress literals to rewrite, so there is nothing for a producer'sLEB-relaxation to desync.
Refs: SharedEverythingDynamicLinking.md,
DynamicLinking.md.
Grounded findings (verified today — wasm-tools 1.243.0, wac 0.6.0, clang 22.1.8)
clang --target=wasm32 -fPIC -O2 -c+wasm-ld --experimental-pic -sharedturnsdataBinto(data (global.get $__memory_base) …)andptr_bintoglobal.get $__memory_base+ offset. Noi32.const <addr>literals exist.wasm-tools component link(andwac 0.6.0) link two dylink.0 modules into a valid component — one$mainmodule owns a shared memory and exports it; each dylib is instantiated
(with "env" …)with that memory + a disjoint__memory_base; an$__initmodule applies relocations at instantiation. This is theSharedEverythingDynamicLinking model, working out of the box.
concluded "PIC excluded" — but it tested
wasm-tools component **new**, whichrejects a dylink core (reconfirmed today:
error: failed to decode world from module; the CM forbids theenv.memory/__memory_basenon-functionimports).
component **link**is purpose-built for these and accepts thesame core (reconfirmed). ADR-6's exclusion is really "excluded from the
component newpipeline", not "excluded".Alignment with PulseEngine goals
base_i + intra_offset, bases disjoint" ≈ the memory-layout-disjointness lemma
meld already proves for merge. The reloc-consumer (fuse --memory auto/shared silently corrupts memory across components: load/store dynamic addresses are not rebased (no memory.grow; distinct from #172/#299) #326→fix(326): reloc-driven shared-memory address rebasing (sound --memory shared) #340) + meld --memory shared --address-rebase skips R_WASM_MEMORY_ADDR_SLEB relocations: a rebased module's i32.const data pointer stays stale -> silent cross-component aliasing (gap in #340) #351 drift are
byte-level and genuinely hard to prove; PIC makes that obligation disappear.
everything is the native model there (no MMU/sandbox), so Christof's
"sacrifices the sandbox" caveat is a non-issue for the MCU target — it's the
goal. The whole MCU-dissolve arc would have been trivial with PIC inputs.
fixed addresses is the cleanest input; better than
component link'sinstantiation-time relocation.
module"): the hard constraint. meld must NOT shell out to
component link—that produces the linked-but-separate graph meld positions against (= wac). The
meld-shaped design is: consume PIC/
-shareddylibs and resolve__memory_baseper module STATICALLY at fuse time, emitting one flat core —keeping meld's static-single-core output while adopting the PIC input ABI.
rustc→PIC-wasm fights default
--export/--gc-sections; a bigger build changethan fuse --memory auto/shared silently corrupts memory across components: load/store dynamic addresses are not rebased (no memory.grow; distinct from #172/#299) #326's one-flag
-C link-arg=--emit-relocsthat gale already uses.Proposal
Treat input ABI as a spectrum, not a single choice:
--emit-relocs(works for gale today); land the fix(351): hard-fail on stale reloc.CODE offsets instead of silent miscompile #352backstop as the safety net for it.
__memory_baseassignment as aparallel input path — the better foundation for the formally-verified/MCU/synth
goals, and it retires the meld --memory shared --address-rebase skips R_WASM_MEMORY_ADDR_SLEB relocations: a rebased module's i32.const data pointer stays stale -> silent cross-component aliasing (gap in #340) #351 reloc-drift class instead of chasing it with
drift-tolerant rebasing (the previously-planned fix(351): hard-fail on stale reloc.CODE offsets instead of silent miscompile #352 tier-2).
Decisive spike (feasibility question to answer next)
Can meld consume PIC/
-shareddylibs (or acomponent link-style shared-everything graph) and statically flatten them into one core module —
resolving
$__init's instantiation-time relocations at build time, assigningdisjoint bases itself? If yes, this is a cleaner ADR-6 successor. If the
instantiation-time relocation can't be statically resolved, PIC stays an
input-format improvement only.
Relation to existing work
spike succeeds. fix(351): hard-fail on stale reloc.CODE offsets instead of silent miscompile #352 tier-1 (backstop) is orthogonal and still lands.
cabi-arena-reallocinstead of trying to satisfy it #301 (arenarealloc), Close the meld→kiln end-to-end seam: run a meld-fused core module on kiln and assert behavioural equivalence #297 (kiln seam).