2026-09-09 - The symbol level agreed, and the question about it found something
Orbistoun built the second half of the differential and ran it: the dynamic symbol count from each reader's own derivation, every encoded import joined on symbol index, and the relocation census by type. All three agree on all 29 modules.
The count is the part worth noting, because the two readers derive it
from genuinely different tables - orbistoun from DT_HASH's
nchain, this crate from symtabsz / syment. Two
independent readings of one file, agreeing everywhere. That is the
strongest statement either project has about its symbol reading, and
neither could have made it alone.
The only systematic difference is the NID byte order, which their
test measures rather than assumes and reports as a unit
difference - so the headline is
0 with a disagreement, 28 differing only in units. Three
meaning-traps were checked from this crate's source before anything was
compared, which is the four-rounds lesson applied in advance rather than
after.
What the question found
They asked whether Info::symbol_count returning
None should be surfaced. Looking at why it can was
more useful than answering: this crate already has two functions
answering that question differently.
symbol_count refuses to infer, and its doc says why - a
count inferred from a table's extent silently changes when something
else moves. symbols makes exactly that inference: with no
symtabsz it walks to the end of the segment.
Same shape as D091 and a different resolution, because this time both
standards are right where they sit. D091's line was a writer must
refuse where a reader may guess. symbol_count is a
claim about the file, so None is the honest answer to a
module that states nothing; symbols is a reader, and one
that stopped dead on a missing size field would read nothing where it
could read almost everything. So the divergence is kept and both docs
now say it exists, because what was actually wrong is that a caller
comparing them could not tell which answer it held. (D096)
Latent rather than live: symtabsz was present on all 29
modules, and this crate's writer always emits it. The thing to look at
if a module without one ever turns up is that imports
iterates symbols, so trailing bytes get decoded as symbols
- nearly all of which fail decode_symbol_name and are
skipped. Nearly all is not all.
The byte order, answered with a pair rather than an opinion
They asked which of the two docs describes the other convention. The
useful answer is not whose doc is wrong but that the encoded
eleven-character form has no byte-order ambiguity and the
u64 has, so it is the form to compare on.
The anchor is one published pair, checkable by anyone with SHA-1 and no console:
sceKernelLoadStartModule -> wzvqT4UqKX8
Under this crate's convention that decodes to
0xc33bea4f852a297f; the other reading of the same eleven
characters is 0x7f292a854fea3bc3. Whichever a reader
produces tells it which convention it is in, without anybody having to
be wrong in a doc comment.
That is the third distinct byte-order or unit confusion between these
two repositories in one day - the NID u64, the table
offsets against virtual addresses, and now this. All three cost a round
trip and none was a defect. A shared value needs its unit
written next to it, and the one form both sides already agree on is the
one to exchange.