re: the timer message's consumer is a runtime registry, not a tag compare

The move I flagged last iteration -- "0xAB03E5BA is built once, so
nothing consumes it" -- is refuted by its own control: 25 of the 40
distinct 0xAB03xxxx tags in the image are built exactly once (62.5 %),
and no 4-aligned word anywhere in the image begins 0xAB03, so tags are
never stored statically.

What does stand:
  * sub_82175C20(bus+4, &msg) is a ring-buffer PUSH, not a dispatch.
  * The message class has a one-method vtable {scalar deleting dtor}
    with an MSVC RTTI locator at vtable[-1] -- no handler of its own.
  * The bus at [0x828F35DC] has a map at +8216, looked up via
    sub_82254A08 from sub_823001E8, whose only caller is the per-frame
    pump sub_8230C398.

So the item is NOT settled: the insert path into bus+8216 is unread,
and whether running out of time ends the mission is still unknown.

Docs only; ISL artefacts regenerate byte-identical.
This commit is contained in:
Sylpheed RE agent
2026-08-27 09:12:36 +00:00
parent d79f59d24e
commit bf17f19f67
2 changed files with 72 additions and 5 deletions

View File

@@ -110,13 +110,52 @@ the same coroutine one instruction apart, which is why they read almost the same
value and the conflation was invisible. **The 1200-second limit belongs to the
mission timer; it is not stopwatch 0's limit.**
## 🔴 The message bus: what the "one occurrence" of the tag is worth — nothing
The obvious next move was to search for a second site building `0xAB03E5BA` and
conclude from its absence that nothing consumes the timer message. **That
reasoning is dead**, and the control kills it:
| | |
|---|---|
| instructions building `0xAB03E5BA` (`addis 0xAB03` + `ori 0xE5BA`) | 1 — the producer |
| `0xAB03E5BA` as a 4-byte word **anywhere** in the image | **0** |
| *any* 4-aligned word beginning `0xAB03` anywhere in the image | **0** |
| distinct `0xAB03xxxx` tags built by an `addis`/`ori` pair | 40 |
| **of those, built exactly once** | **25 (62.5 %)** |
Single-site construction is the **majority** case, so it says nothing about this
tag in particular. And because no tag is ever stored as a static word, there is
no table of subscribed tags to find either.
### ✅ Two structural reasons it cannot be a compare or a virtual call
* **The post is a QUEUE PUSH, not a dispatch.** `sub_82175C20(bus+4, &msg)` is a
ring-buffer append — capacity at `+8`, head at `+12`, count at `+16`, element
array at `+4`, growing through `sub_8228E208`. It never looks at the message.
* **The message class has a ONE-METHOD vtable.** `0x820A8D18``0x820A8DA0` is a
run of 2-word records `{ sub_82301C20, 0x8210Exxx }`. The timer message's vptr
is `0x820A8D68`, so `vtable[0] = sub_82301C20` — a scalar deleting destructor
(it stores `0x820A7014` over the vptr and conditionally frees) — and
`vtable[-1] = 0x8210E288`, an MSVC RTTI locator (`0,0,0, &typeDescriptor
0x8289D094, &classHierarchy 0x8210E29C`, `numBaseClasses = 3`). Not code: that
address is data, and the disassembly does not even reach it (`sylpheed.db`
starts at `0x82150000`). **The message carries no handler of its own.**
### 🟡 Where the subscriber actually lives — located, not read
The bus object at `[0x828F35DC]` carries a **map at `+8216`**, looked up through
`sub_82254A08` from **`sub_823001E8`** — whose only caller is `sub_8230C398`, the
per-frame message pump (itself called from the frame loop `sub_821A6544` with the
frame `dt`). So dispatch is a **runtime registry keyed by the tag**, and the
question "does running out of time end the mission" reduces to: *what inserts into
`bus+8216`, and with which key.* That insert path is not read here.
## 🟡 Not settled
* **Who subscribes to `0xAB03E5BA`.** The literal appears at exactly one site —
the producer — but `0xAB03` is the high half of *many* message tags in this
image and dispatch is not by literal compare, so a single occurrence is **not**
evidence that nothing consumes it. Whether running out of time ends the mission
is therefore unread.
* **Who subscribes to `0xAB03E5BA`** — see above. Located to the registry at
`bus+8216`; the registration path is unread, so whether running out of time
ends the mission is still unknown.
* What B counting to zero does. Nothing observed acts on it.
* Whether `timer_stop`'s 170 sites are all phase teardown, or some are a real
mid-mission stop.