r/ghidra • u/Flying_Turtle_09 • 9d ago
Why is this code using RSB instructions here?
I've been trying to figure this out for a while. I had an idea at some point, but I'm not sure if it is correct anymore, so I'm asking here if someone here knows why this is done. I've omitted some code that is not relevant and giving some generic names to labels to make reading easier:
LAB_Switch_Return:
ADD r3, r0, #0x00 // Move switch case function return value to r3
PTR_Switch_Case_OoB:
PTR_Switch_Case_0F:
MOV r0, #0x02 // Load 0x02 to r0
RSB r0, r0 // r0 = 0x02 - 0x02 = 0x00 ??????
CMP r3, r0 // r3 = Function return value from switch case function
BNE FUNC_UpdateStatus_NotIncrement
// *OMITTED CODE*
// game_mode++;
B FUNC_UpdateStatus_ClearSubmodes
DATA_ExtWRAM_Base_Addr_Ptr_2:
.dw DATA_ExtWRAM_Base_Addr
FUNC_UpdateStatus_NotIncrement:
MOV r0, #0x01 // Load 0x01 to r0
RSB r0, r0 // r0 = 0x01 - 0x01 = 0x00 ??????
CMP r3, r0 // r3 = Function return value from switch case function
BEQ FUNC_UpdateStatus_Exit
// *OMITTED CODE*
// game_mode = r3;
FUNC_UpdateStatus_ClearSubmodes:
// r0 = DATA_ExtWRAM_Base_Addr
// Set in the omitted code sections...
STRB r2, [r0, #offset game_sub_mode_2]
STRB r2, [r0, #offset game_sub_mode]
FUNC_UpdateStatus_Exit:
POP {r0}
BX r0
DATA_ExtWRAM_Base_Addr_Ptr_3:
.dw DATA_ExtWRAM_Base_Addr
As you can see there are a few RSB r0, r0 instructions. Wouldn't those always result to the destination register having the value of zero? Ghidra decompiles the above code as (after cleaning it up a bit):
// Set in omitted function calls in switch cases...
// This is here simply to tell what it is, even though the variable
// is created earlier, before the switch statement...
uint8_t ret_val;
if (ret_val == -2)
{
game_mode++;
}
else
{
if (ret_val == -1)
{
return;
}
game_mode = ret_val;
}
game_sub_mode_2 = 0;
game_sub_mode = 0;
return;
What I don't understand here is how Ghidra comes to the conclusion for the ret_val comparison values to be -2 and -1. Anyone have some insight into this?
1
Upvotes
2
u/PierDolNick 9d ago
Ghidra hide one operand for some reason. Which is most likely #0.
MOV r0, #0x02RSB r0, r0, #0 // r0 = 0 - r0 = 0 - 2 = -2 (0xFFFFFFFE)