re: r0 is not a base register - the last shortlisted row withdrawn

sub_825F2CF0 / sub_825F2F88 (r0, 30 names each, 97% disc names) are not
name-block readers at all: they are the compiler's VMX save/restore helper
pair. 145 instructions each, 72 differ, every difference stvx<->lvx over
v14..v127.

Root cause: in `addi rD, rA, N` the rA slot reads as literal zero when it
names r0, so `addi r11, r0, -N` is `li r11, -N` - vector spill offsets, not
displacements. The solver excluded r1 only; the bogus base landed inside the
stage-settings name block, dense enough to "resolve" 30 real field names.

name_block_bases.py now skips r0 as well. Rows 277 -> 261, functions 190 ->
176, non-64K bases 170 -> 154, data-table rows 53 -> 50; 154+107=261 and
277-16=261. Artefact diff -100/+3, every removed row line carries r0, control
sub_82341A20 r30 = 0x82088F94 217/226 untouched.

Nothing lost: all 30 names are a strict subset of sub_8230D1F8 r29 (129
names), the stage-settings loader already in the corpus. String-xref join
agrees - FinalPassBG, FogMinDistance, ScreenColorR, ExposureKey_BeginValue
each exist once with exactly one xref, from sub_8230D1F8.

Fourteen other artefacts byte-identical; name-block-bases.txt byte-identical
on a second run.
This commit is contained in:
Sylpheed RE agent
2026-08-28 00:21:26 +00:00
parent 1903bf4c37
commit 198273110b
5 changed files with 149 additions and 113 deletions

View File

@@ -57,7 +57,13 @@ def main():
for name in sorted(byf):
for reg in sorted(byf[name]):
D = sorted(set(byf[name][reg]))
if len(D) < MIN_GROUP or reg == 'r1': # r1 is the stack pointer
# r1 is the stack pointer. r0 is NOT a base register at all: in
# `addi rD, r0, N` the RA slot reads as literal zero, so the form is
# `li rD, N` and the displacements are plain immediates. Left in, the
# VMX save/restore helper pair sub_825F2CF0 / sub_825F2F88 (72 x
# `addi r11, r0, -N`, the vector spill offsets) solved a base and
# "named" 30 strings, 97% of them disc names -- a pure artefact.
if len(D) < MIN_GROUP or reg in ('r0', 'r1'):
continue
# Vote: every (string, displacement) pair implies one candidate base.
# The true base collects a vote from each name it explains, so it wins