feat(#798): RV32 active data segments SHIP — .wasm_data records + linker placement + startup copy, read-back hard gate - #802
Merged
Merged
Conversation
…it from the SHIPPED .wasm_data records, not wasmtime's memory The old harness copied wasmtime's instantiated memory image into unicorn, masking the #798 silent initializer drop (the object ships .text only): the 1200-byte decision table read 0x00 at runtime while the differential stayed green. Now linear memory is initialized ONLY from the object's .wasm_data active-segment records (the bytes the generated startup copy loop serves), and a record-less object fails loudly up front. RED on the pre-fix binary (ac79fb3): - object ships NO .wasm_data records -> loud FAIL, and - semantic divergence proven: zeroed-linmem execution of the shipped .text returns 0x00000000 for (3000,50,40,0) where wasmtime returns 0x00210a55 (the differential READS the segment — non-vacuous). GREEN arrives with the .wasm_data shipping commit (#798). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…e read-back in synth_core::static_data_addr The RV32 .wasm_data shipping format: repeated [u32 off][u32 len][bytes][pad4] in declaration order (later-wins preserved by the startup's record-order copy). served_image_from_records() reconstructs the dense image the emitted blob actually serves (read-back, never a recompute — mirror-pinning excluded), for the same validate_served_image gate the #758 ROM image uses. Red-first unit gate: a REVERSED (first-wins) pack of the #757 3-overlap shape fails validate_served_image at the classic 0x100008 byte; the declaration-order pack passes. Plus round-trip, sparse far-offset (8+len flash bytes, no dense image), and loud-reject on malformed blobs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…ent + startup record-copy loop - RiscVElfBuilder::build_with_data: non-empty record blobs become a .wasm_data PROGBITS (SHF_ALLOC, 4-aligned) section between .text and .symtab; empty blobs are BYTE-IDENTICAL to the pre-#798 layout (unit-gated). - Generated linker.ld: flash-resident .wasm_data output section with __wasm_data_records_start/end, placed before _data_load is pinned (no overlap with the .data load image). Old scripts + new startup fail the link LOUDLY (undefined symbol) instead of silently dropping. - Generated startup.c: reset-path loop walks the records and byte-copies each segment to __linear_memory_base + off before main — record order = declaration order, so WASM later-wins overlap semantics hold. - Backend::compile_module (library path) ships the records too and hard-fails on a served/runtime mismatch via the read-back gate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…ning becomes the VCR-VER-003 read-back hard gate The -b riscv arm now packs all_data_segments into .wasm_data records (via pack_segment_records), reads the emitted blob BACK (served_image_from_records) and hard-errors on any served/runtime disagreement (validate_served_image, mixed-split style) — plus the #758-parity instantiation-trap bail when a segment extends past the declared linear memory. The 'ships NO initializer image' warning is gone: the initializers ship. Red->green on the de-vacuated control_step differential: pre-fix object FAILS (no .wasm_data, zeroed-linmem result 0x00000000 vs 0x00210a55); post-fix all 5 vectors match wasmtime incl. gale's reference 0x00210a55. Frozen-fixture impact: NONE on .text (control_step .text sha unchanged); data-free RV32 objects are whole-file byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…full-boot differential through the REAL startup copy loop
- vcr_ver_003_addr_777.rs RV32 class rewritten for the shipped state: nonzero
data compiles green with NO drop-warning and the .wasm_data record bytes
verbatim; overlapping segments ship both records in declaration order;
data-free modules ship no section; a segment past the declared memory is
refused ('instantiation would trap', #758 parity).
- scripts/repro/rv32_data_798_boot_differential.py: synth compile ->
riscv-runtime -> clang(riscv32)+ld.lld -> unicorn boots fw.elf FROM _reset,
so the GENERATED startup's record-copy loop initializes linmem; overlapping
segments must serve the later-wins image and get() must equal wasmtime.
Verified locally: linmem aabb1122, result 0x2211bbaa == wasmtime. Missing
toolchain = loud FAIL, never a skip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…+ CHANGELOG - VCR-VER-003 roadmap item (7): warning-era text replaced with the shipped scheme (records format, linker placement, startup copy, read-back hard gate, de-vacuated differential + full-boot oracle); RV32 shipping removed from the BOUNDED follow-ups; pass-criteria updated. - claims.yaml: comment (c) updated to the shipped state; new count-eq pin holds the RV32 served image to the EMITTED blob read back (served_image_from_records == 1 in main.rs). 21/21 claims hold. - CLAUDE.md Track C + CHANGELOG [Unreleased] entry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #798. v0.48 Wave-1 Lane 3.
What
The RV32 single-base scheme (
s11 = __linear_memory_base, zeroed RAM) shipped a.text-only object: active data segments were silently dropped — every nonzero initializer byte read0x00at runtime (found by the VCR-VER-003 phase-2 probe #777; v0.47/#797 held a loud warning). This PR ships them — the real fix, not the decline:[u32 off][u32 len][bytes][pad4](declaration order;synth_core::static_data_addr::pack_segment_records) emitted as a.wasm_dataPROGBITS (SHF_ALLOC) section. A far segment costs8 + lenflash bytes — no dense image. Data-free modules ship no section and are whole-object byte-identical (unit-gated).synth riscv-runtime): flash-resident.wasm_dataoutput section with__wasm_data_records_start/end, placed before_data_loadis pinned. An old script + new startup fails the link loudly (undefined symbol) instead of dropping data again.__linear_memory_base + offbeforemain— record order = declaration order, so WASM later-wins overlap semantics hold structurally (the 0.43.0: #746 fix relocates but MISCOMPILES the wide-static copy path — silent wrong bytes (was: skip) #757 lesson).served_image_from_records— never a recompute, mirror-pinning structurally excluded) andvalidate_served_imagehard-errors the compile on any served/runtime disagreement. A segment past the declared memory is refused (instantiation would trap, default --cortex-m self-contained image silently DROPS active (data) segments: .linear_memory is NoBits, initializer bytes absent -> every load from an initialized region reads 0 (silent miscompile) #758 parity). The v0.47 warning is gone; the libraryBackend::compile_modulepath ships + validates too.Red → green
control_step_riscv_differential.py: the old harness copied wasmtime's instantiated memory into unicorn, masking the drop (a vacuous gate). It now initializes linmem only from the shipped.wasm_datarecords. On the pre-fix binary (ac79fb3): loud FAIL, and the semantic red is proven — zeroed-linmem execution returns0x00000000for(3000,50,40,0)where wasmtime returns0x00210a55. Post-fix: 5/5 vectors match incl. gale's reference0x00210a55.scripts/repro/rv32_data_798_boot_differential.py: synth compile →riscv-runtime→ clang(riscv32) + ld.lld → unicorn bootsfw.elffrom_reset— the REAL generated startup copy loop initializes linmem; overlapping segments serve the later-wins image (aabb1122) andget()equals wasmtime (0x2211bbaa). PASS locally.validate_served_imageat the classic 0.43.0: #746 fix relocates but MISCOMPILES the wide-static copy path — silent wrong bytes (was: skip) #757 byte; declaration order passes. Malformed blobs parse toNone(loud).Refreeze ritual
All 12
*_riscv_differential.pyscripts re-run PASS on the new bytes. Frozen RV32.textis unchanged (control_step.textsha identical pre/post; data-free objects byte-identical) —frozen_fixtures_rv32_text_is_bit_identical_oracle_001green with no re-pin needed; the compile-success freeze that held the v0.47 warning is moot because the compile stays green by shipping, and its differential now actually reads the segment (de-vacuated per #797's finding).Gates
cargo test --workspacegreen (126 suites),cargo fmt --check,clippy -D warningscleanscripts/claim_check.py: 21/21 — claims/roadmap updated to the shipped state + new count-eq pin holding the RV32 served image to the emitted blob read-back🤖 Generated with Claude Code
https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L