D235 - The initialiser tags are parsed, and the answer was that there are none
decided · 2026-08-25 · hypothesis measured before it was built on
Having eliminated every call in PPSA02664 as the source of the
missing region base (D229, D230, D234), what was left was "not a call at
all". The dynamic-table parser handles NEEDED,
STRTAB, SYMTAB, RELA,
JMPREL and the vendor import tags, and falls through on
everything else - including DT_INIT,
DT_INIT_ARRAY and DT_PREINIT_ARRAY.
That fit the evidence uncomfortably well. A C++ namespace-scope
object with a constructor gets an init_array entry; a
function-local static does not, because it initialises on first use
behind a guard variable. So a guest whose init_array never
ran would show guard traffic in the trace - and PPSA02664 makes fifteen
__cxa_guard_acquire calls - while every global object
stayed zero. A region base held in a global would read as
0, and 0 + 0x100000 - 0x20 is the faulting
address exactly.
It is wrong. The tags are parsed now, and
init_array is absent from all three titles at a wall:
init_arraysz = 0, no entries. There was nothing to run.
Recorded because the hypothesis was good and the discipline is the point: the next step would have been to build an initialiser executor, and it would have executed an empty list, run identically, and been indistinguishable from a correct implementation. Measuring first cost one temporary print.
The parsing stays. The absence is now a measured fact with a test behind it rather than a gap nobody had looked at, and the loader can say so instead of not knowing.
Two things left over
DT_INIT reads 0x10 on all three
titles - identical across three unrelated games, and not a
plausible code address when the entry point is 0x70. Either
tag 12 does not mean DT_INIT in this container, or it is
not an address. Unresolved, and not guessed at.
PPSA28061 carries a preinit_array pointer with
size zero, which is an array of no functions. Also
unexplained.
And a third, which is why the second one mattered
The save button in the preferences window was not reachable.
Laid out in reading order - panes, separator, actions - the
ui.separator() between the pane list and the pane is a
vertical rule inside a horizontal layout, so it grows to fill the
available height; and in a window that sizes itself to its content,
"available" is however much screen there is. The action row was pushed
past the bottom edge, and the only way to press save was to tab
to it blind.
So the one control that could have fixed the library from inside the window was the one control the window had hidden. The actions are now a bottom panel placed before the panes, the content scrolls, and the window opens at a fixed size.
A note on where the file was, which was none of the above
The settings file this chased did exist - twice, byte-identical,
under two paths - and the window was right that it could not see either.
The tooling writing it was running inside a packaged application with
AppData redirection, so
%APPDATA%\orbistoun\data\config.toml resolved to a private
per-package copy and was reported back under the original name. Every
check agreed with every other check and all of them were answering a
different question than the window was.
Nothing in this repository caused it and nothing here can prevent it. It is recorded because the diagnostics added above are what eventually made it visible: the window naming the file it read, and saying plainly that it was not there, is what turned "the scanner is broken" into "these two processes disagree about a path" - which is a question with an answer.