Skip to content

Register Mismatch Decompilation Tricks

H.M. Burger edited this page Oct 2, 2024 · 3 revisions

Register Mismatch Decompilation Tricks

This page contains some examples of some unintuitive or tricky compiler tricks that may be SotN specific to get registers to match.

# GTE/LTE (PSP)

The developers of SotN tended to use foo > bar in if statements.

That tends to get compiled to look as foo >= bar+1

This can cause the "wrong" registers to be used. Take for example the asm

    slti    at,v1,0x29
    bnez    at,3d0
    nop  

Directly, this translates to

if (foo >= 0x29) {

However, that will compile to

    slti    v1,v1,0x29
    bnez    v1,3d0
    nop

Which uses the register v1 instead of at.

The "correct" translation is if (foo> 0x28)

# Modulo

This is a harder one to find in PSX vs PSP.

Take the following assembly in PSX and PSP

PSX PSP
lui     v1,%hi(foo)
lw      v1,%lo(foo)(v1)
nop     
bgez    v1,1c4 ~>
move    v0,v1
addiu   v0,v1,0x7f
sra     a0,v0,0x7
sll     v0,a0,0x7
subu    a0,v1,v0
lui     v0,%hi(foo)
lw      v1,%lo(foo)(v0)
li      v0,0x80
andi    s2,v1,0x7f
bgez    v1,284
nop     
beqz    s2,284
nop     
addiu   s2,s2,-0x80

It sure looks like this is some sort of branching statement and you may try to write something like this

bar = foo & 0x7F;
if (bar < 0 && bar != 0) {
    bar -= 128;
}

However, that compiles to (PSP)

lui     v0,%hi(foo)
lw      v0,%lo(foo)(v0)
andi    s1,v0,0x7f
bgez    s1,284 ~>
nop     
beqz    s1,284 ~>
nop     
addiu   s1,s1,-0x80

Close, but not quite there. The "tell" on this situation is that we are loading 0x80 into v0 on psp, but not doing anything with it.
This may be a compiler bug (it may also be a sort of comment to help debug), but we can leverage it to know that this is actually a modulo. The correct translation is

index = foo % 0x80;