Repository navigation
Conversation
A load or store with `x0` as its base is an absolute access below 2 KiB, a region no program can map, so it can only fault. Only the all-zero form (`sw zero, 0(zero)`, LLVM's poor man's trap) was accepted; any other offset or source register failed with "found an unrelocated absolute store/load". LLVM emits those other forms at -O3 on paths it has proven dereference null plus a field offset. Inlining `midnight-proofs`' `multi_prepare` into a guest does exactly that, so the program linked at -Oz and not at -O3. Both arms now emit `Unimplemented` for any `x0`-based access. The test drives `convert_instruction` with a `sd a0, 8(zero)` and a `ld a1, 16(zero)` against a 600-octet object whose assembly and producer command are checked in beside it. Assisted-by: Claude:claude-opus-5-5 claude-code Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pa3h4NGNHFdgFYQEBpnnv2
`address + length - 1` overflows `u32` when a host pages in the last page of the address space (0xfffff000 + 0x1000), which `zero_memory`'s contract allows (`address + length` up to 2^32). Debug builds panic; release wraps to the right page by luck. Both the generic and the Linux sandbox; the interpreter was already right. `length` is non-zero on every path here (`RawInstance::zero_memory_impl` returns early), so `length - 1` is safe. The generic sandbox's trace line overflowed the same way. Exercised by `test_asm_x0_access` (next commit) on the compiler backends. Assisted-by: Claude:claude-opus-5-5 claude-code Claude-Session: https://claude.ai/code/session_011bynSd1c8vTK3v9NRLVUPk
Supersedes the previous commit's "every x0-based access is a trap": that is
exact at the bottom of the address space, but at the top (a negative offset)
the VM reports a page fault that dynamic paging can resume, and a trap is
terminal.
- load/store through x0 -> LoadAbsolute/StoreAbsolute at the literal
address; the VM reports whatever fault it would have. `AbsoluteTarget`
packs the literal into `SectionTarget`'s 16 octets, keeping `BasicInst`
at 32.
- load *into* x0 through x0 -> a load into the scratch `E0`, spilled later
(as atomics with a discarded result already do): the fault is all it
does, and it must stay resumable.
- atomics at 0, jalr to a literal -> trap, exact at 0.
- refused only in a *linked* ELF, where a loaded section lies at that
address (a lost relocation). An object file (ET_REL, which the linker
accepts) puts every section at a placeholder 0 and keeps its relocations,
so it gets no such check - without that, `sd a0, 8(zero)` in any .o was
refused as "inside section '.text'".
Tests: `test-data/x0-access.{s,o}` has one exported row per case;
conversion unit tests; `test_x0_access_in_a_relocatable_object_links`; and
`test_asm_x0_access` runs every row on every backend with and without
dynamic paging, mapping faulting pages and checking the load into x0
resumes with all registers intact.
Assisted-by: Claude:claude-opus-5-5 claude-code
Claude-Session: https://claude.ai/code/session_011bynSd1c8vTK3v9NRLVUPk
… file The `ET_REL` gate filtered only the code sections: `.filter` sat before the `.chain`s, so an object file's `.rodata`, `.data` or `.bss` - also at a placeholder 0 - still made `sd a0, 8(zero)` fail as "inside section '.rodata'". The gate now covers the whole list. The fixture gains 16 octets of each, which is what exposed it. Assisted-by: Claude:claude-opus-5-5 claude-code Claude-Session: https://claude.ai/code/session_011bynSd1c8vTK3v9NRLVUPk
Signed-off-by: Giles Cope <gilescope@gmail.com>
Signed-off-by: Giles Cope <gilescope@gmail.com>
Signed-off-by: Giles Cope <gilescope@gmail.com>
Signed-off-by: Giles Cope <gilescope@gmail.com>
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.
I had a service that linked fine with
-zand normal but at-O3LLVM emits loads and stores withx0as the base (sd a3, 8(zero)) for a null dereference on a path it assumes never runs. (Ideally the compiler should have picked up and dropped these before they got to the linker but compilers aren't perfect).Fix
x0accessx0E0jalrto a literalrelocation (linker relaxation, or no
--emit-relocs). Object files (ET_REL) are exempt -their sections all sit at 0 and keep their relocations.
AbsoluteTargetstores the literal insideSectionTarget's 16 octets, soBasicInststays at 32.zero_memoryoverflowedu32(generic and Linux).Assisted by my good friend Claude (5.5) and Codex for cross-checking.
(Tested on mac arm64 and linux x86)