diff --git a/config/match_worklist.tsv b/config/match_worklist.tsv index a6d4c36..79a3ecb 100644 --- a/config/match_worklist.tsv +++ b/config/match_worklist.tsv @@ -1272,7 +1272,7 @@ 1265 0x801007E0 0x80100808 40 fallthrough 3 frame 1 - 1 # # listed=1265 -# excluded_already_registered=459 +# excluded_already_registered=460 # excluded_bad_extent_start=8 # excluded_degenerate_body=252 # excluded_delay_slot_start=5 @@ -1280,5 +1280,5 @@ # excluded_low_confidence_grade=90 # excluded_named_exclusion=9 # excluded_no_extent=0 -# excluded_recorded_negative=142 +# excluded_recorded_negative=141 # excluded_trapping_arith=54 diff --git a/config/regions.tsv b/config/regions.tsv index 3975897..f1f3df8 100644 --- a/config/regions.tsv +++ b/config/regions.tsv @@ -359,6 +359,7 @@ 0x800BFEC0 0x800BFEE0 src/func_800BFEC0.c 0x800BFEE0 0x800BFF00 src/func_800BFEE0.c 0x800BFF00 0x800BFF20 src/func_800BFF00.c +0x800C1424 0x800C14BC src/func_800C1424.c 0x800C1EA8 0x800C1F04 src/func_800C1EA8.c 0x800C5C84 0x800C5CBC src/func_800C5C84.c 0x800F2F6C 0x800F2FB8 src/func_800F2F6C.c maspsx=off diff --git a/src/func_800C1424.c b/src/func_800C1424.c new file mode 100644 index 0000000..46ce016 --- /dev/null +++ b/src/func_800C1424.c @@ -0,0 +1,108 @@ +/* + * func_800C1424 — 152 bytes at 0x800C1424..0x800C14BC + * + * Byte-identical reconstruction of a framed table search and release: a + * pointer field on the object is the base of 30 twelve-byte records, the record + * whose first word matches a key is found, and that record is released through + * two calls with the found pointer cleared. + * + * The observed instructions are: + * addiu sp,sp,-32 + * sw ra,24(sp) + * sw s1,20(sp) + * sw s0,16(sp) + * lw a0,468(a0) base = *(int **)(p + 468) + * nop (load delay) + * beqz a0,0x800C14A4 if (base == 0) return + * nop + * beqz a1,0x800C14A4 if (key == 0) return + * move s0,zero (delay slot) found = 0 + * move a2,zero i = 0 + * move s1,a0 base (copied for the calls) + * addiu v1,s1,2356 e = (char *)base + 2356 + * lw v0,0(v1) + * nop + * bne v0,a1,0x800C1470 if (*e == key) { found = e; break; } + * nop + * j 0x800C1480 + * move s0,v1 (delay slot) + * addiu a2,a2,1 i++ + * slti v0,a2,30 + * bnez v0,0x800C1458 + * addiu v1,v1,12 (delay slot) e += 12 + * beqz s0,0x800C14A4 if (found == 0) return + * move a0,s1 (delay slot) + * move a1,zero + * jal 0x800263A8 + * move a2,s0 (delay slot) + * sw zero,0(s0) *found = 0 + * move a0,s1 + * jal 0x80026560 + * move a1,v0 (delay slot) + * lw ra,24(sp) + * lw s1,20(sp) + * lw s0,16(sp) + * addiu sp,sp,32 + * jr ra + * nop + * + * The frame is 32 bytes: the 16-byte o32 outgoing argument area, `s0` at + * 16(sp), `s1` at 20(sp) and `ra` at 24(sp). TWO source-shape facts are + * load-bearing, and both are about register allocation rather than semantics: + * + * 1. The guard must be written against the **expression**, not the local: + * `if (*(int **)(p + 468) == 0) return;` and only then + * `base = *(int **)(p + 468);`. cc1's CSE then keeps ONE load whose + * destination is the guard's operand (`a0`) and emits the `move s1,a0` copy + * for the longer live range. Writing the guard against the local instead + * makes cc1 load straight into `s1` and the copy disappears (148 bytes). + * 2. `i = 0;` must be a **statement before** the base assignment, not the + * `for`-initialiser: scheduled early, `a0` still holds base, so the loop + * counter takes `a2` (the original) rather than `a0` (152 vs 12 differing + * bytes with the counter in a0). + * + * The search is a counted loop with a byte-stride induction pointer (`v1 += 12`) + * and a separate counter, and the "found" path sits behind a `j`, so the loop is + * written as a `break`. `*found = 0` is a separate statement between the two + * calls, which is why the store follows the first `jal`. + * + * LIMITS: the function name, the callees' arities and parameter types, the + * record stride 12, the count 30, the base offset 2356 and the key's meaning + * are hypotheses reconstructed from the disassembly. Only the compiled bytes + * are evidence. + */ + +int func_800263A8(int *, int, int *); +void func_80026560(int *, int); + +void func_800C1424(char *p, int key) { + int *e; + int *found; + int i; + int *base; + int r; + + if (*(int **)(p + 468) == 0) + return; + if (key == 0) + return; + + found = 0; + i = 0; + base = *(int **)(p + 468); + e = (int *)((char *)base + 2356); + for (; i < 30; i++) { + if (*e == key) { + found = e; + break; + } + e = (int *)((char *)e + 12); + } + + if (found == 0) + return; + + r = func_800263A8(base, 0, found); + *found = 0; + func_80026560(base, r); +}