Skip to content

Declare dScMgBase_c slot 32 (Virtual80) across the minigame family - #2107

Merged
andrewboudreau merged 1 commit into
mainfrom
cpp/minigame-slot32
Sep 1, 2026
Merged

Declare dScMgBase_c slot 32 (Virtual80) across the minigame family#2107
andrewboudreau merged 1 commit into
mainfrom
cpp/minigame-slot32

Conversation

@andrewboudreau

Copy link
Copy Markdown
Collaborator

Slot 32 of dScMgBase_c's 36-entry vtable. Base body ov004:0x020b27f4,
one descendant override in the whole family (dScMgSlot3_c,
ov006:0x0210aa60) — the cheapest slot in the campaign after 22's zero.

Stacked on #2106 (slot 31). Base is cpp/minigame-slot31.

The name: Virtual80, not AfterClsn

This is the defect settled at slot 31, one fork further out — and it is the more
misleading of the two, because AfterClsn is a real ROM name.
include/PathLift.h:58 declares it and _ZN16dPathLiftActor_c9AfterClsnEi is a
genuine mangled symbol. But:

fBase_c -> dBase_c -> dActor_c -> dBgActor_c -> dPathLiftActor_c
fBase_c -> dBase_c -> dScene_c -> dScMgBase_c

The chains share only dBase_c, which adds no virtual of its own, so the two
slot 32s have fBase_c's first eighteen entries in common and nothing else.
dPathLiftActor_c::AfterClsn also takes an int; this slot takes nothing.

Independent image-side check: scanning arm9 + all 103 overlays for the dispatch
pair at +0x80ldr rN,[rM,#0x80] with Rn != pc, followed within three
instructions by blx rN — finds exactly three sites. One is
ov004:0x020b0900 (this branch); the other two are ov002:0x020effa4 and
ov064:0x02116e58, which are dPathLiftActor_c::AfterClsn on that branch.

Virtual80 is the offset spelling fBase_c already uses (Virtual34,
Virtual38) and the one slots 33-35 are recorded under in
notes/dScMgBase_c-slots-18-35.md. It costs no new convention.

What the slot actually is

Slots 31 and 32 are one function twice, against the two display engines.

slot 31 (Virtual7C) slot 32 (Virtual80)
engine SUB MAIN
BG1CNT 0x0400100a0x10 0x0400000a0x1000
scroll reset SetSubBg1Offset(0,0) SetBg1Offset(0,0)
BG-enable shadow data_0209d454 &= ~2 data_0209d45c &= ~2
char ptr G2S::GetBG1CharPtr func_02054ea8
screen map G2S::GetBG1ScrPtr, file 0x5b G2::GetBG1ScrPtr, file 0x67
called from BeforeInitResources, last AfterInitResources(u32), first

The two shadow words are exactly the pair slot 30 restores the two DISPCNTs
from, so 30/31/32 are one mechanism. It builds this minigame's top-screen
background. It touches no collision.

dScMgSlot3_c's override is the base body verbatim plus one more write, leaving
BG1CNT at 0x1118 rather than 0x1000 — the same layer, pointed at this
minigame's own character and screen base blocks.

Arity and return type, measured

At ov004:0x020b0900:

ldr r2,[r0]        ; vtable
mov r5,r0          ; this
ldr r2,[r2,#0x80]  ; slot 32
mov r4,r1          ; AfterInitResources's own vfSuccess
blx r2
mov r0,#2          ; result discarded on the very next instruction

r0 is this. r1 is the caller's own parameter, parked in r4 because the
call clobbers it
and handed to 0x0203188c afterwards — a callee that consumed
r1 would not need it saved first. Return type stays a hint for the fourth
consecutive slot.

Verification

  • rombuild -j 16 --no-rom: 11,088/11,088 reproducing, 106/106 exact,
    100.000000%
    of compared bytes, ROM-build analysis PASS.
  • romdata_check vs the slot-31 baseline: verifiedBytes 35416 -> 35420 (+4),
    partialBytes 11748 -> 11872 (+124). 128 bytes = 32 tables × one word,
    which is what declaring exactly one slot must cost.
    symbols 1246, verified 465, partial 253, differs 6, totalRecords
    7560 — all unchanged. The differing set is unchanged in both directions.
  • check_dead_references clean · port_refcheck 405/405 ·
    check_header_offsets --changed origin/main 0 mismatched ·
    check_src_tu_compiles 97/97 · check_duplicate_sources 11038 stems, none
    doubled · langmode ratchet PASS.

What this PR does NOT establish

  • Virtual80 is a placeholder, not a ROM name. The cartridge names nothing
    at this slot on this branch.
  • The return type int is a hint, not a measurement — nothing reads the result.
  • func_02054ea8 is almost certainly G2::GetBG1CharPtr: the G2S pair is
    0x02054e88/0x02055148 and the G2 pair is 0x02054ea8/0x02055168, the
    same +0x20 apart, and slot 31/32 use them in the same two positions. That is
    an arm9 rename outside this campaign's scope and is deliberately not taken
    here
    .
  • Retro-renaming slots 18-30, which borrowed dActor_c's labels by index, stays
    the owner's call.

Three slots left: 33, 34, 35.

Slot 32 of dScMgBase_c's 36-entry vtable, base body ov004:0x020b27f4.
One override in the whole family -- dScMgSlot3_c at ov006:0x0210aa60 --
which makes this the cheapest slot in the campaign after 22's zero.

Shipped as Virtual80, NOT AfterClsn, and this is the same defect settled
at slot 31 one fork further out.  AfterClsn IS a real ROM name:
include/PathLift.h:58 declares it and _ZN16dPathLiftActor_c9AfterClsnEi
is a genuine mangled symbol.  But dPathLiftActor_c derives from
dBgActor_c, which derives from dActor_c, and dScMgBase_c is a dScene_c:

    fBase_c -> dBase_c -> dActor_c -> dBgActor_c -> dPathLiftActor_c
    fBase_c -> dBase_c -> dScene_c -> dScMgBase_c

The chains share only dBase_c, which adds no virtual of its own, so the
two slot 32s have fBase_c's first eighteen entries in common and nothing
else.  That AfterClsn also takes an int; this slot takes nothing.  A
whole-image scan for the dispatch pair at +0x80 (ldr rN,[rM,#0x80] with
Rn != pc, then blx rN within three instructions) finds exactly three
sites: ov004:0x020b0900 on this branch, ov002:0x020effa4 and
ov064:0x02116e58 on that one.

Slots 31 and 32 are one function twice, against the two display engines.
31 is the SUB screen, called last by BeforeInitResources; 32 is the MAIN
screen, called first by AfterInitResources(u32).  Same three
read-modify-writes leaving BG1CNT at exactly the class's base bits, same
scroll reset, same &= ~2 on the engine's BG-enable shadow (data_0209d454
against data_0209d45c -- the two words slot 30 restores the DISPCNTs
from), same language-indexed character file plus a shared screen map,
file 0x5b against 0x67.  It touches no collision.

Arity measured at that one call site: ldr r2,[r0]; mov r5,r0;
ldr r2,[r2,#0x80]; mov r4,r1; blx r2.  r0 is `this`, and r1 is
AfterInitResources's own vfSuccess, parked in r4 BECAUSE the call
clobbers it.  Return type stays a hint for the fourth consecutive slot:
the caller overwrites r0 with a literal 2 on the next instruction.

Verification
  rombuild -j 16 --no-rom: 11,088/11,088 reproducing, 106/106 exact,
    100.000000% of compared bytes, ROM-build analysis PASS
  romdata_check vs the slot-31 baseline: verifiedBytes 35416 -> 35420
    (+4), partialBytes 11748 -> 11872 (+124).  128 bytes = 32 tables x
    one word, which is what declaring exactly one slot must cost.
    symbols 1246, verified 465, partial 253, differs 6, totalRecords
    7560 all unchanged; the differing set is unchanged in both
    directions.
  check_dead_references clean; port_refcheck 405/405;
    check_header_offsets --changed origin/main 0 mismatched;
    check_src_tu_compiles 97/97; check_duplicate_sources 11038 stems,
    none doubled; langmode ratchet PASS.

Three slots left: 33-35.
@andrewboudreau andrewboudreau added the attribution-override Maintainer accepts this PR's contributor-credit changes; validation reports them as warnings label Aug 31, 2026
@tangos-validator

tangos-validator Bot commented Aug 31, 2026

Copy link
Copy Markdown

✅ PR validation — Passed

Committed merge passes; 1 contributor credit reassignment(s) noted, not a blocker.

Full merge validation

Check Result
Committed test merge yes
Byte-verified functions 10,781 / 11,347 (95.01%, +0)
Byte-verified code bytes 2,004,460 / 2,211,124 (90.65%, +0)
Claimed, not byte-verified 436 functions, 101,220 bytes (+0)
Perfect source moves 0 R100
Enrolled ranges (delinks complete) 11,059 functions, 2,053,148 bytes (92.86%, +0) -- differs from byte-verified by +278
Contributor credit 0 added, 1 changed, 0 lost
Relocation check 302 checked; 302 VERIFIED
Port reference check 405 checked; 0 stale
Module fidelity 106/106 exact; 100.000000% compared bytes
Code linked from verified source 11,088 functions, 2,067,148 bytes (93.49%)
Module bytes from source 2,067,148 / 3,049,600 (67.8%); 811,492 (26.6%) are data no delink entry reaches
ROM data reproduced from source 465 symbol(s) exact, 253 partial, 6 differ

Contributor credit moved (1)

Function Source Before After
ov004:0x020b27f4 src/func_ov004_020b27f4.c -> src/_ZN11dScMgBase_c9Virtual80Ev.c tangosdev andrewboudreau

Byte-verified means the range carries complete in a delinks.txt, so the ROM build compiled it and compared it to the cartridge. The 436 claimed functions have a src/ file named after the symbol with no NONMATCHING banner, and nothing compiles them -- dsd fills their addresses with the ROM's own bytes. Both together are the 11,217 this project calls matched.

Warnings: contributor attribution changed, not a blocker (1 changed, 0 lost -- src/_ZN11dScMgBase_c9Virtual80Ev.c: tangosdev -> andrewboudreau).

Per-file link-check detail

All 192 changed file(s) compile to the ROM byte-for-byte with correct relocation targets.

File Symbol Result Slots checked
src/_ZN10dScMgCup_c13InitResourcesEv.cpp _ZN10dScMgCup_c13InitResourcesEv ✅ verified 1
src/_ZN10dScMgCup_c6RenderEv.cpp _ZN10dScMgCup_c6RenderEv ✅ verified 1
src/_ZN10dScMgCup_c8BehaviorEv.cpp _ZN10dScMgCup_c8BehaviorEv ✅ verified 1
src/_ZN10dScMgCup_cD0Ev.cpp _ZN10dScMgCup_cD0Ev ✅ verified 1
src/_ZN10dScMgCup_cD1Ev.cpp _ZN10dScMgCup_cD1Ev ✅ verified 1
src/_ZN11dScMgBase_c15OnHitByMegaCharEv.cpp _ZN11dScMgBase_c15OnHitByMegaCharEv ✅ verified 1
src/_ZN11dScMgBase_c15graphCallback_c14GraphCallback0Ev.cpp _ZN11dScMgBase_c15graphCallback_c14GraphCallback0Ev ✅ verified 1
src/_ZN11dScMgBase_c15graphCallback_c14GraphCallback1Ev.cpp _ZN11dScMgBase_c15graphCallback_c14GraphCallback1Ev ✅ verified 1
src/_ZN11dScMgBase_c15graphCallback_c14GraphCallback2Ev.cpp _ZN11dScMgBase_c15graphCallback_c14GraphCallback2Ev ✅ verified 1
src/_ZN11dScMgBase_c15graphCallback_c14GraphCallback3Ev.cpp _ZN11dScMgBase_c15graphCallback_c14GraphCallback3Ev ✅ verified 1
src/_ZN11dScMgBase_c16OnAimedAtWithEggEv.cpp _ZN11dScMgBase_c16OnAimedAtWithEggEv ✅ verified 1
src/_ZN11dScMgBase_c19OnHitFromUnderneathEv.cpp _ZN11dScMgBase_c19OnHitFromUnderneathEv ✅ verified 1
src/_ZN11dScMgBase_c25OnAimedAtWithEggReturnVecEv.cpp _ZN11dScMgBase_c25OnAimedAtWithEggReturnVecEv ✅ verified 1
src/_ZN11dScMgBase_c8OnPushedEv.cpp _ZN11dScMgBase_c8OnPushedEv ✅ verified 1
src/_ZN11dScMgBase_c9Virtual80Ev.c _ZN11dScMgBase_c9Virtual80Ev ✅ verified 1
src/_ZN11dScMgBase_cC2Ev.cpp _ZN11dScMgBase_cC2Ev ✅ verified 1
src/_ZN11dScMgBase_cD0Ev.cpp _ZN11dScMgBase_cD0Ev ✅ verified 1
src/_ZN11dScMgBase_cD1Ev.cpp _ZN11dScMgBase_cD1Ev ✅ verified 1
src/_ZN11dScMgBase_cD2Ev.cpp _ZN11dScMgBase_cD2Ev ✅ verified 1
src/_ZN11dScMgCoin_c13InitResourcesEv.cpp _ZN11dScMgCoin_c13InitResourcesEv ✅ verified 1
src/_ZN11dScMgCoin_c13OnYoshiTryEatEi.cpp _ZN11dScMgCoin_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN11dScMgCoin_c6RenderEv.cpp _ZN11dScMgCoin_c6RenderEv ✅ verified 1
src/_ZN11dScMgCoin_c8BehaviorEv.cpp _ZN11dScMgCoin_c8BehaviorEv ✅ verified 1
src/_ZN11dScMgCoin_cD0Ev.cpp _ZN11dScMgCoin_cD0Ev ✅ verified 1
src/_ZN11dScMgCoin_cD1Ev.cpp _ZN11dScMgCoin_cD1Ev ✅ verified 1
src/_ZN11dScMgJump_c13InitResourcesEv.cpp _ZN11dScMgJump_c13InitResourcesEv ✅ verified 1
src/_ZN11dScMgJump_c13OnTurnIntoEggEi.cpp _ZN11dScMgJump_c13OnTurnIntoEggEi ✅ verified 1
src/_ZN11dScMgJump_c16CleanupResourcesEv.cpp _ZN11dScMgJump_c16CleanupResourcesEv ✅ verified 1
src/_ZN11dScMgJump_c6RenderEv.cpp _ZN11dScMgJump_c6RenderEv ✅ verified 1
src/_ZN11dScMgJump_c8BehaviorEv.cpp _ZN11dScMgJump_c8BehaviorEv ✅ verified 1
src/_ZN11dScMgJump_cD0Ev.cpp _ZN11dScMgJump_cD0Ev ✅ verified 1
src/_ZN11dScMgJump_cD1Ev.cpp _ZN11dScMgJump_cD1Ev ✅ verified 1
src/_ZN12dScMg3DEsp_c13InitResourcesEv.cpp _ZN12dScMg3DEsp_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMg3DEsp_c13OnYoshiTryEatEi.cpp _ZN12dScMg3DEsp_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN12dScMg3DEsp_c16CleanupResourcesEv.cpp _ZN12dScMg3DEsp_c16CleanupResourcesEv ✅ verified 1
src/_ZN12dScMg3DEsp_c6RenderEv.cpp _ZN12dScMg3DEsp_c6RenderEv ✅ verified 1
src/_ZN12dScMg3DEsp_c8BehaviorEv.cpp _ZN12dScMg3DEsp_c8BehaviorEv ✅ verified 1
src/_ZN12dScMg3DEsp_cD0Ev.cpp _ZN12dScMg3DEsp_cD0Ev ✅ verified 1
src/_ZN12dScMg3DEsp_cD1Ev.cpp _ZN12dScMg3DEsp_cD1Ev ✅ verified 1
src/_ZN12dScMgAmida_c13InitResourcesEv.cpp _ZN12dScMgAmida_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgAmida_c21AfterCleanupResourcesEj.cpp _ZN12dScMgAmida_c21AfterCleanupResourcesEj ✅ verified 1
src/_ZN12dScMgAmida_c5Unk36Ev.cpp _ZN12dScMgAmida_c5Unk36Ev ✅ verified 1
src/_ZN12dScMgAmida_c6RenderEv.cpp _ZN12dScMgAmida_c6RenderEv ✅ verified 1
src/_ZN12dScMgAmida_c8BehaviorEv.cpp _ZN12dScMgAmida_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgAmida_cD0Ev.cpp _ZN12dScMgAmida_cD0Ev ✅ verified 1
src/_ZN12dScMgAmida_cD1Ev.cpp _ZN12dScMgAmida_cD1Ev ✅ verified 1
src/_ZN12dScMgJump2_c13InitResourcesEv.cpp _ZN12dScMgJump2_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgJump2_c16CleanupResourcesEv.cpp _ZN12dScMgJump2_c16CleanupResourcesEv ✅ verified 1
src/_ZN12dScMgJump2_c6RenderEv.cpp _ZN12dScMgJump2_c6RenderEv ✅ verified 1
src/_ZN12dScMgJump2_c8BehaviorEv.cpp _ZN12dScMgJump2_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgJump2_cD0Ev.cpp _ZN12dScMgJump2_cD0Ev ✅ verified 1
src/_ZN12dScMgJump2_cD1Ev.cpp _ZN12dScMgJump2_cD1Ev ✅ verified 1
src/_ZN12dScMgLuigi_c13InitResourcesEv.cpp _ZN12dScMgLuigi_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgLuigi_c21AfterCleanupResourcesEj.cpp _ZN12dScMgLuigi_c21AfterCleanupResourcesEj ✅ verified 1
src/_ZN12dScMgLuigi_c6RenderEv.cpp _ZN12dScMgLuigi_c6RenderEv ✅ verified 1
src/_ZN12dScMgLuigi_c8BehaviorEv.cpp _ZN12dScMgLuigi_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgLuigi_cD0Ev.cpp _ZN12dScMgLuigi_cD0Ev ✅ verified 1
src/_ZN12dScMgLuigi_cD1Ev.cpp _ZN12dScMgLuigi_cD1Ev ✅ verified 1
src/_ZN12dScMgPanel_c13InitResourcesEv.cpp _ZN12dScMgPanel_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgPanel_c6RenderEv.cpp _ZN12dScMgPanel_c6RenderEv ✅ verified 1
src/_ZN12dScMgPanel_c8BehaviorEv.cpp _ZN12dScMgPanel_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgPanel_cD0Ev.cpp _ZN12dScMgPanel_cD0Ev ✅ verified 1
src/_ZN12dScMgPanel_cD1Ev.cpp _ZN12dScMgPanel_cD1Ev ✅ verified 1
src/_ZN12dScMgSlot1_c13InitResourcesEv.cpp _ZN12dScMgSlot1_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgSlot1_c15OnHitByMegaCharEv.cpp _ZN12dScMgSlot1_c15OnHitByMegaCharEv ✅ verified 1
src/_ZN12dScMgSlot1_c19OnHitFromUnderneathEv.cpp _ZN12dScMgSlot1_c19OnHitFromUnderneathEv ✅ verified 1
src/_ZN12dScMgSlot1_c6RenderEv.cpp _ZN12dScMgSlot1_c6RenderEv ✅ verified 1
src/_ZN12dScMgSlot1_c9betIcon_c6RenderEv.cpp _ZN12dScMgSlot1_c9betIcon_c6RenderEv ✅ verified 1
src/_ZN12dScMgSlot1_c9betIcon_c8BehaviorEv.cpp _ZN12dScMgSlot1_c9betIcon_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgSlot1_cD0Ev.cpp _ZN12dScMgSlot1_cD0Ev ✅ verified 1
src/_ZN12dScMgSlot1_cD1Ev.cpp _ZN12dScMgSlot1_cD1Ev ✅ verified 1
src/_ZN12dScMgSlot3_c13InitResourcesEv.cpp _ZN12dScMgSlot3_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgSlot3_c6RenderEv.cpp _ZN12dScMgSlot3_c6RenderEv ✅ verified 1
src/_ZN12dScMgSlot3_c8BehaviorEv.cpp _ZN12dScMgSlot3_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgSlot3_c9Virtual80Ev.cpp _ZN12dScMgSlot3_c9Virtual80Ev ✅ verified 1
src/_ZN12dScMgSlot3_cD0Ev.cpp _ZN12dScMgSlot3_cD0Ev ✅ verified 1
src/_ZN12dScMgSlot3_cD1Ev.cpp _ZN12dScMgSlot3_cD1Ev ✅ verified 1
src/_ZN12dScMgSound_c13InitResourcesEv.cpp _ZN12dScMgSound_c13InitResourcesEv ✅ verified 1
src/_ZN12dScMgSound_c6RenderEv.cpp _ZN12dScMgSound_c6RenderEv ✅ verified 1
src/_ZN12dScMgSound_c8BehaviorEv.cpp _ZN12dScMgSound_c8BehaviorEv ✅ verified 1
src/_ZN12dScMgSound_cD0Ev.cpp _ZN12dScMgSound_cD0Ev ✅ verified 1
src/_ZN12dScMgSound_cD1Ev.cpp _ZN12dScMgSound_cD1Ev ✅ verified 1
src/_ZN13dScMgFlower_c13InitResourcesEv.cpp _ZN13dScMgFlower_c13InitResourcesEv ✅ verified 1
src/_ZN13dScMgFlower_c6RenderEv.cpp _ZN13dScMgFlower_c6RenderEv ✅ verified 1
src/_ZN13dScMgFlower_c8BehaviorEv.cpp _ZN13dScMgFlower_c8BehaviorEv ✅ verified 1
src/_ZN13dScMgFlower_cD0Ev.cpp _ZN13dScMgFlower_cD0Ev ✅ verified 1
src/_ZN13dScMgFlower_cD1Ev.cpp _ZN13dScMgFlower_cD1Ev ✅ verified 1
src/_ZN13dScMgMemory_c13InitResourcesEv.cpp _ZN13dScMgMemory_c13InitResourcesEv ✅ verified 1
src/_ZN13dScMgMemory_c13OnTurnIntoEggEi.c _ZN13dScMgMemory_c13OnTurnIntoEggEi ✅ verified 1
src/_ZN13dScMgMemory_c13OnYoshiTryEatEi.c _ZN13dScMgMemory_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN13dScMgMemory_c15OnGroundPoundedEv.c _ZN13dScMgMemory_c15OnGroundPoundedEv ✅ verified 1
src/_ZN13dScMgMemory_c6RenderEv.cpp _ZN13dScMgMemory_c6RenderEv ✅ verified 1
src/_ZN13dScMgMemory_c8BehaviorEv.cpp _ZN13dScMgMemory_c8BehaviorEv ✅ verified 1
src/_ZN13dScMgMemory_cD0Ev.cpp _ZN13dScMgMemory_cD0Ev ✅ verified 1
src/_ZN13dScMgMemory_cD1Ev.cpp _ZN13dScMgMemory_cD1Ev ✅ verified 1
src/_ZN13dScMgTeresa_c13InitResourcesEv.cpp _ZN13dScMgTeresa_c13InitResourcesEv ✅ verified 1
src/_ZN13dScMgTeresa_c6RenderEv.cpp _ZN13dScMgTeresa_c6RenderEv ✅ verified 1
src/_ZN13dScMgTeresa_c8BehaviorEv.cpp _ZN13dScMgTeresa_c8BehaviorEv ✅ verified 1
src/_ZN13dScMgTeresa_cD0Ev.cpp _ZN13dScMgTeresa_cD0Ev ✅ verified 1
src/_ZN13dScMgTeresa_cD1Ev.cpp _ZN13dScMgTeresa_cD1Ev ✅ verified 1
src/_ZN14dScMgBomroom_c13InitResourcesEv.cpp _ZN14dScMgBomroom_c13InitResourcesEv ✅ verified 1
src/_ZN14dScMgBomroom_c6RenderEv.cpp _ZN14dScMgBomroom_c6RenderEv ✅ verified 1
src/_ZN14dScMgBomroom_c8BehaviorEv.cpp _ZN14dScMgBomroom_c8BehaviorEv ✅ verified 1
src/_ZN14dScMgBomroom_cD0Ev.cpp _ZN14dScMgBomroom_cD0Ev ✅ verified 1
src/_ZN14dScMgBomroom_cD1Ev.cpp _ZN14dScMgBomroom_cD1Ev ✅ verified 1
src/_ZN14dScMgCurling_c13InitResourcesEv.cpp _ZN14dScMgCurling_c13InitResourcesEv ✅ verified 1
src/_ZN14dScMgCurling_c13OnYoshiTryEatEi.cpp _ZN14dScMgCurling_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN14dScMgCurling_c6RenderEv.cpp _ZN14dScMgCurling_c6RenderEv ✅ verified 1
src/_ZN14dScMgCurling_c8BehaviorEv.cpp _ZN14dScMgCurling_c8BehaviorEv ✅ verified 1
src/_ZN14dScMgCurling_cD0Ev.cpp _ZN14dScMgCurling_cD0Ev ✅ verified 1
src/_ZN14dScMgCurling_cD1Ev.cpp _ZN14dScMgCurling_cD1Ev ✅ verified 1
src/_ZN14dScMgD3DBase_c11AfterRenderEj.cpp _ZN14dScMgD3DBase_c11AfterRenderEj ✅ verified 1
src/_ZN14dScMgD3DBase_c12BeforeRenderEv.cpp _ZN14dScMgD3DBase_c12BeforeRenderEv ✅ verified 1
src/_ZN14dScMgD3DBase_c14BeforeBehaviorEv.cpp _ZN14dScMgD3DBase_c14BeforeBehaviorEv ✅ verified 1
src/_ZN14dScMgD3DBase_c16OnAimedAtWithEggEv.cpp _ZN14dScMgD3DBase_c16OnAimedAtWithEggEv ✅ verified 1
src/_ZN14dScMgD3DBase_c18AfterInitResourcesEj.cpp _ZN14dScMgD3DBase_c18AfterInitResourcesEj ✅ verified 1
src/_ZN14dScMgD3DBase_c19BeforeInitResourcesEv.cpp _ZN14dScMgD3DBase_c19BeforeInitResourcesEv ✅ verified 1
src/_ZN14dScMgD3DBase_c21AfterCleanupResourcesEj.cpp _ZN14dScMgD3DBase_c21AfterCleanupResourcesEj ✅ verified 1
src/_ZN14dScMgD3DBase_c25OnAimedAtWithEggReturnVecEv.c _ZN14dScMgD3DBase_c25OnAimedAtWithEggReturnVecEv ✅ verified 1
src/_ZN14dScMgD3DBase_c9Virtual7CEv.c _ZN14dScMgD3DBase_c9Virtual7CEv ✅ verified 1
src/_ZN14dScMgD3DBase_cD0Ev.cpp _ZN14dScMgD3DBase_cD0Ev ✅ verified 1
src/_ZN14dScMgD3DBase_cD1Ev.cpp _ZN14dScMgD3DBase_cD1Ev ✅ verified 1
src/_ZN14dScMgMemory2_c13InitResourcesEv.cpp _ZN14dScMgMemory2_c13InitResourcesEv ✅ verified 1
src/_ZN14dScMgMemory2_c13OnTurnIntoEggEi.c _ZN14dScMgMemory2_c13OnTurnIntoEggEi ✅ verified 1
src/_ZN14dScMgMemory2_c13OnYoshiTryEatEi.c _ZN14dScMgMemory2_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN14dScMgMemory2_c15OnGroundPoundedEv.c _ZN14dScMgMemory2_c15OnGroundPoundedEv ✅ verified 1
src/_ZN14dScMgMemory2_c6RenderEv.cpp _ZN14dScMgMemory2_c6RenderEv ✅ verified 1
src/_ZN14dScMgMemory2_c8BehaviorEv.cpp _ZN14dScMgMemory2_c8BehaviorEv ✅ verified 1
src/_ZN14dScMgMemory2_cD0Ev.cpp _ZN14dScMgMemory2_cD0Ev ✅ verified 1
src/_ZN14dScMgMemory2_cD1Ev.cpp _ZN14dScMgMemory2_cD1Ev ✅ verified 1
src/_ZN15dScMgCurling2_c13InitResourcesEv.cpp _ZN15dScMgCurling2_c13InitResourcesEv ✅ verified 1
src/_ZN15dScMgCurling2_c13OnYoshiTryEatEi.cpp _ZN15dScMgCurling2_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN15dScMgCurling2_c6RenderEv.cpp _ZN15dScMgCurling2_c6RenderEv ✅ verified 1
src/_ZN15dScMgCurling2_c8BehaviorEv.cpp _ZN15dScMgCurling2_c8BehaviorEv ✅ verified 1
src/_ZN15dScMgCurling2_cD0Ev.cpp _ZN15dScMgCurling2_cD0Ev ✅ verified 1
src/_ZN15dScMgCurling2_cD1Ev.cpp _ZN15dScMgCurling2_cD1Ev ✅ verified 1
src/_ZN15dScMgHanachan_c13InitResourcesEv.cpp _ZN15dScMgHanachan_c13InitResourcesEv ✅ verified 1
src/_ZN15dScMgHanachan_c16CleanupResourcesEv.cpp _ZN15dScMgHanachan_c16CleanupResourcesEv ✅ verified 1
src/_ZN15dScMgHanachan_c6RenderEv.cpp _ZN15dScMgHanachan_c6RenderEv ✅ verified 1
src/_ZN15dScMgHanachan_c8BehaviorEv.cpp _ZN15dScMgHanachan_c8BehaviorEv ✅ verified 1
src/_ZN15dScMgHanachan_cD0Ev.cpp _ZN15dScMgHanachan_cD0Ev ✅ verified 1
src/_ZN15dScMgHanachan_cD1Ev.cpp _ZN15dScMgHanachan_cD1Ev ✅ verified 1
src/_ZN15dScMgPachinko_c13InitResourcesEv.cpp _ZN15dScMgPachinko_c13InitResourcesEv ✅ verified 1
src/_ZN15dScMgPachinko_c6RenderEv.cpp _ZN15dScMgPachinko_c6RenderEv ✅ verified 1
src/_ZN15dScMgPachinko_c8BehaviorEv.cpp _ZN15dScMgPachinko_c8BehaviorEv ✅ verified 1
src/_ZN15dScMgPachinko_cD0Ev.cpp _ZN15dScMgPachinko_cD0Ev ✅ verified 1
src/_ZN15dScMgPachinko_cD1Ev.cpp _ZN15dScMgPachinko_cD1Ev ✅ verified 1
src/_ZN15dScMgRoulette_c13InitResourcesEv.cpp _ZN15dScMgRoulette_c13InitResourcesEv ✅ verified 1
src/_ZN15dScMgRoulette_c13OnYoshiTryEatEi.cpp _ZN15dScMgRoulette_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN15dScMgRoulette_c16CleanupResourcesEv.cpp _ZN15dScMgRoulette_c16CleanupResourcesEv ✅ verified 1
src/_ZN15dScMgRoulette_c6RenderEv.cpp _ZN15dScMgRoulette_c6RenderEv ✅ verified 1
src/_ZN15dScMgRoulette_c8BehaviorEv.cpp _ZN15dScMgRoulette_c8BehaviorEv ✅ verified 1
src/_ZN15dScMgRoulette_cD0Ev.cpp _ZN15dScMgRoulette_cD0Ev ✅ verified 1
src/_ZN15dScMgRoulette_cD1Ev.cpp _ZN15dScMgRoulette_cD1Ev ✅ verified 1
src/_ZN15dScMgSnowball_c13InitResourcesEv.cpp _ZN15dScMgSnowball_c13InitResourcesEv ✅ verified 1
src/_ZN15dScMgSnowball_c16CleanupResourcesEv.cpp _ZN15dScMgSnowball_c16CleanupResourcesEv ✅ verified 1
src/_ZN15dScMgSnowball_c6RenderEv.cpp _ZN15dScMgSnowball_c6RenderEv ✅ verified 1
src/_ZN15dScMgSnowball_c8BehaviorEv.cpp _ZN15dScMgSnowball_c8BehaviorEv ✅ verified 1
src/_ZN15dScMgSnowball_c8OnKickedEv.c _ZN15dScMgSnowball_c8OnKickedEv ✅ verified 1
src/_ZN15dScMgSnowball_cD0Ev.cpp _ZN15dScMgSnowball_cD0Ev ✅ verified 1
src/_ZN15dScMgSnowball_cD1Ev.cpp _ZN15dScMgSnowball_cD1Ev ✅ verified 1
src/_ZN16dScMgPachinko2_c13InitResourcesEv.cpp _ZN16dScMgPachinko2_c13InitResourcesEv ✅ verified 1
src/_ZN16dScMgPachinko2_c6RenderEv.cpp _ZN16dScMgPachinko2_c6RenderEv ✅ verified 1
src/_ZN16dScMgPachinko2_c8BehaviorEv.cpp _ZN16dScMgPachinko2_c8BehaviorEv ✅ verified 1
src/_ZN16dScMgPachinko2_cD0Ev.cpp _ZN16dScMgPachinko2_cD0Ev ✅ verified 1
src/_ZN16dScMgPachinko2_cD1Ev.cpp _ZN16dScMgPachinko2_cD1Ev ✅ verified 1
src/_ZN16dScMgSmartball_c21AfterCleanupResourcesEj.cpp _ZN16dScMgSmartball_c21AfterCleanupResourcesEj ✅ verified 1
src/_ZN16dScMgSmartball_c6RenderEv.cpp _ZN16dScMgSmartball_c6RenderEv ✅ verified 1
src/_ZN16dScMgSmartball_c8BehaviorEv.cpp _ZN16dScMgSmartball_c8BehaviorEv ✅ verified 1
src/_ZN16dScMgSmartball_cD0Ev.cpp _ZN16dScMgSmartball_cD0Ev ✅ verified 1
src/_ZN16dScMgSmartball_cD1Ev.cpp _ZN16dScMgSmartball_cD1Ev ✅ verified 1
src/_ZN17dScMgTrampoline_c13InitResourcesEv.cpp _ZN17dScMgTrampoline_c13InitResourcesEv ✅ verified 1
src/_ZN17dScMgTrampoline_c13OnYoshiTryEatEi.c _ZN17dScMgTrampoline_c13OnYoshiTryEatEi ✅ verified 1
src/_ZN17dScMgTrampoline_c16CleanupResourcesEv.cpp _ZN17dScMgTrampoline_c16CleanupResourcesEv ✅ verified 1
src/_ZN17dScMgTrampoline_c6RenderEv.cpp _ZN17dScMgTrampoline_c6RenderEv ✅ verified 1
src/_ZN17dScMgTrampoline_c8BehaviorEv.cpp _ZN17dScMgTrampoline_c8BehaviorEv ✅ verified 1
src/_ZN17dScMgTrampoline_cD0Ev.cpp _ZN17dScMgTrampoline_cD0Ev ✅ verified 1
src/_ZN17dScMgTrampoline_cD1Ev.cpp _ZN17dScMgTrampoline_cD1Ev ✅ verified 1
src/_ZN18dScMgTrampoline2_c13InitResourcesEv.cpp _ZN18dScMgTrampoline2_c13InitResourcesEv ✅ verified 1
src/_ZN18dScMgTrampoline2_c16CleanupResourcesEv.cpp _ZN18dScMgTrampoline2_c16CleanupResourcesEv ✅ verified 1
src/_ZN18dScMgTrampoline2_c6RenderEv.cpp _ZN18dScMgTrampoline2_c6RenderEv ✅ verified 1
src/_ZN18dScMgTrampoline2_c8BehaviorEv.cpp _ZN18dScMgTrampoline2_c8BehaviorEv ✅ verified 1
src/_ZN18dScMgTrampoline2_cD0Ev.cpp _ZN18dScMgTrampoline2_cD0Ev ✅ verified 1
src/_ZN18dScMgTrampoline2_cD1Ev.cpp _ZN18dScMgTrampoline2_cD1Ev ✅ verified 1
src/actors/dScMgBSC_c.cpp _ZN10dScMgBSC_cD1Ev + _ZN10dScMgBSC_cD0Ev + func_ov006_02124a04 + func_ov006_02124a08 + func_ov006_02124ae4 + func_ov006_02124b58 + func_ov006_02124bb4 + func_ov006_02124cb4 + func_ov006_02124dc0 + func_ov006_02124e1c + func_ov006_02124ec4 + func_ov006_02124fd8 + func_ov006_021250e4 + _ZN10dScMgBSC_c15OnGroundPoundedEv + _ZN10dScMgBSC_c13OnTurnIntoEggEi + _ZN10dScMgBSC_c13OnYoshiTryEatEi + _ZN10dScMgBSC_c6RenderEv + _ZN10dScMgBSC_c8BehaviorEv + _ZN10dScMgBSC_c13InitResourcesEv ✅ verified 19
src/actors/dScMgBase_c.cpp _ZN11dScMgBase_c16OnPendingDestroyEv + _ZN11dScMgBase_c6RenderEv + _ZN11dScMgBase_c12BeforeRenderEv + _ZN11dScMgBase_c8BehaviorEv + _ZN11dScMgBase_c14BeforeBehaviorEv + _ZN11dScMgBase_c21AfterCleanupResourcesEj + _ZN11dScMgBase_c18AfterInitResourcesEj + _ZN11dScMgBase_c19BeforeInitResourcesEv ✅ verified 8
src/actors/dScMgCard_c.cpp _ZN11dScMgCard_cD1Ev + _ZN11dScMgCard_cD0Ev + func_ov006_020d96e0 + func_ov006_020d96f0 + func_ov006_020d970c + func_ov006_020d978c + func_ov006_020d9998 + func_ov006_020d99a4 + func_ov006_020d99ec + func_ov006_020d9a14 + func_ov006_020d9bd0 + func_ov006_020d9bdc + func_ov006_020d9c5c + func_ov006_020da00c + func_ov006_020da0ac + func_ov006_020da154 + func_ov006_020da174 + func_ov006_020da420 + func_ov006_020da4ac + func_ov006_020da5e8 + func_ov006_020da834 + func_ov006_020da860 + func_ov006_020da88c + func_ov006_020da8b8 + func_ov006_020da8e4 + func_ov006_020da974 + _ZN11dScMgCard_c16CleanupResourcesEv + _ZN11dScMgCard_c6RenderEv + _ZN11dScMgCard_c8BehaviorEv + func_ov006_020dac34 + _ZN11dScMgCard_c15OnGroundPoundedEv + _ZN11dScMgCard_c13OnTurnIntoEggEi + _ZN11dScMgCard_c13OnYoshiTryEatEi + _ZN11dScMgCard_c13InitResourcesEv ✅ verified 34
src/actors/dScMgMCarlo2_c.cpp _ZN14dScMgMCarlo2_cD1Ev + _ZN14dScMgMCarlo2_cD0Ev + func_ov006_020f8ff0 + func_ov006_020f9000 + func_ov006_020f94f4 + func_ov006_020f9560 + func_ov006_020f95f0 + func_ov006_020f9668 + func_ov006_020f96e0 + func_ov006_020f9760 + func_ov006_020f98dc + func_ov006_020f9994 + func_ov006_020f9bec + func_ov006_020f9cbc + func_ov006_020f9d68 + func_ov006_020f9db8 + func_ov006_020f9f40 + _ZN14dScMgMCarlo2_c16CleanupResourcesEv + _ZN14dScMgMCarlo2_c6RenderEv + _ZN14dScMgMCarlo2_c8BehaviorEv + _ZN14dScMgMCarlo2_c13OnTurnIntoEggEi + _ZN14dScMgMCarlo2_c13OnYoshiTryEatEi + _ZN14dScMgMCarlo2_c13InitResourcesEv ✅ verified 23
src/actors/dScMgMCarlo_c.cpp _ZN13dScMgMCarlo_cD1Ev + _ZN13dScMgMCarlo_cD0Ev + func_ov006_020f7730 + func_ov006_020f7740 + func_ov006_020f7994 + func_ov006_020f7a00 + func_ov006_020f7a90 + func_ov006_020f7b10 + func_ov006_020f7b90 + func_ov006_020f7c10 + func_ov006_020f7e2c + func_ov006_020f7ee4 + func_ov006_020f8154 + func_ov006_020f8224 + func_ov006_020f82d0 + func_ov006_020f8320 + func_ov006_020f84a8 + func_ov006_020f8540 + _ZN13dScMgMCarlo_c6RenderEv + _ZN13dScMgMCarlo_c8BehaviorEv + _ZN13dScMgMCarlo_c13OnTurnIntoEggEi + _ZN13dScMgMCarlo_c13OnYoshiTryEatEi + _ZN13dScMgMCarlo_c13InitResourcesEv ✅ verified 23
src/actors/dScMgSingle3DBase_c.cpp _ZN19dScMgSingle3DBase_cD1Ev + _ZN19dScMgSingle3DBase_cD0Ev + func_ov006_0210a534 + _ZN19dScMgSingle3DBase_c24OnHitByCannonBlastedCharEv + _ZN19dScMgSingle3DBase_c21AfterCleanupResourcesEj + _ZN19dScMgSingle3DBase_c12BeforeRenderEv + _ZN19dScMgSingle3DBase_c14BeforeBehaviorEv + _ZN19dScMgSingle3DBase_c18AfterInitResourcesEj + func_ov006_0210a708 ✅ verified 9
src/func_ov004_020b0a54.cpp func_ov004_020b0a54 ✅ verified 1
src/func_ov006_0210d6b8.cpp func_ov006_0210d6b8 ✅ verified 1

The private worker commits a test merge, builds the stock ROM profile, compares every executable module, measures matched and source-built code, checks contributor lineage, and verifies affected relocations. The mod profile is opt-in and is not part of this merge gate.

@andrewboudreau

Copy link
Copy Markdown
Collaborator Author

Self-review. I wrote this, and this repo has one shared account so no PR here can be APPROVED by a second identity — signing off in a comment instead, with what I checked and what I could not.

Verified on the merge tree, not just the branch. tools/premerge_check.py --base origin/main --fetch 2099 2100 2102 2106 2107 — all five merge trees green on all eight static gates (converted-ratchet, dead-references, duplicate-sources, header-offsets, langmode-ratchet, layout-check, src-tu-refs, source-coverage), nothing base-green goes merge-red. Merge tree for this PR: b3e8ff5dc919, head 567649493a6b.

Byte evidence. rombuild -j16 --no-rom 11,088/11,088 reproducing, 106/106 exact, 100.000000%. romdata_check --json diffed field by field against the slot-31 baseline: verifiedBytes 35416 → 35420 (+4), partialBytes 11748 → 11872 (+124). Every other counter identical — symbols 1246, verified 465, partial 253, differs 6, totalRecords 7560, sourcesChecked 10811 — and the differing set is unchanged in both directions (nothing gained, nothing lost). +128 is 32 tables × one word, the same arithmetic every slot in this campaign has hit.

Also clean: check_dead_references, port_refcheck 405/405, check_header_offsets --changed origin/main 0 mismatched, check_src_tu_compiles 97/97, check_duplicate_sources 11038 stems with none doubled, langmode ratchet PASS.

Why the name is Virtual80 and not AfterClsn, which is the part worth reviewing. AfterClsn is a real ROM name — include/PathLift.h:58 declares virtual void AfterClsn(int clsnResult); and _ZN16dPathLiftActor_c9AfterClsnEi is a genuine mangled symbol. That makes it look stronger than Kill was at slot 31. Measured, it is weaker:

  • dPathLiftActor_c : dBgActor_c : dActor_c. Slot 31 established that dScMgBase_c is on the sibling branch (fBase_c → dBase_c → dScene_c → dScMgBase_c), so dActor_c is already one fork away. dPathLiftActor_c is two forks away.
  • The real AfterClsn takes an int. This slot takes nothing (measured below). Same index, different signature, different branch — the label was carried across a fork, not down a chain.

So this ships as Virtual80, the offset spelling fBase_c already uses for Virtual34/Virtual38 and the one slots 33–35 are recorded under.

Arity, measured. Dispatch-pair scan across arm9 and all 103 overlays for ldr rN,[rM,#0x80] followed by blx rN. Three refinements matter and I got two of them wrong first: the ARM mask is insn & 0x0FF00FFF == 0x05900000|off (0x0FFF0FFF is wrong — bits 19-16 are Rn); Rn == 15 must be excluded or pc-relative literal-pool loads swamp the result; and up to 3 intervening instructions must be allowed, because strict adjacency returns zero ov004/ov006 hits here and would have let me claim "no in-family call site." The real site is ov004:0x020b0900 inside AfterInitResources, with mov r4,r1 sitting between the ldr and the blx. That scan defect was present at slot 31 too; it under-reports, it does not over-report, so slot 31's conclusion stands.

What it actually does — 31 and 32 are one function twice, once per display engine. Slot 31 is the SUB screen and is called last by BeforeInitResources(); slot 32 is the MAIN screen and is called first by AfterInitResources(u32). Same three read-modify-writes leaving BG1CNT at the class's base bits, same scroll reset, same &= ~2 on the engine's BG-enable shadow — data_0209d454 for sub, data_0209d45c for main, which are exactly the two words slot 30 restores the DISPCNTs from. Same language-indexed character file plus a shared screen map (file 0x5b sub, 0x67 main). That symmetry is independent support for slot 31's "this is setup, not teardown" finding.

What this PR does NOT establish, on the record:

  • Virtual80 is a placeholder, not a ROM-derived name. RTTI carries class names only.
  • Return type int is a HINT — the fourth consecutive slot no body pins.
  • func_02054ea8 is almost certainly G2::GetBG1CharPtr by position symmetry with the sub-screen twin. That is an arm9 rename and I deliberately did not take it inside a slot commit; the evidence is recorded in the notes and the PR body instead.
  • Retro-renaming slots 18–30 now that the borrowed-label premise is settled remains your call, not something to slip into a slot commit.

Three slots left: 33, 34, 35. Slot 35 closes _ZTV12dScMgAmida_c and takes _ZTV11dScMgBase_c from PARTIAL to VERIFIED.

Landing stays with you.

@andrewboudreau andrewboudreau left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 567649493a6b. Three asks. One is the systemic return-type split that already holds the four PRs below this; one is an evidence-strength claim I checked hard and could not sustain; one is a word. The config half is clean, and I want to say that first, because on the two PRs either side of this stack the config half is exactly where the defect was.

The config half is clean, and I looked for a specific thing

Both renames are address- and size-preserving:

ov004  -func_ov004_020b27f4          kind:function(arm,size=0x8c)  addr:0x020b27f4
       +_ZN11dScMgBase_c9Virtual80Ev kind:function(arm,size=0x8c)  addr:0x020b27f4
ov006  -func_ov006_0210aa60           kind:function(arm,size=0xa8)  addr:0x0210aa60
       +_ZN12dScMgSlot3_c9Virtual80Ev kind:function(arm,size=0xa8)  addr:0x0210aa60

No coined data symbols anywhere in the diff. I checked for that specifically — I have open changes-requested on #2096 and #2104 over names invented for data_ovNNN_* rows sitting inside a _ZTV extent, and this PR does not do it.

Neither renamed file changed a line of code. I diffed both across the rename with git diff -M; the only hunks are the // @symbol line and comments.

Virtual80 is the right spelling — slot 32 is vtable+0x80, and Virtual7C and Virtual50 are already tracked, so this invents no convention.

Static gates on the real merge tree, both bases:

vs origin/cpp/minigame-slot31   8/8 pass -> pass
vs origin/main                  8/8 pass -> pass

1. The return-type split, now the seventh and eighth

include/dScMgBase_c.h:703    virtual int  Virtual80();    /* slot 32 */
include/dScMgSlot3_c.h:61    virtual int  Virtual80();    /* slot 32 */

src/_ZN11dScMgBase_c9Virtual80Ev.c:28      void _ZN11dScMgBase_c9Virtual80Ev(void)
src/_ZN12dScMgSlot3_c9Virtual80Ev.cpp:29   extern "C" void _ZN12dScMgSlot3_c9Virtual80Ev(void)

The dScMgBase_c census across the stack:

ref header/definition mismatches
origin/main 2
origin/cpp/minigame-slot30 5
origin/cpp/minigame-slot31 6
origin/cpp/minigame-slot32 7

Plus dScMgSlot3_c::Virtual80, an eighth distinct symbol in a different class. Every one is header int / definition void. Nothing in the tree compares those two surfaces, so this compiles and links clean — Virtual80 is absent from include/decl_common.h, so the checker I opened in #2105 reports nothing here either. That gap is mine and I will close it.

On the other four I asked only for consistency and left the choice to you. Here I want to recommend void, and I think this PR supplies the argument for it.

Two reasons, both from your own work.

Your notes file already says void. notes/dScMgBase_c-slots-18-35.md on this branch:

| 29 | 0x74 | ... | OnAimedAtWithEgg          | void(Obj*)  |
| 30 | 0x78 | ... | OnAimedAtWithEggReturnVec | void(char*) |
| 31 | 0x7C | ... | (none) -> Virtual7C       | void(void)  |
| 32 | 0x80 | ... | (none) -> Virtual80       | void(void)  |

Four rows, four void. The headers say int for all four. The notes read as the considered artifact; the headers read as the accident.

The "keep int, return the free r0 value" escape does not travel to the override. For the base it does — the body's last statement is LoadCompressedFileAt(...), so the value is already in r0. For dScMgSlot3_c::Virtual80 the last statement is a volatile store:

*(volatile unsigned short*)0x400000a = (*(volatile unsigned short*)0x400000a & 0x43) | 0x1118;

There is no free return value there. Taking the int route on this PR means finding something to return in a body that ends by writing hardware — which is where a return 0; gets manufactured, and that is a mov r0,#0 the ROM does not have. Declaring void in both headers costs one word each and matches what both bodies actually do.

Either resolution is acceptable to me. Split is not, and I would rather it were settled once at the base of the stack than patched five times.

2. MEASURED overstates the arity evidence

The header says:

arity: no explicit parameters, MEASURED at that one call site.

I tried to confirm this and found that the load-bearing step does not hold. Everything below is measured. The site count and the branch identification are yours, and both check out.

Your three-site count is right, and so is the other-branch call. I confirmed +0x80 dispatch pairs at exactly ov004:0x020b0900, ov002:0x020effa4 and ov064:0x02116e58 across arm9 and 103 overlays. And I can now show the dPathLiftActor_c half positively rather than take it on trust — three vtables put AfterClsn at slot 32:

ov002/relocs.txt  from:0x0210aff0 to:0x020eff18   _ZTV16dPathLiftActor_c @0x0210af70  +0x80
ov036/relocs.txt  from:0x0211401c to:0x020eff18   _ZTV15daObjRcCarpet_c  @0x02113f9c  +0x80
ov100/relocs.txt  from:0x021485fc to:0x020eff18   _ZTV15daObjPathLift_c  @0x0214857c  +0x80

Good call. That is the right identification and I would not have found it by inspection.

But the inference from mov r4,r1 is backwards. The argument is that r1 is parked into r4 because the call clobbers it, so "a callee that consumed r1 would not need it parked first". Here is the whole caller:

0x020b08f8  ldr r2,[r0]
0x020b08fc  mov r5,r0
0x020b0900  ldr r2,[r2,#0x80]
0x020b0904  mov r4,r1          <- parked
0x020b0908  blx r2
0x020b090c  mov r0,#2
0x020b0910  bl 0x0201fcd4
0x020b0914  bl 0x020ae330
0x020b0918  mov r0,r5
0x020b091c  mov r1,r4          <- the caller's own later use
0x020b0920  bl 0x0202e62c

vfSuccess is handed to 0x0202e62c three calls after the dispatch. The caller must preserve it across all three regardless of what any of them read. A callee that did consume r1 would need it parked for exactly the same reason. So the park is evidence about the caller's liveness and says nothing about the callee's signature — and r1 holds a meaningful value at the moment of blx, which is also the shape a real argument would have.

The contrast with slot 31 is what a conclusive measurement looks like. On #2106 I checked your +0x7C scan: 39 sites, and all 39 load the pointer into r1. That is structurally decisive, because r1 cannot simultaneously carry a second argument. At +0x80 the three sites use r1, r2 and r3. Register choice there is tracking local liveness, not the callee's signature, so the same style of argument does not transfer.

One correction, and it cuts your way on the substance. The header groups ov002 and ov064 together as the AfterClsn sites. ov064 cannot be one:

0x02116e50  mov r0,r5
0x02116e54  ldr r1,[r0]
0x02116e58  ldr r1,[r1,#0x80]
0x02116e5c  blx r1

The pointer is in r1, so no second argument can be passed — and _ZN16dPathLiftActor_c9AfterClsnEi mangles Ei, one int parameter. ov064 also carries zero dPathLiftActor_c symbols, and 0x02116e58 sits inside func_ov064_02116d1c, in the daOts_c neighbourhood. The ov002 site, meanwhile, is the two-argument one and establishes it explicitly:

0x020eff98  mov r0,r1
0x020eff9c  ldr r3,[r0]
0x020effa0  mov r1,r2      <- second argument, established
0x020effa4  ldr r3,[r3,#0x80]

So the three sites are three hierarchies with at least two different arities at the same offset. None of that makes your conclusion wrong — the ov002 site shows what establishing an argument looks like, and ov004 does not do it, which is a real if indirect point in favour of nullary. It makes it a hint of the same strength as the return type, from a sample of one.

The ask is one word: drop MEASURED, or qualify it the way the return type is qualified (A HINT). Keep the rest of the block, including the sentence about r1 being vfSuccess — that is true and useful. It is only the conclusion drawn from the park that does not follow. The ov064 attribution should come out, since the register makes it impossible.

3. Off-by-one: this is the fifth, not the fourth

:366  slot 28 -- "the first in this campaign"
:425  slot 29 -- "the second consecutive slot that no body pins"
:510  slot 30 -- "the THIRD consecutive slot no body pins"
:606  slot 31 -- "the third consecutive slot no body pins"        <- inherited from #2106
:693  slot 32 -- "and the FOURTH consecutive slot no body pins"   <- should be FIFTH

Slot 31 already claims third on #2106 and I flagged it there; slot 32 then counts from the wrong number. Both live in include/dScMgBase_c.h, so please fix them in whichever of the two PRs lands second rather than in both — otherwise the second one conflicts on the same lines.

Ordering

Stack is #2099#2100#2102#2106#2107, and all five carry changes-requested from me on the same return-type split. That is deliberate: I would rather it be decided once at the base than five times. Nothing above is a byte-match concern, and the promotion mechanics in this one I checked and they hold.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

attribution-override Maintainer accepts this PR's contributor-credit changes; validation reports them as warnings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant