switch语句反汇编分析

一、简单swith语句反汇编分析

Switch语句如下:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

反汇编代码为:
  

将局部变量flag存放现在栈底即[ebp-8],然后通过eax做中转,在[ebp-4]存放一个flag的备份,复制到ecx中对其进行减一操作,其中的1则是case分支中的最小值,然后将操作完的数保存到[ebp-4]中,此时为flag-1=2,接着进行cmp操作,比较的数值4是由case分支的最大值和最小值相减得到的,如果flag-1大于case分支的相差值,则跳转到地址0x0129107c处,此地址为default语句地址。

 

此处的算法为将flag减去最小的分支得到一个数,然后和case分支最大值与最小值相差数值比较,即是比较两个区间,如果第一个区间较大说明flag不在case分支中则跳转到default分支,但如果比case分支的最小值小呢?怎么没比较?这里其实可以采用一个语句即if(flag>case最大值 || flag<case最小值) 跳转到default,但是编译器这里使用到了一个技巧,如果falgcase值小,flag减去最小的case值会变成负数,而负数在内存中以补码形式存放的,使用ja指令是比较的无符号数,因此也就肯定比那个区间值大了,(例如falg=1case最小值为2,则1-2=-1,在内存中存放为ffffffffH,是一个很大的数)很不错的技巧!

如果flagcase区间的话就会将flag-1的值传递给edx,然后通过[edx*4+01291094h]定位到case分支的地址,为什么可以通过edx定位呢?01291094h又是一个什么地址?其实编译器事先分配好了一个地址数组,其中存放的则是case分支的地址,01291094h是这个数组的首地址,edx是作为索引来找到分支地址的,这也是switch语句不能使用浮点数作为flag的原因。程序中此时edx2,也就是去[2*4+01291094h][0129109ch]中寻找case3的地址,为0129104ch

 

 

 

 

如果flag不在case分支中但在其区间内会怎么样呢?现在假设flag还是3,但去掉case3的语句,这时以edx为索引跳过去的地址中存放的是default的地址。观察发现在编译器生成的地址数组中存在max-min+1个单元,其中仅有case值为索引存放的才是case分支的地址,其余全是default的地址。


二、switch语句与if语句比较

如果switch语句只有两个分支,即case1case100那岂不是要创建长度为100的地址数组,只有头和尾是分支地址,其余全是default地址,极大地浪费内存空间,反编译可以发现编译器采用了if语句的格式来进行跳转

编译器在对case分支有三个及以下的时候,三个if语句也就是三条减法(cmp),而地址数组则需要两条减法(subcmp)和一个索引定位的乘法(至少相当于一次减法),速度并不占优势,因此编译器会选择if语句来实现。但是即使程序中有4个分支,有时候编译器也会采用if语句,假如说是case1,case2,case3,case10000,编译器的地址跳转表将会变得很大,此时也会采用if语句的形式。

 

三、switch的优化

Switch语句还有一种情况就是case分支很多,但是每个分支的数值比较稀疏的情况,跳转表元素为50-40+1=41个,但只有5个元素是分支的地址,其余全是default的地址,此时采用跳转表也会造成太多的内存浪费,编译器对这种情况进行了优化

 

 

在这里将[edx+address]中存放的一个字节传送到eax中,其余位补0,那这个address是什么地址?定位到address可以看到其中存放的数据为:

 

假设flag=10的话,先从[0+010110b4h]处取出一个字节00eax,然后eax充当索引到另一个地址中取出内容跳转,终会跳转到0101109ch处取地址

 

此处的地址正好为case10处的地址

 

假设flag=15的话,先从[5+010110b4h]处取出字节05传递给eax,然后通过eax的索引可以跳转到5*4+0101109ch=010110b0h处取地址

 

此处的地址为default的地址

 

 

通过以上的实验可以看出switch语句在case分支较稀疏的情况下会采用二次跳转的方式来进行优化,第一个数组存放第二个数组的索引号,元素个数为max-min+1maxmincase分支最大最小值),元素大小为一个字节,第二个数组根据索引号找到存放的case分支地址,第二个数组的大小为case分支的个数+1default分支)。上面的实验中如果不采用优化的话跳转表的大小为(50-10+1*4=164字节,而优化后为(50-10+1)*1+(5+1)*4=65字节,大大节省了内存空间,但是需要进行两次数组访问,典型的时间换空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值