D247 - orbistoun read modules by a path the console does not use

decided · 2026-08-25 · found in the first hour of pointing the conformance probe at the loader

DynamicInfo::parse read the standard dynamic tags - DT_STRTAB, DT_SYMTAB, DT_HASH, DT_RELA, DT_JMPREL - and knew exactly two vendor tags, both for import libraries. A console loader ignores every standard tag and reads DT_SCE_* entries describing tables inside a PT_SCE_DYNLIBDATA segment. That is obSCEne's derivation, and it is arithmetic rather than pattern-matching: the table offsets sum end-to-end.

Every title in the local corpus carries both sets. That is the only reason this has ever worked. orbistoun was reading real material by a path the platform does not take, and would have gone on doing so indefinitely - six commercial executables, none of which could expose it, because none of them is built the way the platform expects.

A module that carries only vendor tags was refused outright: "dynamic table lacks a string table, symbol table, or hash table", said of a module that has all three.

Three sites, one difference, and only one of them knew

A standard tag holds a virtual address. A vendor tag holds an offset into the data segment. Resolving one as the other does not fail - it lands at a plausible file offset holding the wrong bytes.

Three places resolved dynamic tables and each had to learn it:

site symptom before
raw_imports "dynamic table lacks a string table"
relocate::apply "2 relocations, 2 unsupported" - of two ordinary GLOB_DAT/JUMP_SLOT
symbol_count silently returned 0 - an empty thunk table, and every relocation blaming its symbol

The third is the one worth remembering. It answers 0 rather than an error, so the failure surfaced two layers away as "2 unresolved" against a symbol that was present and correctly named. One method on the container now, used by all three.

Zero is a value here, not a sentinel

The first attempt still refused the module. is_usable() tests strtab != 0, which is right for a virtual address and wrong for an offset - the probe's string table is at offset 0, the first byte of the data segment.

So the vendor tags are collected as Option, and presence is what the parser saw rather than a test on the value. This is the third time today the same trap has appeared: a real value spelled the same as absence. It was an empty string standing for "the record did not say" (D245), a zero count standing for "the diagnostic did not run" (D241), and now offset zero standing for "no table".

What it cost and what it bought

Twenty minutes and one build of a 126-line module with a single import. Three defects, each isolated by a one-line signal, in sequence. With the full probe's four hundred imports across fourteen libraries, every one of them would have surfaced together and been read as "the probe does not load".

The minimal module is a bisection instrument, not a lowered bar. Nothing fixed for it was specific to it: all three fixes are how the platform reads any module, including the six titles that were quietly relying on carrying both sets of tags.