switch...case跳转表

Posted Qing-Huan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了switch...case跳转表相关的知识,希望对你有一定的参考价值。

0. 本文结构概述

  1. switch...case语法格式
  2. C和C++的switch不同点
  3. switch...case反汇编
  4. switch...case跳转表
  5. 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反汇编

  1. 如下图绿色框中:在 case 较少的情况下,switch...case 与 if...else 是一样的
  2. 如下图红色框中:我们在学习switch...case时知道这样的语法,case语句块结束后若不加break,会继续向下执行其他case语句块。原因是编译器会将case语句提取出来,在switch阶段就对各个case语句进行了判定跳转,语句块指令会按顺序排列在下方,若没有break就会继续执行下面的语句块。

4. switch...case跳转表

case 较多的情况下,编译器会考虑以 空间换时间 ,对 switch...case 进行优化(优化方案:添加跳转表)

由于 case 后的数据为相邻整型变量,所以系统在编译阶段,将这些数值映射为跳转表,将表头地址记录下来用于寻址。

  1. 编译阶段开辟一段连续空间,内部存储每个case语句块的入口地址,将寻址方式写入代码段:jmp dword ptr [edx*4+0B3844h]
  2. 运行时计算 switch值case最小值距离 (求差)
  3. 距离 大于 case最小值case最大值 之差,说明 switch值 大于最大值或小于最小值。直接跳转至default语句块
  4. 距离 传入 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执行效率高

GCC 4.4:避免在 gcc 中对 switch/case 语句进行范围检查?

汇编中Switch逆向基础(跳转表)

switch case语句总执行第一个case