C反汇编实例(详细注解版)(二)

来源:互联网 发布:合并两首歌用的软件 编辑:程序博客网 时间:2024/04/29 02:35
 

    那么有了上述三方面的基础,我们就可以来逐一解读那段“传奇”的汇编代码了。

初始化i

00411A3E mov dword ptr [i],0

跳转至条件判断

00411A45 jmp myfunction+30h (411A50h)

循环表达式,对i每轮加1

00411A47 mov eax,dword ptr [i]

00411A4A add eax,1

00411A4D mov dword ptr [i],eax

条件判断,若不满足i < 3,则跳出循环

00411A50 cmp dword ptr [i],3

00411A54 jge myfunction+0AEh (411ACEh)

{ i的循环体

这里比较特殊,传说中的“嵌套循环”,可以对比

最前面的C代码看一下,其实是一样的

初始化j

00411A56 mov dword ptr [j],0

跳至j循环的条件判断

00411A5D jmp myfunction+48h (411A68h)

每轮对j1

00411A5F mov eax,dword ptr [j]

00411A62 add eax,1

00411A65 mov dword ptr [j],eax

j循环的条件判断

00411A68 cmp dword ptr [j],3

00411A6C jge myfunction+0A9h (411AC9h)

{ j的循环体

这里省略的是数组赋值的过程代码,会在稍后分析

} j 的循环体结束

跳到jexpr

00411AC7 jmp myfunction+3Fh (411A5Fh)

} i的循环体结束

跳至iexpr

00411AC9 jmp myfunction+27h (411A47h)

    以下我们再详细分析下上面挖下来的数组赋值的代码。为了方便起见,再把C语句贴如下:

c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j];

; 还记得前面所说的汇编访问二维数组的方式么?忘记的话,再回过头去看一下哈

 

; 第i行,每行3个占4字节的int类型,所以乘以i×12(0Ch),表示行偏移

00411A6E mov eax,dword ptr [i]

00411A71 imul eax,eax,0Ch

 

; 往寄存器送入一些变量

00411A74 mov ecx,dword ptr [a]

00411A77 mov edx,dword ptr [j]

00411A7A mov esi,dword ptr [b]

 

00411A7D mov eax,dword ptr [ecx+eax] ; ecx已经含有a数组的起始地址,这句相当于往

; eax存入基址+i行偏移这个地址开始的int

; 型值,也就是a[i][0]

 

00411A80 imul eax,dword ptr [esi+edx*4] ; 这句比较好理解,esib数组起始地址

                                         ; edx * 4表示列偏移,相当于eax * b[0][j]

                                         ; 也就是eax = a[i][0] * b[0][j]

; 同理,ecx获得i行偏移量

00411A84 mov ecx,dword ptr [i]

00411A87 imul ecx,ecx,0Ch

00411A8A mov edx,dword ptr [a] ; edx保存的a数组基地址

00411A8D mov esi,dword ptr [j]  ; esi = j

00411A90 mov edi,dword ptr [b]  ; edi保存的b数组基地址

00411A93 mov ecx,dword ptr [edx+ecx+4] ; edx 基址 = a

                                       ; ecx 行偏移 = i

                                       ; 4  列偏移 = 1

                                      ; 综上,ecx = a[i][1]

; edi b的基址;esi = j,第j列;0Ch,行偏移量,相当于是第1

; 综上,ecx = ecx * b[1][j],即ecx = a[i][1] * b[1][j]

00411A97 imul ecx,dword ptr [edi+esi*4+0Ch]

; 把第一项a[i][0] * b[0][j]和第二项相加存入eax,从这也可以看出

; 其实eax就是用来保存最后结果的,此时eax = a[i][0] * b[0][j] + a[i][1] * b[1][j]

00411A9C add eax,ecx

; 以下这段不用解释了吧?依样花葫芦,到411AB6为止

; eax = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j]

00411A9E mov edx,dword ptr [i]

00411AA1 imul edx,edx,0Ch

00411AA4 mov ecx,dword ptr [a]

00411AA7 mov esi,dword ptr [j]

00411AAA mov edi,dword ptr [b]

00411AAD mov edx,dword ptr [ecx+edx+8]

00411AB1 imul edx,dword ptr [edi+esi*4+18h]

00411AB6 add eax,edx

; 首先是老规矩,通过ecxedx找到了c[i][j]的内存地址,411AC4这句就是把

; 前边eax中的计算结果写入到内存中代表c[i][j]这个元素的位置

00411AB8 mov ecx,dword ptr [i]

00411ABB imul ecx,ecx,0Ch

00411ABE add ecx,dword ptr [c]

00411AC1 mov edx,dword ptr [j]

00411AC4 mov dword ptr [ecx+edx*4],eax

    这样就完成了a中第i行每个元素分别与b中第j列的每个元素的乘积保存到c的第i行第j列元素中,这么一个操作,确实比较复杂。如果看不大懂,不要紧,回过头多看几遍,一定会明白的,如果说有些话我的表述不妥当,也请大侠指出,以免误人子弟J

    我的一些朋友问我,研究汇编,尤其研究C反汇编,到底有什么用处?我的理解是,除非你是底层开发人员,否则我们的目的并非是学习如何运用汇编写复杂的算法程序,而是将它应用在排错、性能优化等方面,如果你能看懂一些汇编代码,那么当你的客户程序崩溃时,你打开调试器,就可以先简要分析出出错程序代码的大致意思,这对你的调试是相当有帮助的。而如果汇编懂得较深的话(我只是皮毛而已),那么就可以对C目标程序进行有目的的修改以提高程序性能,因为有时候即便是release模式下的exe文件,仍然有可以优化之处,只是这时一定要谨慎再谨慎,万一捡了芝麻丢了西瓜就太不划算了。当然了还有另外某些用途,呵呵,比较邪恶,就不点破了……总之希望本文能对大家有所帮助!

原创粉丝点击