您的位置:首页 > 编程语言 > C语言/C++

C++反汇编学习笔记2——循环语句

2013-12-17 18:23 417 查看


两年前写的,欢迎大家吐槽!


转载请注明出处。

1.1 do循环

首先来看一段goto语句(什么?不知道goto语句,C语言老师太水了吧,这都不教。其实就和无条件跳转指令JMP差不多,但是最好不要用,因为会破坏结构化)的例子:

int GoToDo(intnCount)
{
int nSum =0;
int nIndex =0;
GOTO_DO:
nSum += nIndex;
nIndex++;
if (nIndex<= nCount)
{
gotoGOTO_DO;
}
return nSum;
}
没错,这个和do…while循环语句实现的功能相同,是一个循环,并且至少执行一遍。下面再来看主题:
23: int nSum = 0;
004272AE mov dword ptr [nSum],0
24: int nIndex = 0;
004272B5 mov dword ptr [nIndex],0
25: do
26: {
27: nSum += nIndex;
004272BC mov eax,dword ptr [nSum]
004272BF add eax,dword ptr [nIndex]
004272C2 mov dword ptr [nSum],eax
28: nIndex++;
004272C5 mov eax,dword ptr [nIndex]
004272C8 add eax,1
004272CB mov dword ptr [nIndex],eax
//先执行加操作
29: } while(nIndex <= nCount);
004272CE mov eax,dword ptr [nIndex]
004272D1 cmp eax,dword ptr [nCount]
004272D4 jle LoopDO+2Ch (4272BCh)
//跳转至do处
可以看到两段代码非常相似,但是仔细可以看出,if判定的条件和while判定的条件是相反的(这里指的是汇编代码的判定条件而不是C语言的代码),这样就很容易区分if语句与do…while之间的区别了。

1.2 while循环

由于循环结构的比较简单,所以就直接看例子,下面的也是。

36: while (nIndex <= nCount)
0042730C mov eax,dword ptr [nIndex]
0042730F cmp eax,dword ptr [nCount]
00427312 jg LoopWhile+48h (427328h)
//先进行判断
37: {
38: nSum += nIndex;
00427314 mov eax,dword ptr [nSum]
00427317 add eax,dword ptr [nIndex]
0042731A mov dword ptr [nSum],eax
39: nIndex++;
0042731D mov eax,dword ptr [nIndex]
00427320 add eax,1
00427323 mov dword ptr [nIndex],eax
40: }
00427326 jmp LoopWhile+2Ch (42730Ch)
//无条件跳转至while循环开始处
可以看到while循环需要进行两次跳转,如此一来效率必然比不上do…while循环。但是可以将其优化成如下模式:

If(xxx)

{

do

{

}while(xxx);

}

1.3 for循环

for循环是最常用的循环语句,同时也较为复杂。例子:

47: for (int nIndex = 0; nIndex <= nCount; ++nIndex)
00427365 mov dword ptr [nIndex],0
0042736C jmp LoopFor+37h (427377h)
//以上是赋初值部分,即nIndex = 0
0042736E mov eax,dword ptr [nIndex]
00427371 add eax,1
00427374 mov dword ptr [nIndex],eax
//步长计算部分,即++nIndex
00427377 mov eax,dword ptr [nIndex]
0042737A cmp eax,dword ptr [nCount]
0042737D jg LoopFor+4Ah (42738Ah)
//判断及跳转部分
48: {
49: nSum += nIndex;
0042737F mov eax,dword ptr [nSum]
00427382 add eax,dword ptr [nIndex]
00427385 mov dword ptr [nSum],eax
50: }
00427388 jmp LoopFor+2Eh (42736Eh)
//无条件跳转至步长计算部分

这里可以看到,for循环与while循环一样,都是先判断后执行,但是for循环共有3次跳转,是循环语句中效率最低的,但是如果把赋初值部分移动到循环之外即可转化为while循环然后再转化为do…while循环。

以上代码均为Debug版本的反汇编代码,Release版本的会按照后面讲解的优化方案进行优化,此处不再赘述。

1.4 循环结构优化——代码外提

例子:IDA Pro反汇编的Release版本

源代码:

// 代码外提
int CodePick(intnCount)
{
int nSum =0;
int nIndex =0;
do
{
nSum += nIndex;
nIndex++;
} while(nIndex< nCount - 1);
return nSum;
}
反汇编代码:

.text:00401000 arg_0 = dword ptr 8

.text:00401000

.text:00401000 push ebp

.text:00401001 mov ebp, esp

.text:00401003 mov edx, [ebp+arg_0]

.text:00401006 xor eax, eax

.text:00401008 xor ecx, ecx

.text:0040100A dec edx

.text:0040100B jmp short loc_401010

.text:0040100B ;---------------------------------------------------------------------------

.text:0040100D align 10h

.text:00401010

.text:00401010 loc_401010: ; CODE XREF:sub_401000+Bj

.text:00401010 ;sub_401000+15j

.text:00401010 add eax, ecx

.text:00401012 inc ecx

.text:00401013 cmp ecx,edx

.text:00401015 jl short loc_401010

可以很明显的看到.text:0040100A dec edx这条语句不在循环中,这就是代码外提。把不需要重复的计算都放到循环之外,这样可以减少计算量,提高计算效率。

1.5 强度降低

源代码:
// 强度降低
void DoRate(int argc)
{
int t = 0;
int i = 0;
while (t <argc)
{
t = i * 99;
i++;
}
printf("%d",t);
}
这里只列出循环的反汇编代码:

.text:00401030 loc_401030: ; CODE XREF: sub_401020+17j

.text:00401030 mov eax, ecx

.text:00401032 add ecx, 63h

.text:00401035 cmp eax, edx

.text:00401037 jl short loc_401030

这里把乘法转化成了加法从而大大减少了运算量,提高了程序的执行效率。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: