一丶 if else 的最简单情况还原 (无分支情况)
高级代码:
- #include "stdafx.h"
- int main(int argc, char* argv[])
- {
- unsigned int nNumber = 0;
- scanf("/span>,&nNumber);
- if(argc == 0)
- {
- nNumber = 0; // 第一种情况下无分支
- }
- else
- {
- nNumber = -1;
- }
- return nNumber;
- }
总共两种情况, 我们看下 Release 中怎么优化的把 (注意, 优化方式选择 O2, 速度优先)
汇编代码:
可以看到我们熟悉的代码了. 也就是昨天的三目运算.
总共三行汇编代码.
还原套路一样, 还是 代入大于 0 小于 0 还有 ==0, 看看最终结果是什么.
鉴于昨天还原过代码了, 这里这届代入, 还原出高级代码.
argc> 0 的情况下
if(argc> 0) eax = -1
argc <0 的情况下
if(argc < 0) eax =-1
argc == 0 的情况下
if(argc == 0) eax = 0
综合三种情况, 可以得出具体的条件了. 其中 >< 这样写是在高级语言中不能这样写的,
所以得出的还原代码为
- if(argc == 0) eax =0
- else eax == -1
二丶 if else 的第二种情况 (减少分支)
高级代码:
- #include "stdafx.h"
- int main(int argc, char* argv[])
- {
- unsigned int nNumber = 0;
- scanf("/span>,&nNumber);
- if(argc == nNumber)
- {
- printf("%d",nNumber / 8);
- }
- else
- {
- printf("%d",nNumber / 5);
- }
- return nNumber;
- }
对应汇编代码:
这个主要涉及找上下界问题
1. 地址: 1018 101C 分别保存了局部变量的值
2. 地址: 1023 比较了 argc 和局部变量 Var4 的值
3. 地址: 1025 jnz 跳转, 因为 1023 地址的比较会影响标志位 由此判定, argc 和 var4 比较, jnz(不相等) 但因为汇编中是反条件, 所以是相等的情况下
4. 因为 jnz 是一个地址, 所以这个地址是一个下界, 那么 jnz 上面的比较代码则是上界, 在其内部, 我们还原为 if 语句块 (先不用管里面具体干啥)
还原 if 语句块
if(argc == var4) printf("%d",var4 / 8);
还原 else 语句块
else printf("%d",var4 / 5);
在下方我们发现了相同的汇编代码, 也就是把 retn 放到上面去了, 这个主要是为了减少分支.
三丶 if else 第第三种形式, 代码外提的情况
代码外提的情况下, 主要在优化方式的选择上, 我们知道 o2(优化方式是速度优先) 现在我们改成 o1(也就是体积优先了)
这个时候就会出现代码外提.
高级代码:
- #include "stdafx.h"
- int main(int argc, char* argv[])
- {
- unsigned int nNumber = 0;
- scanf("/span>,&nNumber);
- if(argc == nNumber)
- {
- printf("Hello");
- }
- else
- {
- printf("World");
- }
- return nNumber;
- }
切换为 o1
protect -> setting 即可.
对应汇编代码:
首先, 找 if else 的时候, 先确定上下界
地址: 101A 位置 寻得了 if 的上界
地址: 101E 位置 寻得了 if 的下界
注意: 中间划掉了两个指令, 这两个指令是流水线优化, 平栈的指令. 所以没有帮助, 划掉
地址: 1025 位置, 其指令跳转的地址是一个增量, 那么则确定是 else 的下界
地址: 1027 位置 寻得了 else 的上界
其实简单来说, 第一个跳转位置, 跳转到哪里的一块区域, 是一个 if 的语句块而跳转的位置则是 else 语句块的上界, 其上面固定一个 jmp(注意其地址跳转是一个增量) 那么跳转的地址是 else 的下界
重点代码外提:
我们可以看到 我们的 if 语句块中 push 了一个 hello, 我们的 else 语句块中, push 了一个 Word
那么除了 if else 直接调用的 printf, 这样也是可以的. 因为参数是一样的. 平栈都是相等的. 所以可以提到外面来打印输出.
四丶多分支 if elseif .... else 的还原
这个其实很简单了. 如果是多分支, 则寻找上界下界即可.
因为编译器做的东西很多了.
高级代码:
- #include "stdafx.h"
- int main(int argc, char* argv[])
- {
- unsigned int nVar_4 = 5;
- scanf("%d", &nVar_4);
- // argc == 0 ? 0 : -1
- if (argc == 0)
- {
- printf("argc == 0\r\n");
- }
- else if(argc == 1)
- {
- printf("argc == 1\r\n");
- }
- else if(argc == 2)
- {
- printf("argc == 2\r\n");
- }
- else if(argc == 3)
- {
- printf("argc == 3\r\n");
- }
- else
- {
- printf("else\r\n");
- }
- printf("haha\r\n");
- printf("haha\r\n");
- printf("haha\r\n");
- printf("haha\r\n");
- printf("haha\r\n");
- return nVar_4;
- }
对应汇编代码:
看到这种, 直接判断为 if else if else if else 这种语句, 然后寻找上下界即可.
转载于:
作者: IBinary
来源: http://www.bubuko.com/infodetail-3129492.html