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

来源:互联网 发布:centos 安装desktop 编辑:程序博客网 时间:2024/05/02 04:16

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

转载请注明出处。

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

这里把乘法转化成了加法从而大大减少了运算量,提高了程序的执行效率。
0 0
原创粉丝点击