switch反汇编分析

文章详细分析了C语言中的switch语句在遇到大量连续case值时的反汇编过程,指出当case值连续时,编译器可能会生成一个查找表以提高效率。对于有空缺的连续case或不连续case,编译器可能采用小表或二分查找的方法。总结了四种不同情况下的代码生成策略。
摘要由CSDN通过智能技术生成

switch反汇编分析:

1、case后的值大量且连续的情况

c代码

#include<stdio.h>

void fun(int a);

int main()
{
	int a = 105;
	fun(a);
}

void fun(int a)
{
	switch (a) {
	case 100: printf("%d\n", a); break;
	case 101: printf("%d\n", a); break;
	case 102: printf("%d\n", a); break;
	case 103: printf("%d\n", a); break;
	case 104: printf("%d\n", a); break;
	case 105: printf("%d\n", a); break;
	case 106: printf("%d\n", a); break;
	case 107: printf("%d\n", a); break;
	case 108: printf("%d\n", a); break;
	case 109: printf("%d\n", a); break;
	case 110: printf("%d\n", a); break;
	case 111: printf("%d\n", a); break;
	case 112: printf("%d\n", a); break;
	case 113: printf("%d\n", a); break;
	case 114: printf("%d\n", a); break;
	case 115: printf("%d\n", a); break;
	case 116: printf("%d\n", a); break;

	}

}

对应的汇编

00007FF7B3F017AE 8B 85 F0 00 00 00    mov         eax,dword ptr [a] 
将参数a(105),保存到eax
00007FF7B3F017B4 89 85 C0 00 00 00    mov         dword ptr [rbp+0C0h],eax  
将105再保存到rbp+0C(栈的下面)的地方
00007FF7B3F017BA 8B 85 C0 00 00 00    mov         eax,dword ptr [rbp+0C0h] 
再把105保存回eax处
00007FF7B3F017C0 83 E8 64             sub         eax,64h 
eax-64h(十进制的100),再将结果保存到eax中,执行完该语句eax中值为5
00007FF7B3F017C3 89 85 C0 00 00 00    mov         dword ptr [rbp+0C0h],eax  
将5保存到rbp+0C处
00007FF7B3F017C9 83 BD C0 00 00 00 10 cmp         dword ptr [rbp+0C0h],10h  
再将5与10h(16)比较
00007FF7B3F017D0 0F 87 8A 01 00 00    ja          $LN20+12h (07FF7B3F01960h)  
如果大于就跳转到(07FF7B3F01960h)  也就是switch结束的地方
00007FF7B3F017D6 48 63 85 C0 00 00 00 movsxd      rax,dword ptr [rbp+0C0h]  
带符号扩展;将5带符号扩展为64位数字;
00007FF7B3F017DD 48 8D 0D 1C E8 FE FF lea         rcx,[__ImageBase (07FF7B3EF0000h)]  
将imageBase内存映像基址保存到rcx中;
00007FF7B3F017E4 8B 84 81 6C 19 01 00 mov         eax,dword ptr [rcx+rax*4+1196Ch]  
将该处地址保存的值复制到eax中;该处地址是一个表(该表中存储着)
该处地址的内容:很明显的看出是有规律的,你可以将5改为1-16中任意一个数x,再进行[rcx+rax*4+1196Ch] 运算,然后根据运算结果继续
运行代码可以得到100+x对应的地址
0x00007FF7B3F0196C  f0 17 01 00  ?...
0x00007FF7B3F01970  07 18 01 00  ....
0x00007FF7B3F01974  1e 18 01 00  ....
0x00007FF7B3F01978  35 18 01 00  5...
0x00007FF7B3F0197C  4c 18 01 00  L...
0x00007FF7B3F01980  63 18 01 00  c...
0x00007FF7B3F01984  7a 18 01 00  z...
0x00007FF7B3F01988  91 18 01 00  ?...
0x00007FF7B3F0198C  a8 18 01 00  ?...
0x00007FF7B3F01990  bf 18 01 00  ?...
0x00007FF7B3F01994  d6 18 01 00  ?...
0x00007FF7B3F01998  ea 18 01 00  ?...
0x00007FF7B3F0199C  fe 18 01 00  ?...
0x00007FF7B3F019A0  12 19 01 00  ....
0x00007FF7B3F019A4  26 19 01 00  &...
0x00007FF7B3F019A8  3a 19 01 00  :...
0x00007FF7B3F019AC  4e 19 01 00  N...


00007FF7B3F017EB 48 03 C1             add         rax,rcx  
此时rcx中保存着内存基址,rax中是eax的也就是偏移;
00007FF7B3F017EE FF E0                jmp         rax  
跳转到对应的值,
	case 100: printf("%d\n", a); break;
00007FF7B3F017F0 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F017F6 48 8D 0D 27 94 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F017FD E8 89 F9 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F01802 E9 59 01 00 00       jmp         $LN20+12h (07FF7B3F01960h)  
	case 101: printf("%d\n", a); break;
00007FF7B3F01807 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F0180D 48 8D 0D 10 94 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F01814 E8 72 F9 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F01819 E9 42 01 00 00       jmp         $LN20+12h (07FF7B3F01960h)  
	case 102: printf("%d\n", a); break;
00007FF7B3F0181E 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F01824 48 8D 0D F9 93 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F0182B E8 5B F9 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F01830 E9 2B 01 00 00       jmp         $LN20+12h (07FF7B3F01960h)  
	case 103: printf("%d\n", a); break;
00007FF7B3F01835 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F0183B 48 8D 0D E2 93 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F01842 E8 44 F9 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F01847 E9 14 01 00 00       jmp         $LN20+12h (07FF7B3F01960h)  
	case 104: printf("%d\n", a); break;
00007FF7B3F0184C 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F01852 48 8D 0D CB 93 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F01859 E8 2D F9 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F0185E E9 FD 00 00 00       jmp         $LN20+12h (07FF7B3F01960h)  
	case 105: printf("%d\n", a); break;
00007FF7B3F01863 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F01869 48 8D 0D B4 93 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F01870 E8 16 F9 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F01875 E9 E6 00 00 00       jmp         $LN20+12h (07FF7B3F01960h)  
	case 106: printf("%d\n", a); break;
00007FF7B3F0187A 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F01880 48 8D 0D 9D 93 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F01887 E8 FF F8 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F0188C E9 CF 00 00 00       jmp         $LN20+12h (07FF7B3F01960h)  
	case 107: printf("%d\n", a); break;
00007FF7B3F01891 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F01897 48 8D 0D 86 93 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F0189E E8 E8 F8 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F018A3 E9 B8 00 00 00       jmp         $LN20+12h (07FF7B3F01960h)  
	case 108: printf("%d\n", a); break;
00007FF7B3F018A8 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F018AE 48 8D 0D 6F 93 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F018B5 E8 D1 F8 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F018BA E9 A1 00 00 00       jmp         $LN20+12h (07FF7B3F01960h)  
	case 109: printf("%d\n", a); break;
00007FF7B3F018BF 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F018C5 48 8D 0D 58 93 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F018CC E8 BA F8 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F018D1 E9 8A 00 00 00       jmp         $LN20+12h (07FF7B3F01960h)  
	case 110: printf("%d\n", a); break;
00007FF7B3F018D6 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F018DC 48 8D 0D 41 93 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F018E3 E8 A3 F8 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F018E8 EB 76                jmp         $LN20+12h (07FF7B3F01960h)  
	case 111: printf("%d\n", a); break;
00007FF7B3F018EA 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F018F0 48 8D 0D 2D 93 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F018F7 E8 8F F8 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F018FC EB 62                jmp         $LN20+12h (07FF7B3F01960h)  
	case 112: printf("%d\n", a); break;
00007FF7B3F018FE 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F01904 48 8D 0D 19 93 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F0190B E8 7B F8 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F01910 EB 4E                jmp         $LN20+12h (07FF7B3F01960h)  
	case 113: printf("%d\n", a); break;
00007FF7B3F01912 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F01918 48 8D 0D 05 93 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F0191F E8 67 F8 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F01924 EB 3A                jmp         $LN20+12h (07FF7B3F01960h)  
	case 114: printf("%d\n", a); break;
00007FF7B3F01926 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F0192C 48 8D 0D F1 92 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F01933 E8 53 F8 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F01938 EB 26                jmp         $LN20+12h (07FF7B3F01960h)  
	case 115: printf("%d\n", a); break;
00007FF7B3F0193A 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F01940 48 8D 0D DD 92 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F01947 E8 3F F8 FF FF       call        printf (07FF7B3F0118Bh)  
00007FF7B3F0194C EB 12                jmp         $LN20+12h (07FF7B3F01960h)  
	case 116: printf("%d\n", a); break;
00007FF7B3F0194E 8B 95 F0 00 00 00    mov         edx,dword ptr [a]  
00007FF7B3F01954 48 8D 0D C9 92 00 00 lea         rcx,[string "%d\n" (07FF7B3F0AC24h)]  
00007FF7B3F0195B E8 2B F8 FF FF       call        printf (07FF7B3F0118Bh)  

	}

}

00007FF7B3F01960 48 8D A5 D8 00 00 00 lea         rsp,[rbp+0D8h]  
00007FF7B3F01967 5F                   pop         rdi  
00007FF7B3F01968 5D                   pop         rbp  
00007FF7B3F01969 C3                   ret  
00007FF7B3F0196A 66 90                nop  

第二种情况是其中有大量空缺,但仍然有些连续的,这种情况会生成一个小表;

第三种情况:就是不连续的,那种情况就是和if-else反汇编一样

第四种情况就是:间隔较大的case后的值,使用二分法来提高效率;

由于懒的原因就不一 一具体分析,有兴趣的自己尝试

总结:
1、正常switch语句:生成代码与if...else一样
2、有较多case后值连续的语句:生成一个大表;
3、有case后值连续,但是其中有一部分空缺:生成一个小表(小表255位空间,用来节省空间)
4、间隔较大的case后的值,生成二叉树查找也就是类似于二分法的查找方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值