D237 - Address translation was only ever implemented for signed containers
Status: decided (2026-08-25)
Container::vaddr_to_offset opened with
let Some(wrapper) = self.wrapper else { return Ok(None); };so every address of every unwrapped module resolved to
nothing. Not the ones it could not find - all of them,
including an address squarely inside a PT_LOAD whose
p_offset was valid and whose bytes were present in the
file.
It surfaced from outside. obSCEne ran its own module under orbistoun
and reported: two segments placed, then no PT_DYNAMIC
segment, or its address could not be located - about a module whose
PT_DYNAMIC sits at 0x67ec10, inside a
PT_LOAD spanning 0x5e8000..0x69ed10 that
orbistoun had just mapped successfully. Their own reading was right: it
was the second clause of that message, not the first.
The comment was true and had stopped being the whole truth
The headers' own
p_offsetvalues are not usable - they routinely point past end-of-file.
True of a wrapped container, where the program headers describe the decrypted image while the file holds the wrapper's descriptor table (D052). In an unwrapped container the offsets are the only thing there is, and they are authoritative. The function was written when the only input was a SELF, the early return was correct then, and nothing said so when bare ELF became an input the loader accepts and maps.
mapped segments []
was not the bug, and looked exactly like it
The inspector reported zero wrapper-located segments on a module with six program headers, which reads as the parser failing. It is correct and documented: a bare ELF has no descriptor table, so there is nothing to locate anything through. The defect was one function further on, and a test now pins the correct behaviour so the next reader does not re-investigate it.
A
PT_LOAD wins a tie, and that is a preference rather than a
proof
Two headers can cover one address. A vendor segment carrying dynamic
data is commonly declared at virtual address zero - its contents are
addressed as offsets into itself - and a module whose first
PT_LOAD also starts at zero then has two headers over the
same low range. An address in the image means the image, so
PT_LOAD is preferred and anything else is a fallback.
Stated as a limit rather than dressed up. An address
that is really an offset into a vendor segment will resolve against the
PT_LOAD and return the wrong bytes. The wrapper path does
not have this problem because a descriptor table says which header owns
which run of file. Telling them apart without one needs the vendor
segment's own conventions, which is separate work - so it is written
down here and in the source, not guessed at.
What it unblocks, and what it does not
The dynamic table is reachable now, which is the wall obSCEne hit.
Whether their module gets all the way to imports depends on whether its
DT_SCE_* addresses resolve, and that is the ambiguity above
- so this is honestly described as further, not as
works. A guest that can be run as often as we like, whose
source we have, and which announces every call before making it is worth
the next hour regardless of where it stops next.