2026-09-03
- (/loop) .bss, and a blind spot of our own making
tests 1991 -> 1991 (a report over numbers the loader already had)
The plan called one check "the cheap decisive one": is the null a
.data the loader failed to copy, or a .bss
that is zero by design? It was cheap, it was decisive, and the answer
needed no new measurement at all - only for the loader to say what it
already knew.
The split, from numbers that were already there
PlacedSegment records copied and
zeroed separately for every segment. That
is the .data/.bss split, and
nothing printed it. Now it does:
segment Il2CppUserAssemblies #4 0x480001d68000 0x194a6c copied 0x26e0dc zeroed flags 0x6
Copied ends at 0x480001efca6c. The faulting
rsi is 0x480001f0c330 -
0xf8c4 inside the zeroed run.
So the loader copied everything the file held. The global is zero
because .bss is zero, and the question stops being "what
did placement get wrong" and becomes "what was supposed to write this".
Three hypotheses died over three ticks - missing constructors (D491),
module_start (D492), a failed .data copy
(this) - and the placement path is now clear of all of them.
The caller is identified too: +0x13d5f00 is
0x70 into the export at +0x13d5e90, which is
0x9fdbed4fe0989d70 - one of the five imports the eboot
binds into the module.
And then the trace was empty
The obvious next question is which of those five the eboot calls first, and in what order. The trace answers that. It did, until four worklogs ago:
Il2Cpp entries in the trace: NONE
Before D489's binding, 0x6f8b9da539afc9af showed up as
222 calls carrying il2cpp_init as its
first argument - which is the only reason the resolver was ever found.
Bound to a real address, the guest calls it directly and no thunk sees
it.
Principle 7 says so in as many words: interception is linking, not hooking. What gets observed is exactly what resolves to a stub. Binding an import to real code is the right answer and is also, in the same stroke, switching the instrument off for that call.
I did not think that through when writing D489, and the shrinking call count in worklog 339 - 10884 down to 2080 - was read as the guest taking a different path. It is that, and it is also several hundred calls that still happen and are no longer counted. The trace measures what orbistoun answers, not what the guest does.
Which makes the next instrument non-optional
Every interesting call from here is one this build has deliberately stopped watching. So a trace of bound calls is the next real piece of work, and it is a design question rather than a feature: a thunk that forwards into the module would restore visibility and reintroduce exactly the indirection principle 7 exists to avoid. Recorded in D493 rather than attempted at the end of a session.
State
cargo test --workspace green - 117 suites, 1991
tests, 0 failures. clippy --tests clean, fmt
clean, identity scan clean.
Nothing committed. The day holds worklogs 292-343 and D466-D493.
Next: how to observe a bound call without undoing
the binding. Then the .bss question it is blocking.