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后的值,生成二叉树查找也就是类似于二分法的查找方法