在分支较多的时候,switch的效率比if高,在反汇编中我们即可看到效率高的原因

0x01分支结构不超过3个

#include <stdio.h>

void main()
{
int x = 5;
switch(x)
{
case 5:
printf("%d\n",x);
break;
case 6:
printf("%d\n",x);
break;
case 7:
printf("%d\n",x);
break;
default:
break;
} return;
}
5:        int x = 5;
00401028 mov dword ptr [ebp-4],5
6: switch(x)
7: {
0040102F mov eax,dword ptr [ebp-4]
00401032 mov dword ptr [ebp-8],eax //x的值放入[ebp-8]
00401035 cmp dword ptr [ebp-8],5
00401039 je main+39h (00401049) //x与5相等就跳转,下面6和7相同
0040103B cmp dword ptr [ebp-8],6
0040103F je main+4Ch (0040105c)
00401041 cmp dword ptr [ebp-8],7
00401045 je main+5Fh (0040106f)
00401047 jmp main+72h (00401082)
8: case 5:
9: printf("%d\n",x);
00401049 mov ecx,dword ptr [ebp-4]
0040104C push ecx
0040104D push offset string "%d\n" (0042201c)
00401052 call printf (004010d0)
00401057 add esp,8
10: break;
0040105A jmp main+83h (00401093)
11: case 6:
12: printf("%d\n",x);
0040105C mov edx,dword ptr [ebp-4]
0040105F push edx
00401060 push offset string "%d\n" (0042201c)
00401065 call printf (004010d0)
0040106A add esp,8
13: break;
0040106D jmp main+83h (00401093)
14: case 7:
15: printf("%d\n",x);
0040106F mov eax,dword ptr [ebp-4]
00401072 push eax
00401073 push offset string "%d\n" (0042201c)
00401078 call printf (004010d0)
0040107D add esp,8
16: break;
00401080 jmp main+83h (00401093)
17: default:
18: printf("%d\n",x);
00401082 mov ecx,dword ptr [ebp-4]
00401085 push ecx
00401086 push offset string "%d\n" (0042201c)
0040108B call printf (004010d0)
00401090 add esp,8
19: break;
20: }

0x02分支数超过3且分支存在线性关系

#include <stdio.h>

void main()
{
int x = 5;
switch(x)
{
case 5:
printf("%d\n",x);
break;
case 6:
printf("%d\n",x);
break;
case 7:
printf("%d\n",x);
break;
case 8:
printf("%d\n",x);
break;
case 9:
printf("%d\n",x);
break;
default:
printf("%d\n",x);
break;
} return;
}
5:        int x = 5;
0040D778 mov dword ptr [ebp-4],5
6: switch(x)
7: {
0040D77F mov eax,dword ptr [ebp-4]
0040D782 mov dword ptr [ebp-8],eax
0040D785 mov ecx,dword ptr [ebp-8]
0040D788 sub ecx,5 //x减去分支中的最小值5,方便构建跳转表
0040D78B mov dword ptr [ebp-8],ecx
0040D78E cmp dword ptr [ebp-8],4
0040D792 ja $L537+13h (0040d7fd) //x-5>4跳转到default,即x>9跳转
0040D794 mov edx,dword ptr [ebp-8] //edx=x-5
0040D797 jmp dword ptr [edx*4+40D81Fh] //构建跳转表,根据edx的值从对应地址取出值(各个分支的地址),40D81F为跳转表起始地址
8: case 5:
9: printf("%d\n",x);
0040D79E mov eax,dword ptr [ebp-4]
0040D7A1 push eax
0040D7A2 push offset string "%d\n" (0042201c)
0040D7A7 call printf (004010d0)
0040D7AC add esp,8
10: break;
0040D7AF jmp $L537+24h (0040d80e)
11: case 6:
12: printf("%d\n",x);
0040D7B1 mov ecx,dword ptr [ebp-4]
0040D7B4 push ecx
0040D7B5 push offset string "%d\n" (0042201c)
0040D7BA call printf (004010d0)
0040D7BF add esp,8
13: break;
0040D7C2 jmp $L537+24h (0040d80e)
14: case 7:
15: printf("%d\n",x);
0040D7C4 mov edx,dword ptr [ebp-4]
0040D7C7 push edx
0040D7C8 push offset string "%d\n" (0042201c)
0040D7CD call printf (004010d0)
0040D7D2 add esp,8
16: break;
0040D7D5 jmp $L537+24h (0040d80e)
17: case 8:
18: printf("%d\n",x);
0040D7D7 mov eax,dword ptr [ebp-4]
0040D7DA push eax
0040D7DB push offset string "%d\n" (0042201c)
0040D7E0 call printf (004010d0)
0040D7E5 add esp,8
19: break;
0040D7E8 jmp $L537+24h (0040d80e)
20: case 9:
21: printf("%d\n",x);
0040D7EA mov ecx,dword ptr [ebp-4]
0040D7ED push ecx
0040D7EE push offset string "%d\n" (0042201c)
0040D7F3 call printf (004010d0)
0040D7F8 add esp,8
22: break;
0040D7FB jmp $L537+24h (0040d80e)
23: default:
24: printf("%d\n",x);
0040D7FD mov edx,dword ptr [ebp-4]
0040D800 push edx
0040D801 push offset string "%d\n" (0042201c)
0040D806 call printf (004010d0)
0040D80B add esp,8
25: break;
26: }

跳转表从[edx*4+40D81Fh]取出分支的地址值然后进行jmp,下表是跳转表部分

0040D81F  9E D7 40 00  ..@.
0040D823 B1 D7 40 00 ..@.
0040D827 C4 D7 40 00 ..@.
0040D82B D7 D7 40 00 ..@.
0040D82F EA D7 40 00 ..@.

0x03分支跃度大难以构成跳转表的分支结构

#include <stdio.h>

void main()
{
int x = 5;
switch(x)
{
case 5:
printf("%d\n",x);
break;
case 6:
printf("%d\n",x);
break;
case 7:
printf("%d\n",x);
break;
case 8:
printf("%d\n",x);
break;
case 100:
printf("%d\n",x);
break;
default:
printf("%d\n",x);
break;
} return;
}
5:        int x = 5;
00401028 mov dword ptr [ebp-4],5
6: switch(x)
7: {
0040102F mov eax,dword ptr [ebp-4]
00401032 mov dword ptr [ebp-8],eax
00401035 mov ecx,dword ptr [ebp-8]
00401038 sub ecx,5
0040103B mov dword ptr [ebp-8],ecx
0040103E cmp dword ptr [ebp-8],5Fh
00401042 ja $L536+13h (004010b5) //具体参见上一种,x大于100跳转到default
00401044 mov eax,dword ptr [ebp-8] //edx=x-5
00401047 xor edx,edx //edx置零
00401049 mov dl,byte ptr (004010ef)[eax] //查询索引表并将取出来的值放入DL(在od里面的这条反汇编更清楚)
0040104F jmp dword ptr [edx*4+4010D7h] //根据DL(EDX)的值查跳转表
8: case 5:
9: printf("%d\n",x);
00401056 mov ecx,dword ptr [ebp-4]
00401059 push ecx
0040105A push offset string "%d\n" (0042201c)
0040105F call printf (004011a0)
00401064 add esp,8
10: break;
00401067 jmp $L536+24h (004010c6)
11: case 6:
12: printf("%d\n",x);
00401069 mov edx,dword ptr [ebp-4]
0040106C push edx
0040106D push offset string "%d\n" (0042201c)
00401072 call printf (004011a0)
00401077 add esp,8
13: break;
0040107A jmp $L536+24h (004010c6)
14: case 7:
15: printf("%d\n",x);
0040107C mov eax,dword ptr [ebp-4]
0040107F push eax
00401080 push offset string "%d\n" (0042201c)
00401085 call printf (004011a0)
0040108A add esp,8
16: break;
0040108D jmp $L536+24h (004010c6)
17: case 8:
18: printf("%d\n",x);
0040108F mov ecx,dword ptr [ebp-4]
00401092 push ecx
00401093 push offset string "%d\n" (0042201c)
00401098 call printf (004011a0)
0040109D add esp,8
19: break;
004010A0 jmp $L536+24h (004010c6)
20: case 100:
21: printf("%d\n",x);
004010A2 mov edx,dword ptr [ebp-4]
004010A5 push edx
004010A6 push offset string "%d\n" (0042201c)
004010AB call printf (004011a0)
004010B0 add esp,8
22: break;
004010B3 jmp $L536+24h (004010c6)
23: default:
24: printf("%d\n",x);
004010B5 mov eax,dword ptr [ebp-4]
004010B8 push eax
004010B9 push offset string "%d\n" (0042201c)
004010BE call printf (004011a0)
004010C3 add esp,8
25: break;
26: }

索引表

004010F1  00 01 02 03 05 05 05 05  ........
004010F9 05 05 05 05 05 05 05 05 ........
00401101 05 05 05 05 05 05 05 05 ........
00401109 05 05 05 05 05 05 05 05 ........
00401111 05 05 05 05 05 05 05 05 ........
00401119 05 05 05 05 05 05 05 05 ........
00401121 05 05 05 05 05 05 05 05 ........
00401129 05 05 05 05 05 05 05 05 ........
00401131 05 05 05 05 05 05 05 05 ........
00401139 05 05 05 05 05 05 05 05 ........
00401141 05 05 05 05 05 05 05 05 ........
00401149 05 05 05 05 05 05 05 04 ........

跳转表

004010D9  58 10 40 00  X.@.
004010DD 6B 10 40 00 k.@.
004010E1 7E 10 40 00 ~.@.
004010E5 91 10 40 00 ..@.
004010E9 A4 10 40 00 ..@.
004010ED B7 10 40 00 ..@.

switch反汇编(C语言)的更多相关文章

  1. Linux环境下使用gcc编译,gdb反汇编C语言程序

    使用虚拟机 VMware Workstation 10 Linux环境:Ubuntu 14.04 LTS Server amd64   我把过程截图如下. 首先是hello world程序: 备注: ...

  2. 通过反汇编C语言小程序学习Liunx汇编语言

    大家好!    我是来自山东师范大学的吴乐.    今天在<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ...

  3. 《天书夜读:从汇编语言到windows内核编程》三 练习反汇编C语言程序

    1) Debug版本算法反汇编,现有如下3×3矩阵相乘的程序: #define SIZE 3 int MyFunction(int a[SIZE][SIZE],int b[SIZE][SIZE],in ...

  4. switch反汇编

    以下总结为debug模式

  5. Go丨语言学习笔记--switch

    Java语言与Go语言的switch对比 Go语言 switch str { case "yes" : do something ... case "no" d ...

  6. 利用反汇编手段解析C语言函数

    1.问题的提出函数是 C语言中的重要概念.利用好函数能够充分利用系统库的功能写出模块独立.易于维护和修改的程序.函数并不是 C 语言独有的概念,其他语言中的方法.过程等本质上都是函数.可见函数在教学中 ...

  7. go语言之if语句和switch语句和循环语句

    1.if语句 package main import ( "fmt" "io/ioutil" ) func main() { //流程控制 //使用常量定义一个 ...

  8. (八)羽夏看C语言——C番外篇

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.本人非计算机专业,可能对本教程涉及的事物没有了解的足够深入,如有错误,欢迎批评指正. 如有好的建议,欢迎反馈.码字不易,如果本篇文章 ...

  9. Go语言程序设计(1)--基本语法

    第一个程序 package main import "fmt" func main() { fmt.Printf("Hello world") } 通过阅读这个 ...

随机推荐

  1. linux常用系统工作命令

    1.echo命令 echo命令用于在终端输出字符串或变量提取后的值,格式为“echo [字符串 | $变量]”. 2.date命令 date命令用于显示及设置系统的时间或日期,格式为“date [选项 ...

  2. uvalive 3126 Taxi Cab Scheme

    题意: 有m个人要坐出租车,每个人给出出发时间,出发地点和目的地(以二维坐标表示),两个地点之间所花的时间计算方式是两点之间的哈密顿距离.现在需要排遣车出去,一辆车每次只能装一个人,如果一辆车在装完一 ...

  3. ecplise问题总结

    ecplise 1.ecplise在运行的时候出现错误 Unable to execute dex: GC overhead limit exceeded GC overhead limit exce ...

  4. kalinux实现自适用全屏、与物理主机共享文件方法

    1.执行虚拟机>安装VMware Tools菜单命令,自动挂载光驱(一般是自动挂载的,如果没有自动挂载请自行百度linux如何手动挂载光驱) 2.打开vm光驱的vmtools复制此文件到桌面: ...

  5. 输出列表为字符串,并在最后一个值前加上and 4.10.1

    逗号代码: def test4(lis): str1='' for i in range(len(lis)-1): str1+=(str(val[i])+', ') str1+=('and '+str ...

  6. python 创建临时文件和文件夹

    ----需要在程序执行时创建一个临时文件或目录,并希望使用完之后可以自动销毁掉. tempfile 模块中有很多的函数可以完成这任务.为了创建一个匿名的临时文件,可以使用tempfile.Tempor ...

  7. Hive批量删除历史分区

    批量删除历史分区和数据可以采用如下操作: -- 删除20180101之前的所有分区 alter table example_table_name drop if exists partition (d ...

  8. android本地数据库,微信数据库WCDB for Android 使用实例

    android本地数据库,微信数据库WCDB for Android 使用实例 Home · Tencent/wcdb Wikihttps://github.com/Tencent/wcdb/wiki ...

  9. AWS免费云服务套餐申请步骤及常见问题

    AWS免费云服务套餐申请步骤及常见问题 AWS免费使用套餐常见问题_AWS免费云服务套餐_-AWS云服务https://amazonaws-china.com/cn/free/faqs/ 什么是 AW ...

  10. highchart 柱状图 分组样例

    var chart = Highcharts.chart('container',{ chart: { type: 'column' }, title: { text: '月平均降雨量' }, sub ...