mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-09-21 20:06:25 +02:00
LoadRelocations2 declared last_type, initialised it to -1, read it once - and never assigned it. So the (flag & 0x38) == 0x08 case, which means "reuse the lo16 the previous relocation carried", always saw last_type != 4 and reset lo16 to 0 instead. That matters because R_MIPS_HI16 computes ((op << 16) + lo16) + relocate_to and then adds 0x10000 if bit 15 of the result is set, to pre-compensate the sign extension the paired addiu will do. With lo16 wrongly 0 the carry decision is made on the load address alone, so for any base whose low half has bit 15 set the high half comes out one too high and the pointer lands 0x10000 past what it should be. A compiler emits exactly this pattern around a branch-likely: one lui in the delay slot, another on the fall-through path, both for the same symbol, sharing a single addiu after the paths converge. Only the second lui is adjacent to a HI16, so the first one silently got the wrong high half. last_type is assigned where JPCSP assigns its R_TYPE_OLD: at the end of the branch that actually relocates something, so the commands that only move the base around don't count as "the previous relocation" and a HI16/HI16/LO16 group still pairs up across them. R_MIPS_NONE stops continuing the loop for the same reason - it has to clear last_type, or a HI16 after it would reuse a lo16 that isn't its own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>