diff --git a/config/regions.tsv b/config/regions.tsv index 0d9b556..6f349a3 100644 --- a/config/regions.tsv +++ b/config/regions.tsv @@ -93,6 +93,7 @@ 0x8002DEB4 0x8002DF1C src/func_8002DEB4.c 0x8002E028 0x8002E070 src/func_8002E028.c 0x8002E3A8 0x8002E3B8 src/func_8002E3A8.c +0x8002E3FC 0x8002E44C src/func_8002E3FC.c 0x8002E4C8 0x8002E4F0 src/func_8002E4C8.c 0x8002E7C4 0x8002E7E4 src/func_8002E7C4.c 0x8002E968 0x8002E9AC src/func_8002E968.c diff --git a/config/symbols.tsv b/config/symbols.tsv index 17db0ef..5ce85d6 100644 --- a/config/symbols.tsv +++ b/config/symbols.tsv @@ -381,6 +381,7 @@ func_80024668 0x80024668 func_8002F404 0x8002F404 func_800695D8 0x800695D8 func_800F4098 0x800F4098 +g_80121BFA 0x80121BFA gp g_80122068 0x80122068 gp g_80122158 0x80122158 gp g_80122354 0x80122354 diff --git a/src/func_8002E3FC.c b/src/func_8002E3FC.c new file mode 100644 index 0000000..cd79ce6 --- /dev/null +++ b/src/func_8002E3FC.c @@ -0,0 +1,51 @@ +/* + * func_8002E3FC — 80 bytes at 0x8002E3FC..0x8002E44C + * + * One-shot initialiser guarded by a gp-relative flag byte: returns immediately if + * the flag is already set, otherwise sets it and makes three calls. + * + * The observed instructions are: + * lbu v0,706(gp) ; v0 = D_80121BFA <- UNSIGNED byte + * addiu sp,sp,-24 + * bnez v0,0x8002E43C ; if (already done) return + * sw ra,16(sp) ; save ra (delay slot) + * li v0,1 + * sb v0,706(gp) ; D_80121BFA = 1 + * move a0,zero + * jal 0x80062D10 + * move a1,zero ; second argument = 0 (delay slot) + * move a0,zero + * jal 0x80062D10 + * li a1,12 ; second argument = 12 (delay slot) + * lui a1,0x8003 + * addiu a1,a1,-7240 ; a1 = D_8002E3B8 + * jal 0x800592A4 + * move a0,zero ; first argument = 0 (delay slot) + * 3C: lw ra,16(sp) + * addiu sp,sp,24 + * jr ra + * nop + * + * The guard is `if (flag != 0) return;` — the early-return form — because the + * whole body is skipped and there is only one epilogue. The gp flag is read and + * written with `lbu`/`sb`, so it is an unsigned byte. + * + * LIMITS: the gp offset (706 = 0x2C2; gp = 0x80121938, so the symbol is at 0x80121BFA), the constant (12), the function address + * D_8002E3B8 and the three callees are hypotheses read from the instruction + * shape; the gp offset is a fact about this executable's gp layout. What the flag + * and the callees mean is unknown and is not guessed here. Only the compiled bytes + * are evidence. + */ + +extern unsigned char g_80121BFA; +extern char D_8002E3B8[]; + +void func_8002E3FC(void) { + if (g_80121BFA != 0) + return; + + g_80121BFA = 1; + func_80062D10(0, 0); + func_80062D10(0, 12); + func_800592A4(0, (int)D_8002E3B8); +}