An eboot is not the module this project builds, in three separate ways
/app0 mounts, and a console's rtld now
reads the eboot and refuses it. Each refusal named the next difference,
and all three are the same kind of difference: what a loader
that maps a module wants, against what a loader that
executes one does.
| module (elfldr, emulators) | eboot in a real package | |
|---|---|---|
| container magic | current generation | previous - and selfish wrap already
defaulted to it |
e_type |
0xFE10 executable |
0xFE00 fixed-address executable |
| image base | 0 - addresses are offsets, the loader adds a base |
0x400000 - mapped where the file
says |
first PT_LOAD file offset |
0, with FILEHDR PHDRS |
0x4000, and the headers are in no
segment at all |
The first two are fixed: mkmodule --fixed writes
0xFE00, the eboot targets wrap at generation 4, and
module.ld takes an optional
OBS_IMAGE_BASE.
The fourth row is the one still standing, and it is the interesting one because this script argues for the opposite in a comment that is correct about the case it was written for:
FILEHDR and PHDRS here rather than on a segment of their own: without them the headers are not covered by any segment, and a loader that maps only what the segments describe cannot read the header table it just used.
True of a loader that maps segments and then reads the file through the mapping. A system loader reads the file directly, and refuses one whose first segment starts at file offset zero:
[rtld] ERROR verify_ehdr:930: B: offset 0x0 end 0x190
0x190 is exactly ehdr + 6 phdrs. A real
eboot puts its first LOAD at file offset
0x4000 with PT_INTERP at the same place, so
the header region is covered by nothing. Both layouts are right for
their loader, which is why this cannot be a fix to
module.ld - it needs a second script, or a switch as
deliberate as OBS_IMAGE_BASE.
Worth saying about the method
Every one of these came from measuring a real package's eboot rather
than from reasoning about what a loader ought to want, and three times
the reasoning would have been wrong: a current-generation console wants
the previous generation's container, a fixed-address executable
is a different e_type rather than a linker flag, and
mapping the headers - which one loader requires - is what another
refuses. The file was sitting inside a package that has been on the
bench all along.