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(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 |
非