设为首页 加入收藏

TOP

5.5 难以构成跳转表的switch(2)
2013-10-07 14:30:05 来源: 作者: 【 】 浏览:56
Tags:5.5 难以 构成 switch

5.5 难以构成跳转表的switch(2)

在代码清单5-15中,从case 1开始到case 255结束,共255个case值,会生成一个255字节大小索引表。其中从6到255间隔了249个case值, 这249项保存的是case语句块地址表中switch的结尾地址下标,如代码清单5-16所示。

代码清单5-16 非线性索引表—Debug版

  1. switch(nIndex){                     // 源码对比  
  2. 0040DF80    mov     ecx,dword ptr [ebp-4]  
  3. 0040DF83    mov     dword ptr [ebp-8],ecx  
  4. ; 这三条指令为取出变量nIndex的值并保存到edx的操作  
  5. 0040DF86    mov     edx,dword ptr [ebp-8]  
  6. ; 索引表以0下标开始,case最小标号值为1,需要进行减1调整  
  7. 0040DF89    sub     edx,1  
  8. ; 将对齐下标后的值放回到临时变量ebp-8中  
  9. 0040DF8C    mov     dword ptr [ebp-8],edx  
  10. ; 将临时变量与254进行无符号比较,若临时变量大于254则跳转  
  11. ; 跳转到地址0x0040e002处,那里是switch结构的结尾  
  12. 0040DF8F    cmp     dword ptr [ebp-8],0FEh  
  13. 0040DF96    ja      $L566+0Dh (0040e002)  
  14. ; switch的参数值在case值范围内,取出临时变量中的数据并保存到ecx中  
  15. 0040DF98    mov     ecx,dword ptr [ebp-8]  
  16. ; 清空eax的值,以ecx为下标在索引表中取出1字节的内容放入al中  
  17. ; 地址0x0040E02F为索引表的首地址,查看图5-5  
  18. 0040DF9B    xor     eax,eax  
  19. ; 从索引表中取出对应地址表的下标  
  20. 0040DF9D    mov     al,byte ptr  (0040e02f)[ecx]  
  21. ; 以eax作下标,0x0040E013为基址进行寻址,跳转到该地址处  
  22. ; 地址0x0040E013为case语句块地址表的首地址,查看图5-5  
  23. 0040DFA3    jmp     dword ptr [eax*4+40E013h]  
  24. case 1: printf("nIndex == 1");      // 源码对比  
  25. 0040DFAA    push    offset string "nIndex == 1" (00421024)  
  26. 0040DFAF    call    printf (004014b0)  
  27. 0040DFB4    add     esp,4  
  28. break;                              // 源码对比  
  29. 0040DFB7   jmp      $L566+0Dh (0040e002)  
  30. case 2: printf("nIndex == 2");      // 源码对比  
  31. 0040DFB9    push    offset string "nIndex == 2" (0042003c)  
  32. 0040DFBE    call    printf (004014b0)  
  33. 0040DFC3    add     esp,4  
  34. break;                              // 源码对比  
  35. 0040DFC6    jmp     $L566+0Dh (0040e002)  
  36. case 3: printf("nIndex == 3");      // 源码对比  
  37. 0040DFC8    push    offset string "nIndex == 3" (004210d8)  
  38. 0040DFCD    call    printf (004014b0)  
  39. 0040DFD2    add     esp,4  
  40. break;                              // 源码对比  
  41. 0040DFD5    jmp     $L566+0Dh (0040e002)  
  42. case 5: printf("nIndex == 5");      // 源码对比  
  43. 0040DFD7    push    offset string "i == 3" (00420028)  
  44. 0040DFDC    call    printf (004014b0)  
  45. 0040DFE1    add     esp,4  
  46. break;                              // 源码对比  
  47. 0040DFE4   jmp      $L566+0Dh (0040e002)  
  48. case 6: printf("nIndex == 6");  
  49. 0040DFE6    push    offset string "nIndex == 6" (004210cc)  
  50. 0040DFEB    call    printf (004014b0)  
  51. 0040DFF0    add     esp,4  
  52. break;                              // 源码对比  
  53. 0040DFF3    jmp     $L566+0Dh (0040e002)  
  54. case 255: printf("nIndex == 255");      // 源码对比  
  55. 0040DFF5    push    offset string "nIndex == 255" (0042005c)  
  56. 0040DFFA    call    printf (004014b0)  
  57. 0040DFFF    add     esp,4  
  58. break; }                                // 源码对比  
  59. ; switch结束地址  
  60. 0040E002    pop     edi 

代码清单5-16首先查询索引表,索引表由数组组成,数组的每一项大小为1字节。从索引表中取出地址表的下标,根据下标值,找到跳转地址表中对应的case语句块首地址,跳转到该地址处。这种查询方式会产生两次间接内存访问,在效率上低于线性表方式。

 
图5-7 非线性索引表—Debug版
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇5.5 难以构成跳转表的switch(3) 下一篇5.5 难以构成跳转表的switch(1)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: