mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-02 16:00:27 -04:00
f9a2de3edd
- CRACKED pin-free at xHigh (Opus 5 agent), then ALL FOUR family siblings banked via §40 remap, each MATCHING FIRST TRY: ov_SC03_090 (the crack) · ov_SC03_089 · ov_SC03_104 · func_8017E778 @ ov_SC03_091 · func_8017CD9C @ ov_SC03_102 (the last two cross-address). Verified independently before believing the report (R14): match_one MATCH (3338 ins), then harvest_verify BYTE-IDENTICAL on all five binaries, then R22 clean-fleet 140/140. - METRICS: distinct-code 3,816,534 -> 3,833,224 (+16,690) = 67.7% -> 68.0%, the first percentage-point movement in that metric all session. instr-weighted 80.3% -> 80.5%. Session distinct-code total +19,712 ins, ALL from the three behemoths; propagation gave +0. - MY BRIEF WAS WRONG IN AN INSTRUCTIVE WAY -> §78. I said a negative length drift means "missing instructions". The 4 absent instructions were 4 emit tails × 1 nop -- delay slots the target could NOT FILL because the register it wanted was still live. otp at function scope has 4 deaths -> fails local-alloc.c:472 -> global allocno in $a2 -> via global.c:668-671 pushes tp off $a1 -> the 0xFFFFFF mask is free early -> maspsx hoists it into the slot. Declaring otp PER EMIT ARM fixed the whole drift in one edit (3334->3338, 1806->333). SECOND TIME IN ONE SESSION a "structural"-looking residual was an allocno-class choice (the first: F510's "scheduling" transposition, §76). A nop present in the target but absent from the draft is usually a register-liveness fact, not missing code. - TWO MORE REUSABLE FINDINGS (§78): gcc-2.7.2 fold NEVER leaves a literal first in an `|` chain (7 parenthesisations, all reassociate) -- so `or acc, var, K` first in the target means K was a VARIABLE in the source, an asm->source read that retires a whole sweep family. And "make it a variable" has TWO separable effects (fold-opacity vs a new allocno): a fresh short-lived local fixes structure and wrecks allocation (690 mismatched, damage ~300 ins away); reuse a busy one. - ECONOMICS: 9 levers, each necessary by drop-one ablation, and 5 of the 9 were read straight off the MATCHED relatives func_8017F510 (cracked earlier today) and func_8017CA80. Crack the smaller family member first -- it is a lever library for the larger one. - NEW TOOL .run/giants/s19_remap_family.py: family_remap + the §77 preamble carry in one step (reproduces the exemplar's FULL file-scope preamble with the tool's own substitution map applied). Took the 4 siblings from "4 rounds of CC1 FAIL each" to MATCH first try, ×4.
36 lines
1.6 KiB
Python
36 lines
1.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Bucketed histogram of FULL(register-kept) divergent target indices.
|
|
usage: d960_hist.py <obj.o> [bucket]"""
|
|
import sys, re, subprocess, shutil, difflib
|
|
sys.path.insert(0, '/home/musashi/bfm-decomp/.run/giants')
|
|
OBJ = sys.argv[1]; BK = int(sys.argv[2]) if len(sys.argv) > 2 else 100
|
|
TGT = '/home/musashi/bfm-decomp/asm/ov_SC03_090/nonmatchings/ov_SC03_090_jr_8017CA80/func_8017D960.s'
|
|
OD = [c for c in ["mips-linux-gnu-objdump","mipsel-linux-gnu-objdump"] if shutil.which(c)][0]
|
|
out = subprocess.run([OD,"-drz",OBJ],capture_output=True,text=True).stdout
|
|
wm=[]
|
|
for line in out.splitlines():
|
|
m=re.match(r'\s*[0-9a-f]+:\s+([0-9a-f]{8})\s',line)
|
|
if m: wm.append(int(m.group(1),16))
|
|
elif 'R_MIPS_' in line and wm and not isinstance(wm[-1],tuple) and (wm[-1]>>26) not in (2,3): wm[-1]=('R',wm[-1])
|
|
wt=[]
|
|
for line in open(TGT):
|
|
m=re.match(r'\s*/\* \w+ [0-9A-F]{8} ([0-9A-F]{8}) \*/\s+(\S+)\s*(.*)',line)
|
|
if m:
|
|
v=int.from_bytes(bytes.fromhex(m.group(1)),'little')
|
|
wt.append(('R',v) if ('%hi(' in line or '%lo(' in line) else v)
|
|
def full(x):
|
|
rel=isinstance(x,tuple); v=x[1] if rel else x; op=(v>>26)&0x3F
|
|
if rel: return (v&0xFFFF0000,'R')
|
|
if op in (2,3): return (op<<26,'')
|
|
if op in (1,4,5,6,7): return (v&0xFFFF0000,'')
|
|
return (v,'')
|
|
a=[full(x) for x in wm]; b=[full(x) for x in wt]
|
|
sm=difflib.SequenceMatcher(None,a,b,autojunk=False)
|
|
bad=[]
|
|
for t,i1,i2,j1,j2 in sm.get_opcodes():
|
|
if t!='equal': bad.extend(range(j1,j2))
|
|
from collections import Counter
|
|
c=Counter(i//BK for i in bad)
|
|
print('total divergent %d' % len(bad))
|
|
for k in sorted(c): print(' %5d-%5d : %4d %s' % (k*BK,(k+1)*BK-1,c[k],'#'*min(60,c[k])))
|