Win32反汇编(六)C/C++中的循环语句反汇编分析、置增置减反汇编分析与编译器的优化分析

前言

作者:浪子花梦,一个有趣的程序员 ~
此系列文章都是一些基础的文章,每篇文章都通过几个小例子快速的了解 Win32反汇编与OD的使用,在此作个笔记
如若对您有帮助,记得三连哟 ~


前文链接

Win32反汇编(一) 初步探索Win32反汇编 与 Ollydbg的简单使用
Win32反汇编(二)几种常见的指令反汇编详解:EAX、MOVSX与MOVZX、LEA、SUB、CMP与转移指令
Win32反汇编(三)深层次的了解各种转移指令:IF语句有符号与无符号跳转
Win32反汇编(四)栈的工作原理与堆栈平衡,函数方法参数的调用约定
Win32反汇编(五)C/C++中的 if-else 与 switch-case 的正向分析与反向分析


文章目录

这篇文章我们除了对 C/C++中的循环、置加减反汇编之外,还对VS的优化进行分析,就是当设置某一个优化属性时对应的反汇编分析,能让我们对程序有一个更好的理解 . . .


在这里插入图片描述

for 语句分析

for 循环是高级语言中比较灵活的一种循环语句了,比较常用,所以我们先来分析一下 for 循环语句的反汇编形式,如下所示,我们准备一个 for循环的代码:

#include <cstdio>

int main() {
	printf("start:\n");	

	int sum = 0;
	for (int i = 1; i <= 10; ++i) {
		sum += i;
	}

	printf("sum = %d\n", sum);

	printf("end!");

	return 0;
}

我们用 for循环计算 1 - 10 之间的累和,下面我们来看看反汇编是什么样子的,使用 OD调试如下所示,这是没有用VS进行优化的情况:
在这里插入图片描述
看样子是非常多的指令,如果没有优化的话,效率将会比较低,所以我们可以将它理解为第一代版本,下面我们会分析其它的一些优化过的版本,下面我们来分析一下这个程序吧 . . .

首先,程序在开始时会分配一个栈空间,然后执行 printf函数,如下所示:
在这里插入图片描述
然后对这两个局部变量分别初始化为 0、1 . . .

下面用红色框框起来的指令就是将 i 与 10作比较,如下所示:
在这里插入图片描述
如果条件成立,则执行下面的几条指令,如下所示:
在这里插入图片描述
实现了一个加法运算,然后通过 jmp 跳转到上面的指令,将一个内存单元的值(i的值)+ 1,然后做同样的事,继续判断,运行流程动图如下所示:

在这里插入图片描述

整个程序非常的简单,但是我们通过VS将这个程序进行一个高级优化,那么反汇编之后是什么样子的呢?

如下所示,我们将 VS 开启为最大优化:
在这里插入图片描述
然后我们重新编译 cpp代码,通过 OD打开如下所示:
在这里插入图片描述
我们发现上面的那些指令已经被压缩成这么短短几行了,而且上面也没跳转指令、比较指令了,那么上面的几行指令是什么意思呢?

我们观察上面的指令,它并没有 for循环的影子,它直接把 1 ~ 10 的结果先算出来了,然后直接作为 printf的参数传入,这样就不需要一次一次的计算判断了,这样效率就大大的提高了,有兴趣的朋友可以看看《编译原理》这本书 . . .
.
.


do-while 语句分析

我们只要把上面的 for语句的反汇编了解后,do-while、while理解起来非常的容易 . . .

首先,我们准备一个 do-while的cpp代码,这是没有优化的版本,如下所示:

#include <cstdio>

int main() {
	printf("start:\n");

	int sum = 0;
	int i = 1;

	do {
		sum += i;
		i += 1;
	} while (i <= 10);

	printf("sum = %d\n", sum);

	printf("end!");

	return 0;
}

我们做的事情是和上面 for 是一样的,都是计算 1 ~ 10 之和,通过OD反汇编如下所示:
在这里插入图片描述

do-while的执行体是下面的这些指令:
在这里插入图片描述
刚开始是没有判断的,先执行这些指令,然后通过 jle (小于等于)跳转到上面的指令, 和0A(10)作比较,这是比较好理解的,我们主要来分析一下开启优化的反汇编是什么样子的,如下所示:
在这里插入图片描述
主要代码只是几行,可见这IDE是多么强大,这样效率就大大的提高了,我们来分析这几行指令,首先,是通过 ecx、eax来存储两个变量的值(sum、i),然后使用 inc来使值 + 1,速度加快了 n倍,强的一批 . . .
.
.


while 语句分析

有了 for、do-while 的基础, while还不是手到擒来吗?不急,我们一定要熟悉每一种语句的反汇编方式,打好基础,这样才能学好逆向,cpp代码如下所示:

#include <cstdio>

int main() {
	printf("start:\n");

	int sum = 0;
	int i = 1;

	while (i <= 10) {
		sum += i;
		++i;
	}

	printf("sum = %d\n", sum);

	printf("end!");

	return 0;
}

首先是没有优化的反汇编结果,使用OD调试如下所示:
在这里插入图片描述
首先就是直接使用CMP进行比较,如果不成立则执行 jg指令跳转到后面的指令,如果成立则顺序执行,重复同样的行为10 次,动图演示如下所示:

在这里插入图片描述
下面我们来试试优化的 while语句的反汇编是什么样子的,如下所示:
在这里插入图片描述
这个和 for循环是差不多的,直接计算出循环内的数值是多少,然后直接调用 printf函数输出就行了 . . .

.
.


++、- - 运算符分析

下面我们来看看++、- -运算符的使用,cpp代码如下所示(无优化的情况):

#include <cstdio>

int main() {
	printf("start:\n");

	int i = 1;

	int j = i++;	// i = 2  j = 1  
	i = j++;		// i = 1  j = 2
		
	j = ++i;		// i = 2  j = 2  
	i = ++j;		// i = 3  j = 3

	printf("%d  %d\n", i, j);
	 
	printf("end!");

	return 0;
}

就是简单的运算而已,下面我们通过 OD来调试这个程序,看看发生了什么事,如下所示:
在这里插入图片描述
我们发现这个程序非常的长,其实运用了大量的mov、add指令,这是没有优化的情况,我们来看看这些指令代表什么意思,我们先来看最开始的这几条指令,如下所示:
在这里插入图片描述
他对应着后面注释的两条C语句,int j = i++ 做的事情就是先将 i的值给 j,然后i的值 + 1,我们可以从对应的汇编指令中看出,然后下面做的大量类似的操作都是一样的原理,下面我们来看一下- -运算符是什么样子的,如下所示:
在这里插入图片描述
操作的方式都是一样的,只不过 add 换成了 sub,下面我们来看一下优化的样子是什么样子的,如下所示:
在这里插入图片描述
我们发现直接将 1,1作为printf的参数进行打印,并没有之前的一系列的操作,因为编译器在编译时已经将 i,j的值算出来了,所以觉得这些语句没有必要执行了,这就是IDE的强大之处 . . .

inc 表示 ++ 运算, dec 表示 - -运算,这两种指令比add、sub快多了 . . . 以后有机会再演示吧,^ _ ^

.
.


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值