switch...case跳转表
Posted Qing-Huan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了switch...case跳转表相关的知识,希望对你有一定的参考价值。
0. 本文结构概述
- switch...case语法格式
- C和C++的switch不同点
- switch...case反汇编
- switch...case跳转表
- case值间距过大不用跳转表
1. switch...case语句
switch (表达式1) // 表达式结果不能是实型、字符串
case 值1:
// case后的值只能是常量表达式:整型(long、int、short、char)
// 多数情况下和enum组合使用
语句1;
break;
case 值2:
语句2;
break;
case 值3:
语句3;
break;
default:
语句4;
break;
2. C和C++的switch不同点
3. switch...case反汇编
- 如下图绿色框中:在 case 较少的情况下,switch...case 与 if...else 是一样的
- 如下图红色框中:我们在学习switch...case时知道这样的语法,case语句块结束后若不加break,会继续向下执行其他case语句块。原因是编译器会将case语句提取出来,在switch阶段就对各个case语句进行了判定跳转,语句块指令会按顺序排列在下方,若没有break就会继续执行下面的语句块。
4. switch...case跳转表
当 case
较多的情况下,编译器会考虑以 空间换时间
,对 switch...case
进行优化(优化方案:添加跳转表)
由于 case
后的数据为相邻整型变量,所以系统在编译阶段,将这些数值映射为跳转表,将表头地址记录下来用于寻址。
- 编译阶段开辟一段连续空间,内部存储每个case语句块的入口地址,将寻址方式写入代码段:
jmp dword ptr [edx*4+0B3844h]
- 运行时计算
switch值
与case最小值
的距离
(求差) - 若
距离
大于case最小值
与case最大值
之差,说明switch值
大于最大值或小于最小值。直接跳转至default语句块 - 将
距离
传入edx
中,代入寻址公式跳转
int main()
......
int a = 102;
000B37EA mov dword ptr [a],66h
switch (a)
000B37F1 mov eax,dword ptr [a]
000B37F4 mov dword ptr [ebp-4Ch],eax
000B37F7 mov ecx,dword ptr [ebp-4Ch]
000B37FA sub ecx,64h
// 和case中的最小值作差,得到从最小case距离与a相等case之间的距离 ---> 2
000B37FD mov dword ptr [ebp-4Ch],ecx
000B3800 cmp dword ptr [ebp-4Ch],3
// 比较距离是否在范围内 ---> 2 < 3
000B3804 ja $LN7+9h (0B3834h)
// 若距离大于所有case的长度,跳转至default语句块
000B3806 mov edx,dword ptr [ebp-4Ch]
000B3809 jmp dword ptr [edx*4+0B3844h]
// 以0B3844作为基址,加上距离*4(一个地址4位),此处存储的是语句块的起始地址。
case 100:
t = 100;
000B3810 mov dword ptr [t],64h
break;
......
default:
t = 104;
000B3834 mov dword ptr [t],68h
break;
return 0;
000B383B xor eax,eax
5. case值间距过大不用跳转表
若case语句较多,满足优化为跳转表的条件时,还要看case值间距大小,若case值间距过大,就不会用跳转表了
以上是关于switch...case跳转表的主要内容,如果未能解决你的问题,请参考以下文章
switch...case 与 if...else 的性能分析
逆向知识第九讲,switch case语句在汇编中表达的方式
为什么switch...case语句比if...else执行效率高