反汇编角度解释C++语言中引用的原理

来源:互联网 发布:淘宝代练跑商可靠吗 编辑:程序博客网 时间:2024/03/28 20:19
给出一个很简单的引用实例C++源码:
#include<iostream>
using namespace std;


void Add(int& __nVar)
{
__nVar++;
}

void main()
{
int nVar=0x00000001;
Add(nVar);
cout<<"nVar="<<nVar<<endl;
}
运行结果:nVar=2



下面是反汇编代码:        
5:        void Add(int& __nVar)
6:    {
00401580 55                   push        ebp
00401581 8B EC                mov         ebp,esp
00401583 83 EC 40             sub         esp,40h
00401586 53                   push        ebx
00401587 56                   push        esi
00401588 57                   push        edi
00401589 8D 7D C0             lea         edi,[ebp-40h]
0040158C B9 10 00 00 00       mov         ecx,10h
00401591 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
00401596 F3 AB                rep stos    dword ptr [edi]//以上为DEBUG模式标准子函数内部初始代码;
7:        __nVar++;
00401598 8B 45 08             mov         eax,dword ptr [ebp+8]//将参数复制到 EAX;参数的内容其实是32位的地址;
0040159B 8B 08                mov         ecx,dword ptr [eax]//将参数内容的地址所指向的DWORD类型数据复制到ECX;
0040159D 83 C1 01             add         ecx,1//ECX内容加1;
004015A0 8B 55 08             mov         edx,dword ptr [ebp+8]//将参数复制到 EDX;参数的内容其实是32位的地址;
004015A3 89 0A                mov         dword ptr [edx],ecx//将ECX的内容复制到参数内容的地址所指向的DWORD类型数据;
8:    }
004015A5 5F                   pop         edi
004015A6 5E                   pop         esi
004015A7 5B                   pop         ebx
004015A8 8B E5                mov         esp,ebp
004015AA 5D                   pop         ebp
004015AB C3                   ret//DEBUG模式子函数返回代码;恢复现场;


10:   void main()
11:   {
004015C0 55                   push        ebp
004015C1 8B EC                mov         ebp,esp
004015C3 83 EC 44             sub         esp,44h
004015C6 53                   push        ebx
004015C7 56                   push        esi
004015C8 57                   push        edi
004015C9 8D 7D BC             lea         edi,[ebp-44h]
004015CC B9 11 00 00 00       mov         ecx,11h
004015D1 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
004015D6 F3 AB                rep stos    dword ptr [edi]//以上为DEBUG模式标准子函数内部初始代码;注意main()对编译器而言仍然是子函数;
并不是入口函数;
12:   int nVar=0x00000001;
004015D8 C7 45 FC 01 00 00 00 mov         dword ptr [ebp-4],1//将0x00000001赋值给nVar;
13:   Add(nVar);
004015DF 8D 45 FC             lea         eax,[ebp-4]//得到nVar的偏移地址
004015E2 50                   push        eax//EAX作为实际参数提供给Add()函数
004015E3 E8 52 FC FF FF       call        @ILT+565(Add) (0040123a)//通过ILT表调用Add函数;
004015E8 83 C4 04             add         esp,4//恢复栈顶指针;因为前面的PUSH EAX;
14:   cout<<"nVar="<<nVar<<endl;
//打印函数不做反汇编解释;
004015EB 68 C8 10 40 00       push        offset @ILT+195(std::endl) (004010c8)
004015F0 8B 4D FC             mov         ecx,dword ptr [ebp-4]
004015F3 51                   push        ecx
004015F4 68 1C E0 46 00       push        offset string "nVar=" (0046e01c)
004015F9 68 90 BE 47 00       push        offset std::cout (0047be90)
004015FE E8 87 FC FF FF       call        @ILT+645(std::operator<<) (0040128a)
00401603 83 C4 08             add         esp,8
00401606 8B C8                mov         ecx,eax
00401608 E8 F2 FA FF FF       call        @ILT+250(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010ff)
0040160D 8B C8                mov         ecx,eax
0040160F E8 CC FB FF FF       call        @ILT+475(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e0)
15:   }
//此处省略掉main()函数返回代码;

总结:从主函数main()的对Add函数的调用处可以看出,EAX作为实际参数入栈;EAX的内容为变量nVar的偏移地址;这一点非常
重要;
再回过头去看Add函数体内,提到2次的“参数内容的地址所指向的DWORD类型”其实就是EAX的内容;即nVar的偏移地址;
因此可以看出,在Add函数体内,有权限对变量nVar进行操作;比如+1;因为参数EAX将nVar的偏移地址传递给了Add函数,Add函数
就可以通过这个偏移地址去改动此地址的内容;

因此,对于代码:Add(nVar);我们知道传递的其实是nVar的偏移地址;对于引用的作用也就一目了然了;










原创粉丝点击