-
Notifications
You must be signed in to change notification settings - Fork 130
GCC 2.8.1 Tips and Tricks
This page lists patterns and problems that frequently show up when decomping, and how to go about matching them.
TARGET CURRENT
lui a0, %hi(foo) lui a0, %hi(foo)
addiu a0, %lo(foo)
jal bar jal bar
nop addiu a0, %lo(foo)
This usually means foo
is a .data
or .rodata
symbol of this file, rather than extern
ed elsewhere. (TODO: could it be the other way around? alex has forgotten)
If you encounter likely instructions, these mean that the delay slot instruction is only executed if the branch is taken. Sometimes your code is equalvent but you still get these instructions (or don't get them when you want them). Try inverting the condition, as this sometimes coerces the compiler into using a likely instruction
This
f32 x;
MULT_HI(x, constant) >> shift
should be rewritten as
f32 x;
x / y
division only generates break if you divide by a variable rather than a constant
This issue lists the constants/shifts: https://github.com/NationalSecurityAgency/ghidra/issues/668
e.g. MULT_HI(x, 0x51EB851F) >> 5
is x / 10
You may see the asm do this:
void fx_73_update(EffectInstance* arg0) {
SomeStruct* structTemp;
s32 i;
structTemp = arg0->data;
if (arg0->numParts > 1) {
structPlus20 = temp_a1 + 0x20;
do {
if (structPlus20->unk0 <= 0) {
structPlus20->unk-1C--;
if (structPlus20->unk-1C >= 0xA) {
structPlus20->unk0 = -1;
}
}
i++;
structPlus20 += 0x24;
} while (i < arg0->numParts);
}
}
Note the negative offsets (unk-1C, for example) and how structPlus20 is 0x20 bytes into the struct. You can calculate the correct offsets by taking the 0x20 and subtracting 0x1C to get structTemp->unk_04
. However, to get the code to actually generate these negative offsets, you need to increment the struct temp pointer as well as the normal loop iterator: for (i = 1; i < numParts; i++, structTemp++) {
todo expand
"Irregular" switches (as deemed by m2c) are switches that are small enough that they do not need a jumptable, and may appear as an if/else chain in m2c's output.
The following is an example of what you might see from m2c for an irregular switch:
if (var != 1) {
if (var < 4) {
// case 0, 2, 3
temp = 2;
} else {
// default case
temp = 5;
}
} else {
// case 1
temp = 10;
}
which can be matched with the following switch statement:
switch (var) {
case 1:
temp = 10;
break;
case 0:
case 2:
case 3:
temp = 2;
break;
default:
temp = 5;
break;
}
Irregular switches may include a seemingly unused register checking for a certain condition; this may imply that the original code contained a case that was identical to the default case but was explicitly provided e.g.
slti t6, s5, 2
the t6 register (result of the comparison) will never be used in the following switch, but the comparison that sets it will appear in the asm:
switch (temp_t5) {
case 0:
case 1:
/* matches default case! */
var1 = 10;
var2 = 20;
break;
case 8:
var1 = 15;
var2 = 40;
break;
case 11:
var1 = 30;
var2 = 5;
break;
default:
var1 = 10;
var2 = 20;
break;
}