编译器对switch case结构的优化
2012-10-16 23:10
148 查看
在使用IDA分析Crack Me的时候,发现IDA对switch case结构的分析很是清晰,还发现了一个jump table for switch statement,也就是所谓的跳转表了,是编译器优化的结果。对于case分支的值是连续的那种,所有分支的跳转地址都会存入一个数组之中,然后通过case的值来寻址,如果值超出边界则直接跳到default分支所在地址。
.text:004010EA align 4
.text:004010EC off_4010EC dd offset loc_401038 ; DATA XREF: _wmain+31
.text:004010EC dd offset loc_40104B ; jump table for switch statement
.text:004010EC dd offset loc_40105E
.text:004010EC dd offset loc_401071
.text:004010EC dd offset loc_401084
.text:004010EC dd offset loc_401097
.text:004010EC dd offset loc_4010AA
.text:004010EC dd offset loc_4010BD.text:00401000 push ecx
.text:00401001 push esi
.text:00401002 lea eax, [esp+8+var_4]
.text:00401006 push eax
.text:00401007 push offset Format ; "%d"
.text:0040100C mov [esp+10h+var_4], 0
.text:00401014 call ds:scanf
.text:0040101A mov eax, [esp+10h+var_4]
.text:0040101E mov esi, ds:putchar
.text:00401024 dec eax
.text:00401025 add esp, 8
.text:00401028 cmp eax, 7 ; switch 8 cases
.text:0040102B ja loc_4010D0 ; default
.text:00401031 jmp ds:off_4010EC[eax*4] ; switch jump
如果case分支的值之间有一定的间隔,但是差距又不是很大,则会先生成一个数组(可能比较大),先通过switch的变量当做下标在一个数组中取得对应的值,然后把这个值当做下标再在跳转地址表中取得对应的地址。
如果case分支的部分值之间有一定的间隔,而又有一些分支的值没有规律,比如很大,且分布不均匀等。那么分布均匀的那一部分将采用两级跳转表的形式,而其他分支则采用简单的比较判断方式。
如果case分支值没有规律,则会采用二叉树查找的方式进行优化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include "stdafx.h"
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
int nMax = 0;
scanf("%d", &nMax);
switch (nMax)
{
case 1:
putchar('1');
break;
case 256:
putchar('2');
break;
case 3:
putchar('3');
break;
case 999:
putchar('4');
break;
case 512:
putchar('5');
break;
case 0x0FFFFFFF:
putchar('6');
break;
case 10000:
putchar('7');
break;
case 0:
putchar('8');
break;
default:
printf("default");
}
putchar('\n');
return 0;
}
IDA Pro中的截图:
.text:00401000 _wmain proc near ; CODE XREF: ___tmainCRTStartup+10A
.text:00401000
.text:00401000 var_4 = dword ptr -4
.text:00401000
.text:00401000 push ecx
.text:00401001 push esi
.text:00401002 lea eax, [esp+8+var_4]
.text:00401006 push eax
.text:00401007 push offset Format ; "%d"
.text:0040100C mov [esp+10h+var_4], 0
.text:00401014 call ds:scanf
.text:0040101A mov eax, [esp+10h+var_4]
.text:0040101E mov esi, ds:putchar
.text:00401024 add esp, 8
.text:00401027 cmp eax, 200h
.text:0040102C jg short loc_4010A7
.text:0040102E jz short loc_401094
.text:00401030 cmp eax, 3
.text:00401033 jg short loc_40107A
.text:00401035 jz short loc_401067
.text:00401037 sub eax, 0
.text:0040103A jz short loc_401054
.text:0040103C sub eax, 1
.text:0040103F jnz short loc_4010BC
.text:00401041 push 31h ; Ch
.text:00401043 call esi ; putchar
.text:00401045 add esp, 4
.text:00401048 push 0Ah ; Ch
.text:0040104A call esi ; putchar
.text:0040104C add esp, 4
.text:0040104F xor eax, eax
.text:00401051 pop esi
.text:00401052 pop ecx
.text:00401053 retn
.text:00401054 ; ---------------------------------------------------------------------------
.text:00401054
.text:00401054 loc_401054: ; CODE XREF: _wmain+3A
.text:00401054 push 38h ; Ch
.text:00401056 call esi ; putchar
.text:00401058 add esp, 4
.text:0040105B push 0Ah ; Ch
.text:0040105D call esi ; putchar
.text:0040105F add esp, 4
.text:00401062 xor eax, eax
.text:00401064 pop esi
.text:00401065 pop ecx
.text:00401066 retn
.text:00401067 ; ---------------------------------------------------------------------------
.text:00401067
.text:00401067 loc_401067: ; CODE XREF: _wmain+35
.text:00401067 push 33h ; Ch
.text:00401069 call esi ; putchar
.text:0040106B add esp, 4
.text:0040106E push 0Ah ; Ch
.text:00401070 call esi ; putchar
.text:00401072 add esp, 4
.text:00401075 xor eax, eax
.text:00401077 pop esi
.text:00401078 pop ecx
.text:00401079 retn
.text:0040107A ; ---------------------------------------------------------------------------
.text:0040107A
.text:0040107A loc_40107A: ; CODE XREF: _wmain+33
.text:0040107A cmp eax, 100h
.text:0040107F jnz short loc_4010BC
.text:00401081 push 32h ; Ch
.text:00401083 call esi ; putchar
.text:00401085 add esp, 4
.text:00401088 push 0Ah ; Ch
.text:0040108A call esi ; putchar
.text:0040108C add esp, 4
.text:0040108F xor eax, eax
.text:00401091 pop esi
.text:00401092 pop ecx
.text:00401093 retn
.text:00401094 ; ---------------------------------------------------------------------------
.text:00401094
.text:00401094 loc_401094: ; CODE XREF: _wmain+2E
.text:00401094 push 35h ; Ch
.text:00401096 call esi ; putchar
.text:00401098 add esp, 4
.text:0040109B push 0Ah ; Ch
.text:0040109D call esi ; putchar
.text:0040109F add esp, 4
.text:004010A2 xor eax, eax
.text:004010A4 pop esi
.text:004010A5 pop ecx
.text:004010A6 retn
.text:004010A7 ; ---------------------------------------------------------------------------
.text:004010A7
.text:004010A7 loc_4010A7: ; CODE XREF: _wmain+2C
.text:004010A7 cmp eax, 3E7h
.text:004010AC jz short loc_4010FC
.text:004010AE cmp eax, 2710h
.text:004010B3 jz short loc_4010E9
.text:004010B5 cmp eax, 0FFFFFFFh
.text:004010BA jz short loc_4010D6
.text:004010BC
.text:004010BC loc_4010BC: ; CODE XREF: _wmain+3F
.text:004010BC ; _wmain+7F
.text:004010BC push offset aDefault ; "default"
.text:004010C1 call ds:printf
.text:004010C7 add esp, 4
.text:004010CA push 0Ah ; Ch
.text:004010CC call esi ; putchar
.text:004010CE add esp, 4
.text:004010D1 xor eax, eax
.text:004010D3 pop esi
.text:004010D4 pop ecx
.text:004010D5 retn
.text:004010D6 ; ---------------------------------------------------------------------------
.text:004010D6
.text:004010D6 loc_4010D6: ; CODE XREF: _wmain+BA
.text:004010D6 push 36h ; Ch
.text:004010D8 call esi ; putchar
.text:004010DA add esp, 4
.text:004010DD push 0Ah ; Ch
.text:004010DF call esi ; putchar
.text:004010E1 add esp, 4
.text:004010E4 xor eax, eax
.text:004010E6 pop esi
.text:004010E7 pop ecx
.text:004010E8 retn
.text:004010E9 ; ---------------------------------------------------------------------------
.text:004010E9
.text:004010E9 loc_4010E9: ; CODE XREF: _wmain+B3
.text:004010E9 push 37h ; Ch
.text:004010EB call esi ; putchar
.text:004010ED add esp, 4
.text:004010F0 push 0Ah ; Ch
.text:004010F2 call esi ; putchar
.text:004010F4 add esp, 4
.text:004010F7 xor eax, eax
.text:004010F9 pop esi
.text:004010FA pop ecx
.text:004010FB retn
.text:004010FC ; ---------------------------------------------------------------------------
.text:004010FC
.text:004010FC loc_4010FC: ; CODE XREF: _wmain+AC
.text:004010FC push 34h ; Ch
.text:004010FE call esi ; putchar
.text:00401100 add esp, 4
.text:00401103 push 0Ah ; Ch
.text:00401105 call esi ; putchar
.text:00401107 add esp, 4
.text:0040110A xor eax, eax
.text:0040110C pop esi
.text:0040110D pop ecx
.text:0040110E retn
.text:0040110E _wmain endp
简单的画一个二叉树的图就是这个样子:
512
/ \
/ \
3 999
/ \ \
/ \ \
0 256 10000
\ \
\ \
1 0x0FFFFFFF
不明白的同学可以参考下往上的一篇文档《C++逆向学习三步走》,下载地址:直接下载 迅雷下载
--------------------------------------------------------------------------------
本博客很少转载他人文章,如未特别标明,均为原创,转载请注明出处:
本文出自程序人生 >> 编译器对switch case结构的优化
Copyed From 程序人生
Home Page:http://www.programlife.net
Source URL:http://www.programlife.net/switch-case-optimization.html
.text:004010EA align 4
.text:004010EC off_4010EC dd offset loc_401038 ; DATA XREF: _wmain+31
.text:004010EC dd offset loc_40104B ; jump table for switch statement
.text:004010EC dd offset loc_40105E
.text:004010EC dd offset loc_401071
.text:004010EC dd offset loc_401084
.text:004010EC dd offset loc_401097
.text:004010EC dd offset loc_4010AA
.text:004010EC dd offset loc_4010BD.text:00401000 push ecx
.text:00401001 push esi
.text:00401002 lea eax, [esp+8+var_4]
.text:00401006 push eax
.text:00401007 push offset Format ; "%d"
.text:0040100C mov [esp+10h+var_4], 0
.text:00401014 call ds:scanf
.text:0040101A mov eax, [esp+10h+var_4]
.text:0040101E mov esi, ds:putchar
.text:00401024 dec eax
.text:00401025 add esp, 8
.text:00401028 cmp eax, 7 ; switch 8 cases
.text:0040102B ja loc_4010D0 ; default
.text:00401031 jmp ds:off_4010EC[eax*4] ; switch jump
如果case分支的值之间有一定的间隔,但是差距又不是很大,则会先生成一个数组(可能比较大),先通过switch的变量当做下标在一个数组中取得对应的值,然后把这个值当做下标再在跳转地址表中取得对应的地址。
如果case分支的部分值之间有一定的间隔,而又有一些分支的值没有规律,比如很大,且分布不均匀等。那么分布均匀的那一部分将采用两级跳转表的形式,而其他分支则采用简单的比较判断方式。
如果case分支值没有规律,则会采用二叉树查找的方式进行优化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include "stdafx.h"
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
int nMax = 0;
scanf("%d", &nMax);
switch (nMax)
{
case 1:
putchar('1');
break;
case 256:
putchar('2');
break;
case 3:
putchar('3');
break;
case 999:
putchar('4');
break;
case 512:
putchar('5');
break;
case 0x0FFFFFFF:
putchar('6');
break;
case 10000:
putchar('7');
break;
case 0:
putchar('8');
break;
default:
printf("default");
}
putchar('\n');
return 0;
}
IDA Pro中的截图:
.text:00401000 _wmain proc near ; CODE XREF: ___tmainCRTStartup+10A
.text:00401000
.text:00401000 var_4 = dword ptr -4
.text:00401000
.text:00401000 push ecx
.text:00401001 push esi
.text:00401002 lea eax, [esp+8+var_4]
.text:00401006 push eax
.text:00401007 push offset Format ; "%d"
.text:0040100C mov [esp+10h+var_4], 0
.text:00401014 call ds:scanf
.text:0040101A mov eax, [esp+10h+var_4]
.text:0040101E mov esi, ds:putchar
.text:00401024 add esp, 8
.text:00401027 cmp eax, 200h
.text:0040102C jg short loc_4010A7
.text:0040102E jz short loc_401094
.text:00401030 cmp eax, 3
.text:00401033 jg short loc_40107A
.text:00401035 jz short loc_401067
.text:00401037 sub eax, 0
.text:0040103A jz short loc_401054
.text:0040103C sub eax, 1
.text:0040103F jnz short loc_4010BC
.text:00401041 push 31h ; Ch
.text:00401043 call esi ; putchar
.text:00401045 add esp, 4
.text:00401048 push 0Ah ; Ch
.text:0040104A call esi ; putchar
.text:0040104C add esp, 4
.text:0040104F xor eax, eax
.text:00401051 pop esi
.text:00401052 pop ecx
.text:00401053 retn
.text:00401054 ; ---------------------------------------------------------------------------
.text:00401054
.text:00401054 loc_401054: ; CODE XREF: _wmain+3A
.text:00401054 push 38h ; Ch
.text:00401056 call esi ; putchar
.text:00401058 add esp, 4
.text:0040105B push 0Ah ; Ch
.text:0040105D call esi ; putchar
.text:0040105F add esp, 4
.text:00401062 xor eax, eax
.text:00401064 pop esi
.text:00401065 pop ecx
.text:00401066 retn
.text:00401067 ; ---------------------------------------------------------------------------
.text:00401067
.text:00401067 loc_401067: ; CODE XREF: _wmain+35
.text:00401067 push 33h ; Ch
.text:00401069 call esi ; putchar
.text:0040106B add esp, 4
.text:0040106E push 0Ah ; Ch
.text:00401070 call esi ; putchar
.text:00401072 add esp, 4
.text:00401075 xor eax, eax
.text:00401077 pop esi
.text:00401078 pop ecx
.text:00401079 retn
.text:0040107A ; ---------------------------------------------------------------------------
.text:0040107A
.text:0040107A loc_40107A: ; CODE XREF: _wmain+33
.text:0040107A cmp eax, 100h
.text:0040107F jnz short loc_4010BC
.text:00401081 push 32h ; Ch
.text:00401083 call esi ; putchar
.text:00401085 add esp, 4
.text:00401088 push 0Ah ; Ch
.text:0040108A call esi ; putchar
.text:0040108C add esp, 4
.text:0040108F xor eax, eax
.text:00401091 pop esi
.text:00401092 pop ecx
.text:00401093 retn
.text:00401094 ; ---------------------------------------------------------------------------
.text:00401094
.text:00401094 loc_401094: ; CODE XREF: _wmain+2E
.text:00401094 push 35h ; Ch
.text:00401096 call esi ; putchar
.text:00401098 add esp, 4
.text:0040109B push 0Ah ; Ch
.text:0040109D call esi ; putchar
.text:0040109F add esp, 4
.text:004010A2 xor eax, eax
.text:004010A4 pop esi
.text:004010A5 pop ecx
.text:004010A6 retn
.text:004010A7 ; ---------------------------------------------------------------------------
.text:004010A7
.text:004010A7 loc_4010A7: ; CODE XREF: _wmain+2C
.text:004010A7 cmp eax, 3E7h
.text:004010AC jz short loc_4010FC
.text:004010AE cmp eax, 2710h
.text:004010B3 jz short loc_4010E9
.text:004010B5 cmp eax, 0FFFFFFFh
.text:004010BA jz short loc_4010D6
.text:004010BC
.text:004010BC loc_4010BC: ; CODE XREF: _wmain+3F
.text:004010BC ; _wmain+7F
.text:004010BC push offset aDefault ; "default"
.text:004010C1 call ds:printf
.text:004010C7 add esp, 4
.text:004010CA push 0Ah ; Ch
.text:004010CC call esi ; putchar
.text:004010CE add esp, 4
.text:004010D1 xor eax, eax
.text:004010D3 pop esi
.text:004010D4 pop ecx
.text:004010D5 retn
.text:004010D6 ; ---------------------------------------------------------------------------
.text:004010D6
.text:004010D6 loc_4010D6: ; CODE XREF: _wmain+BA
.text:004010D6 push 36h ; Ch
.text:004010D8 call esi ; putchar
.text:004010DA add esp, 4
.text:004010DD push 0Ah ; Ch
.text:004010DF call esi ; putchar
.text:004010E1 add esp, 4
.text:004010E4 xor eax, eax
.text:004010E6 pop esi
.text:004010E7 pop ecx
.text:004010E8 retn
.text:004010E9 ; ---------------------------------------------------------------------------
.text:004010E9
.text:004010E9 loc_4010E9: ; CODE XREF: _wmain+B3
.text:004010E9 push 37h ; Ch
.text:004010EB call esi ; putchar
.text:004010ED add esp, 4
.text:004010F0 push 0Ah ; Ch
.text:004010F2 call esi ; putchar
.text:004010F4 add esp, 4
.text:004010F7 xor eax, eax
.text:004010F9 pop esi
.text:004010FA pop ecx
.text:004010FB retn
.text:004010FC ; ---------------------------------------------------------------------------
.text:004010FC
.text:004010FC loc_4010FC: ; CODE XREF: _wmain+AC
.text:004010FC push 34h ; Ch
.text:004010FE call esi ; putchar
.text:00401100 add esp, 4
.text:00401103 push 0Ah ; Ch
.text:00401105 call esi ; putchar
.text:00401107 add esp, 4
.text:0040110A xor eax, eax
.text:0040110C pop esi
.text:0040110D pop ecx
.text:0040110E retn
.text:0040110E _wmain endp
简单的画一个二叉树的图就是这个样子:
512
/ \
/ \
3 999
/ \ \
/ \ \
0 256 10000
\ \
\ \
1 0x0FFFFFFF
不明白的同学可以参考下往上的一篇文档《C++逆向学习三步走》,下载地址:直接下载 迅雷下载
--------------------------------------------------------------------------------
本博客很少转载他人文章,如未特别标明,均为原创,转载请注明出处:
本文出自程序人生 >> 编译器对switch case结构的优化
Copyed From 程序人生
Home Page:http://www.programlife.net
Source URL:http://www.programlife.net/switch-case-optimization.html
相关文章推荐
- 编译器的基本结构(一)
- LCC编译器的源程序分析(65)后端接口的结构注释
- 深入理解JVM读书笔记四: (早期)编译器优化
- Android性能优化之优化布局层次结构
- [转载]LCC编译器的源程序分析(14)结构类型的声明
- PHP优化之mysql结构
- 有关代码结构的优化若干
- 浅谈Android系统的基本体系结构与内存管理优化
- ollvm 编译器优化的bug
- 每个程序员都应当知道的编译器优化知识
- 使用Intel编译器(3)HLO(1)高级别优化的选项和使用
- javascript优化编译器 - Closure Compiler
- 由浅入深探究mysql索引结构原理、性能分析与优化
- 编译器的结构——词法分析
- MySQL 数据库性能优化之表结构
- 多重if选择结构代码优化1
- ARM高效C编程和优化--编译器,内存和Cache优化以及功耗管理
- 如何优化你的布局层级结构之RelativeLayout和LinearLayout及FrameLayout性能分析
- GCC编译器选项及优化提示
- 如何优化你的布局层级结构之RelativeLayout和LinearLayout及FrameLayout性能分析