简明x86汇编语言教程(6)
2010-01-10 09:37:37 来源:WEB开发网上述代码确实做了一些无用功,当然,这是因为编译器没有对这段代码进行优化。让我们来关注一下这段代码中,是如何调用子程序的。不考虑myTransform这个函数实际进行的数值运算,最让我感兴趣的是这一行代码:
00401003 mov eax,dword ptr [nInput] ; 取参数
这里nInput是一个简简单单的变量符号吗?Visual C++的调试器显然不能告诉我们答案——它的设计目标是为了方便程序调试,而不是向你揭示编译器生成的代码的实际构造。我用另外一个反汇编器得到的结果是:
00401003 mov eax,dword ptr [ebp+8] ; 取参数
这和我们在main()中看到的压栈顺序是完全吻合的(注意,程序运行到这个地方的时候,EBP=ESP)。main()最终将i的值通过堆栈传递给了myTransform()。
剖析上面的程序只是说明了我前面所提到的子程序的一部分用法。对于汇编语言来说,完全没有必要拘泥于结构化程序设计的框架(在今天,使用汇编的主要目的在于提高执行效率,而不是方便程序的维护和调试,因为汇编不可能在这一点上做得比C++更好)。考虑下面的程序:
void myTransform1(int nCount, char* sBytes){
for(register int i=1; i<nCount; i++)
sBytes[i] += sBytes[i-1];
for(i=0; i<nCount; i++)
sBytes[i] <<= 1;
}
void myTransform2(int nCount, char* sBytes){
for(register int i=0; i<nCount; i++)
sBytes[i] <<= 1;
}
很容易看出,这两个函数包含了公共部分,即
for(i=0; i<nCount; i++)
sBytes[i] <<= 1;
目前,还没有编译器能够做到将这两部分合并。依然沿用刚才的编译选项,得到的反汇编结果是(同样地删除了int 3):
1: void myTransform1(int nCount, char* sBytes){
00401000 push ebp
00401001 mov ebp,esp
00401003 push ecx
2: for(register int i=1; i<nCount; i++)
00401004 mov dword ptr [i],1
0040100B jmp myTransform1+16h (00401016)
0040100D mov eax,dword ptr [i]
00401010 add eax,1
00401013 mov dword ptr [i],eax
00401016 mov ecx,dword ptr [i]
00401019 cmp ecx,dword ptr [nCount]
0040101C jge myTransform1+3Dh (0040103d)
3: sBytes[i] += sBytes[i-1];
0040101E mov edx,dword ptr [sBytes]
00401021 add edx,dword ptr [i]
00401024 movsx eax,byte ptr [edx-1]
00401028 mov ecx,dword ptr [sBytes]
0040102B add ecx,dword ptr [i]
0040102E movsx edx,byte ptr [ecx]
00401031 add edx,eax
00401033 mov eax,dword ptr [sBytes]
00401036 add eax,dword ptr [i]
00401039 mov byte ptr [eax],dl
0040103B jmp myTransform1+0Dh (0040100d)
4: for(i=0; i<nCount; i++)
0040103D mov dword ptr [i],0
00401044 jmp myTransform1+4Fh (0040104f)
00401046 mov ecx,dword ptr [i]
00401049 add ecx,1
0040104C mov dword ptr [i],ecx
0040104F mov edx,dword ptr [i]
00401052 cmp edx,dword ptr [nCount]
00401055 jge myTransform1+6Bh (0040106b)
5: sBytes[i] <<= 1;
00401057 mov eax,dword ptr [sBytes]
0040105A add eax,dword ptr [i]
0040105D mov cl,byte ptr [eax]
0040105F shl cl,1
00401061 mov edx,dword ptr [sBytes]
00401064 add edx,dword ptr [i]
00401067 mov byte ptr [edx],cl
00401069 jmp myTransform1+46h (00401046)
6: }
0040106B mov esp,ebp
0040106D pop ebp
0040106E ret
7:
8: void myTransform2(int nCount, char* sBytes){
00401070 push ebp
00401071 mov ebp,esp
00401073 push ecx
9: for(register int i=0; i<nCount; i++)
00401074 mov dword ptr [i],0
0040107B jmp myTransform2+16h (00401086)
0040107D mov eax,dword ptr [i]
00401080 add eax,1
00401083 mov dword ptr [i],eax
00401086 mov ecx,dword ptr [i]
00401089 cmp ecx,dword ptr [nCount]
0040108C jge myTransform2+32h (004010a2)
10: sBytes[i] <<= 1;
0040108E mov edx,dword ptr [sBytes]
00401091 add edx,dword ptr [i]
00401094 mov al,byte ptr [edx]
00401096 shl al,1
00401098 mov ecx,dword ptr [sBytes]
0040109B add ecx,dword ptr [i]
0040109E mov byte ptr [ecx],al
004010A0 jmp myTransform2+0Dh (0040107d)
11: }
004010A2 mov esp,ebp
004010A4 pop ebp
004010A5 ret
12:
13: int main(int argc, char* argv[])
14: {
004010B0 push ebp
004010B1 mov ebp,esp
004010B3 sub esp,0CCh
15: char a[200];
16: for(register int i=0; i<200; i++)a[i]=i;
004010B9 mov dword ptr [i],0
004010C3 jmp main+24h (004010d4)
004010C5 mov eax,dword ptr [i]
004010CB add eax,1
004010CE mov dword ptr [i],eax
004010D4 cmp dword ptr [i],0C8h
004010DE jge main+45h (004010f5)
004010E0 mov ecx,dword ptr [i]
004010E6 mov dl,byte ptr [i]
004010EC mov byte ptr a[ecx],dl
004010F3 jmp main+15h (004010c5)
17: myTransform1(200, a);
004010F5 lea eax,[a]
004010FB push eax
004010FC push 0C8h
00401101 call myTransform1 (00401000)
00401106 add esp,8
18: myTransform2(200, a);
00401109 lea ecx,[a]
0040110F push ecx
00401110 push 0C8h
00401115 call myTransform2 (00401070)
0040111A add esp,8
19: return 0;
0040111D xor eax,eax
20: }
0040111F mov esp,ebp
00401121 pop ebp
00401122 ret
更多精彩
赞助商链接