7

I have come across the following x86 (Built with some version of Visual Studio AFAIK) switch statement:

0x1009E476  cmp edx, 0x3B
0x1009E479  jnz switch_statement

switch_statement:
0x1009E591  movzx ecx, byte [indirect_table+edx]
0x1009E598  jmp dword [table1+ecx*4]

indirect_table:
0x1009E7AB  db 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07
            db 0x07, 0x07, 0x06, 0x8B, 0xFF

table1:
0x1009E7B8  dd ptr code1
            dd ptr code2
            dd ptr code3
            dd ptr code4
            dd ptr code5
            dd ptr code6
            dd 0x00000000 
0x1009E7D4  dd 0x01060600, 0x06020606, 0x06060306, 0x06060606 ; Note: nothing directly references this data.
            dd 0x06040606, 0x06060606, 0x06060606, 0x06060606
            dd 0x06060606, 0x06060606, 0x06060606, 0x06060606
            dd 0x06060606, 0x06060606, 0x06060606, 0x06060606
            dd 0x06060606

No index in the indirect_table will end up referencing any of the 6 pointers in table1. Index 6 will dereference a null pointer, index 7 will dereference 0x01060600 and indexes 0x8B and 0xFF will end up dereferencing garbage. So everything will end up access violating.

So perhaps this is a compiler optimization, the data at table1 following the 6 code pointers and 1 null pointer looks like an indirect table, and coincidentally all indexes are suitable for this switch statement (0-6). While the binary has no references to this data, if EBX was known to be 0x29 or upwards, it would reference into this. The compiler may have decided EBX will not be 0-0x29 so moved the indirect table location backwards to line things up correctly. What then is the role of cmp edx, 0x3B in this?

Is this a compiler code gen issue, a compiler optimization, or have I grossly misunderstood the code?

If an optimization, any supporting reading material would be greatly appreciated.

1 Answer 1

7

Either there is a check somewhere before, or the compiler knows otherwise that edx is not less than 41 (0x29). 0x3B is probably handled by a single switch label, so the compiler added this check to avoid the double memory lookup (or maybe there's an actual if before switch in the source).

The table at 0x1009E7D4 is used to retrieve the jump table entry index - Visual C++ compiler always puts the indirect table after the jumps. 0x1009E7AB is likely a part of the previous switch's indirect table. And 8B FF is mov edi, edi, used here for alignment.

This specific optimization (no subtraction for zero-indexing) seems to be pretty rare; I think I've only seen it in Windows DLLs which often use PGO and other tricks to achieve the last few percents of performance.

1
  • nicely spotted with the 'mov edi, edi' alignment! thanks for the good answer.
    – QAZ
    Commented Aug 27, 2013 at 14:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.