逻辑流控制
在我的抽象中执行逻辑有三种-顺序、选择、循环。默认汇编就是从上到下顺序执行,选择用if-else和switch,循环用while、for等。
分支语句
if-else
int main(int argc, char const *argv[]) { int a=10; if (a>10){ printf("a>10"); }else{ printf("a<=10"); } return 0;
int main(int argc, char const *argv[]) { int a=10; if (a>10){ printf("a>10"); }else if(a<2){ printf("a<2"); }else{ printf("2<=a<=10"); } return 0; }
从上面两个二分支和三分支可以看出:
- 开始标志就是cmp,jcc 这两条标志语句,代表条件判断。
- 直接跳转的jmp代表执行的是它上面的分支。
- 每个分支内jmp跳的地址是一样的都是else{};这条语句之后的位置。
- 巧妙的运用了顺序结构
switch
int main(int argc, char const *argv[]) { int a=11; switch (a) { case 10: printf("a=10"); break; case 11: printf("a=11"); break; case 12: printf("a=12"); break; case 13: printf("a=13");c break; case 14: printf("a=14"); break; default: printf("!!"); } return 0; }
特征
- 当switch分支小的时候(视不同编译器实现,visual studio 为3个(包含)以下)返回百年结构和if-else结构相同,但是当分支测试的常量连续并且有一定数目,就会根据一个表保存要跳转的地址。
- 如果不是从0开始编译器会减去测试常量这个连续序列的最小值,直接得到偏移地址,加上基址即可到要跳转的分支。
总结
从分支语句中我们可以总结一些特征,测试条件用cmp、fcmp等指令,下面紧跟着jcc指令。jmp代表这个分支执行完了,一般跳出这个分支检测结构,而上面的cmp;jcc连着用的话一般指紧跟着的分支的否定,一般会跳到最后一个分支。switch在大量、连续的分支测试比if-else性能高。
循环
for (a=0;a<10;a++){ sum=sum+a; }
80483ef: c7 45 f8 00 00 00 00 mov DWORD PTR [ebp-0x8],0x0 80483f6: eb 0a jmp 8048402 <main+0x27> sum=sum+a; 80483f8: 8b 45 f8 mov eax,DWORD PTR [ebp-0x8] 80483fb: 01 45 fc add DWORD PTR [ebp-0x4],eax for (a=0;a<10;a++){ 80483fe: 83 45 f8 01 add DWORD PTR [ebp-0x8],0x1 8048402: 83 7d f8 09 cmp DWORD PTR [ebp-0x8],0x9 8048406: 7e f0 jle 80483f8 <main+0x1d>
初始化 a=0 mov DWORD PTR [ebp-0x8],0x0 条件判断,可以看到cmp;jcc;判断 cmp DWORD PTR [ebp-0x8],0x9 jle 80483f8 <main+0x1d> 控制变量变化 DWORD PTR [ebp-0x8],0x1 从上到下执行,首先初始化变量,接着直接jmp到cmp判断循环变量,向上跳到循环体
break和continue
for (a=0;a<10;a++){ if (a == 6){ continue; } if (a == 7){ break; } sum=sum+a; }
80483ef: c7 45 f8 00 00 00 00 mov DWORD PTR [ebp-0x8],0x0 80483f6: eb 19 jmp 8048411 <main+0x36> 80483f8: 83 7d f8 06 cmp DWORD PTR [ebp-0x8],0x6 80483fc: 74 0e je 804840c <main+0x31> 80483fe: 83 7d f8 07 cmp DWORD PTR [ebp-0x8],0x7 8048402: 74 15 je 8048419 <main+0x3e> 8048404: 8b 45 f8 mov eax,DWORD PTR [ebp-0x8] 8048407: 01 45 fc add DWORD PTR [ebp-0x4],eax 804840a: eb 01 jmp 804840d <main+0x32> 804840c: 90 nop 804840d: 83 45 f8 01 add DWORD PTR [ebp-0x8],0x1 8048411: 83 7d f8 09 cmp DWORD PTR [ebp-0x8],0x9 8048415: 7e e1 jle 80483f8 <main+0x1d> 8048417: eb 01 jmp 804841a <main+0x3f> 8048419: 90 nop 804841a: b8 00 00 00 00 mov eax,0x0 804841f: c9 leave 8048420: c3 ret
break跳出循环jmp 804840d
continue跳到循环变量控制也就是a++;add DWORD PTR [ebp-0x8],0x1
总结
for循环典型特征jmp指令,循环体,条件控制和判断。jmp跳条件控制和判断,然后回调循环体。