Reverse Engineering for Beginners

(avery) #1

CHAPTER 13. SWITCH()/CASE/DEFAULT CHAPTER 13. SWITCH()/CASE/DEFAULT


or $at, $zero ; load delay slot, NOP
jr $t9
la $a0, ($LC3 & 0xFFFF) # "something unknown" ; branch delay slot
# ---------------------------------------------------------------------------

loc_4C: # CODE XREF: f+14
lui $a0, ($LC2 >> 16) # "two"
lw $t9, (puts & 0xFFFF)($gp)
or $at, $zero ; load delay slot, NOP
jr $t9
la $a0, ($LC2 & 0xFFFF) # "two" ; branch delay slot


---------------------------------------------------------------------------


loc_60: # CODE XREF: f+8
lui $a0, ($LC1 >> 16) # "one"
lw $t9, (puts & 0xFFFF)($gp)
or $at, $zero ; load delay slot, NOP
jr $t9
la $a0, ($LC1 & 0xFFFF) # "one" ; branch delay slot


The function always ends with callingputs(), so here we see a jump toputs()(JR: “Jump Register”) instead of “jump and
link”. We talked about this earlier:13.1.1 on page 143.


We also often see NOP instructions after LW ones. This is “load delay slot”: anotherdelay slotin MIPS. An instruction next to
LW may execute at the moment while LW loads value from memory. However, the next instruction must not use the result
of LW. Modern MIPS CPUs have a feature to wait if the next instruction uses result of LW, so this is somewhat outdated, but
GCC still adds NOPs for older MIPS CPUs. In general, it can be ignored.


13.1.7 Conclusion.


Aswitch()with few cases is indistinguishable from anif/elseconstruction, for example: listing.13.1.1.


13.2 A lot of cases


If aswitch()statement contains a lot of cases, it is not very convenient for the compiler to emit too large code with a lot
JE/JNEinstructions.


#include <stdio.h>


void f (int a)
{
switch (a)
{
case 0: printf ("zero\n"); break;
case 1: printf ("one\n"); break;
case 2: printf ("two\n"); break;
case 3: printf ("three\n"); break;
case 4: printf ("four\n"); break;
default: printf ("something unknown\n"); break;
};
};


int main()
{
f (2); // test
};


13.2.1 x86


Non-optimizing MSVC


We get (MSVC 2010):

Free download pdf