学习C++反汇编-构造函数
来源:互联网 发布:c语言库函数大全 编辑:程序博客网 时间:2024/06/05 10:23
1.局部对象下的构造函数
C++源代码:
#include<iostream>using namespace std;class CNumber{public:int num;CNumber(){num = 1;}};int main(){CNumber Number;return 0;}生成的汇编代码:
int main(){00C81750 push ebp 00C81751 mov ebp,esp 00C81753 sub esp,0D0h 00C81759 push ebx 00C8175A push esi 00C8175B push edi 00C8175C lea edi,[ebp-0D0h] 00C81762 mov ecx,34h 00C81767 mov eax,0CCCCCCCCh 00C8176C rep stos dword ptr es:[edi] 00C8176E mov eax,dword ptr ds:[00C88004h] 00C81773 xor eax,ebp 00C81775 mov dword ptr [ebp-4],eax CNumber Number;00C81778 lea ecx,[Number] 取得对象首地址传入ecx中作为参数 00C8177B call CNumber::CNumber (0C81348h) 调用构造函数return 0;00C81780 xor eax,eax }#include<iostream>using namespace std;class CNumber{public:int num;CNumber()00C816A0 push ebp 00C816A1 mov ebp,esp 00C816A3 sub esp,0CCh 00C816A9 push ebx 00C816AA push esi 00C816AB push edi 00C816AC push ecx 00C816AD lea edi,[ebp-0CCh] 00C816B3 mov ecx,33h 00C816B8 mov eax,0CCCCCCCCh 00C816BD rep stos dword ptr es:[edi] 00C816BF pop ecx 还原ecx,ecx中保存对象的首地址00C816C0 mov dword ptr [this],ecx 传递给this指针{num = 1;00C816C3 mov eax,dword ptr [this] eax中保存了对象的首地址00C816C6 mov dword ptr [eax],1 将数据成员设置为1}00C816CC mov eax,dword ptr [this] 将this指针存入eax中作为返回值00C816CF pop edi 00C816D0 pop esi 00C816D1 pop ebx 00C816D2 mov esp,ebp 00C816D4 pop ebp 00C816D5 ret在进入对象的作用域时编译器会产生调用构造函数的代码。由于构造函数属于成员函数,因此在调用过程中同样需要传递this指针。构造函数调用结束后,会将this指针作为返回值。
2.堆对象下的构造函数
C++源代码:
#include<iostream>using namespace std;class CNumber{public:int num;CNumber(){num = 1;}};int main(){CNumber *Number=0;Number=new CNumber;Number->num=2;printf("%d \r\n",Number->num);return 0;}//用结构体定义了一个实体,那么要引用里面的成员就用.操作符//用结构体定义的是一个结构指针,那么要引用里面的成员就用->操作符生成的汇编代码:
int main(){002519C3 call 532519C8 002519C8 push esi 002519C9 push edi 002519CA lea edi,[ebp-0F4h] 002519D0 mov ecx,3Ah 002519D5 mov eax,0CCCCCCCCh 002519DA rep stos dword ptr es:[edi] 002519DC mov eax,dword ptr ds:[0025B004h] 002519E1 xor eax,ebp 002519E3 push eax 002519E4 lea eax,[ebp-0Ch] 002519E7 mov dword ptr fs:[00000000h],eax CNumber *Number = 0;002519ED mov dword ptr [Number],0 指针初始化为0 Number = new CNumber;002519F4 push 4 压入类的大小用于堆内存的申请002519F6 call operator new (02512C1h) 002519FB add esp,4 002519FE mov dword ptr [ebp-0ECh],eax 使用临时变量保存new返回值00251A04 mov dword ptr [ebp-4],0 保存申请堆空间的次数00251A0B cmp dword ptr [ebp-0ECh],0 检测堆内存是否申请成功00251A12 je main+77h (0251A27h) 失败则跳过构造函数00251A14 mov ecx,dword ptr [ebp-0ECh] 申请成功将对象首地址传入ecx中00251A1A call CNumber::CNumber (02513FCh) 调用构造函数00251A1F mov dword ptr [ebp-0F4h],eax 00251A25 jmp main+81h (0251A31h) 00251A27 mov dword ptr [ebp-0F4h],0 申请堆空间失败设置指针值为NULL00251A31 mov eax,dword ptr [ebp-0F4h] 00251A37 mov dword ptr [ebp-0E0h],eax 00251A3D mov dword ptr [ebp-4],0FFFFFFFFh 00251A44 mov ecx,dword ptr [ebp-0E0h] 00251A4A mov dword ptr [Number],ecx Number->num = 2;00251A4D mov eax,dword ptr [Number] eax得到this指针Number->num = 2;00251A50 mov dword ptr [eax],2 为成员变量赋值printf("%d \r\n", Number->num);00251A56 mov eax,dword ptr [Number] 00251A59 mov ecx,dword ptr [eax] 00251A5B push ecx 00251A5C push 258B30h 00251A61 call _printf (02513C5h) 00251A66 add esp,8 return 0;00251A69 xor eax,eax }在使用new申请了堆空间以后需要调用构造函数以完成对象的数据成员初始化过程。如果堆空间申请失败则会避开构造函数的调用。因此需要编译器检查堆空间的申请结果产生一个双分支结构。
3.参数对象下的构造函数
C++源代码:
#include<iostream>using namespace std;class CMyString{public:char * m_pString;//无参构造函数 CMyString(){m_pString = 0;}//拷贝构造函数 CMyString(CMyString& obj){int nLen = strlen(obj.m_pString);this->m_pString = new char[nLen + sizeof(char)];strcpy(this->m_pString, obj.m_pString);}//析构函数 ~CMyString(){if (m_pString != NULL){delete[] m_pString;m_pString = NULL;}}//设置字符串的成员函数 void setString(char * pString){int nLen = strlen(pString);if (m_pString != NULL){delete[] m_pString;m_pString = NULL;}m_pString = new char[nLen + sizeof(char)];strcpy(m_pString, pString);}};//参数是对象类型会触发拷贝构造函数 void Show(CMyString MyString){printf(MyString.m_pString);}int main(){CMyString MyString;MyString.setString("Hello");Show(MyString);return 0;}生成的汇编代码:
int main(){00115460 push ebp 00115461 mov ebp,esp 00115463 push 0FFFFFFFFh 00115465 push 116318h 0011546A mov eax,dword ptr fs:[00000000h] 00115470 push eax 00115471 sub esp,0ECh 00115477 push ebx 00115478 push esi 00115479 push edi 0011547A lea edi,[ebp-0F8h] 00115480 mov ecx,3Bh 00115485 mov eax,0CCCCCCCCh 0011548A rep stos dword ptr es:[edi] 0011548C mov eax,dword ptr ds:[0011B004h] 00115491 xor eax,ebp 00115493 mov dword ptr [ebp-10h],eax 00115496 push eax 00115497 lea eax,[ebp-0Ch] 0011549A mov dword ptr fs:[00000000h],eax CMyString MyString;001154A0 push 4 001154A2 lea ecx,[MyString] 001154A5 call CMyString::__autoclassinit2 (0111424h) 001154AA lea ecx,[MyString] 001154AD call CMyString::CMyString (0111433h) 调用无参构造函数001154B2 mov dword ptr [ebp-4],0 MyString.setString("Hello");001154B9 push 118B30h 001154BE lea ecx,[MyString] 001154C1 call CMyString::setString (011141Ah) 调用成员函数Show(MyString);001154C6 push ecx 001154C7 mov ecx,esp 获取参数对象的地址保存到ecx中001154C9 mov dword ptr [ebp-0E4h],esp 001154CF lea eax,[MyString] 获取对象的地址保存到eax中 001154D2 push eax 将MyString的地址作为参数调用拷贝构造函数001154D3 call CMyString::CMyString (0111429h) 001154D8 mov dword ptr [ebp-0F8h],eax 保存拷贝构造函数返回的this指针001154DE call Show (011141Fh) 001154E3 add esp,4 return 0;001154E6 mov dword ptr [ebp-0F0h],0 001154F0 mov dword ptr [ebp-4],0FFFFFFFFh 001154F7 lea ecx,[MyString] 001154FA call CMyString::~CMyString (011140Bh) 001154FF mov eax,dword ptr [ebp-0F0h] }在执行Show之前先进入到CMyString的拷贝构造函数中。由于使用了深拷贝的方式,对对象中的数据成员所指向的堆空间数据也进行了数据复制,因此当参数对象被销毁时,释放的堆空间数据是拷贝对象所制作的数据副本,对源对象没有任何影响。
4.返回对象下的构造函数
C++源代码:
#include<iostream>using namespace std;class CMyString{public:char * m_pString;//无参构造函数 CMyString(){m_pString = 0;}//拷贝构造函数 CMyString(CMyString& obj){int nLen = strlen(obj.m_pString);this->m_pString = new char[nLen + sizeof(char)];strcpy(this->m_pString, obj.m_pString);}//析构函数 ~CMyString(){if (m_pString != NULL){delete[] m_pString;m_pString = NULL;}}//设置字符串的成员函数 void setString(char * pString){int nLen = strlen(pString);if (m_pString != NULL){delete[] m_pString;m_pString = NULL;}m_pString = new char[nLen + sizeof(char)];strcpy(m_pString, pString);}};CMyString GetMyString(){CMyString MyString;MyString.setString("World");return MyString;}int main(){CMyString MyString=GetMyString();}生成的汇编代码:
int main(){01351C90 push ebp 01351C91 mov ebp,esp 01351C93 sub esp,0D0h 01351C99 push ebx 01351C9A push esi 01351C9B push edi 01351C9C lea edi,[ebp-0D0h] 01351CA2 mov ecx,34h 01351CA7 mov eax,0CCCCCCCCh 01351CAC rep stos dword ptr es:[edi] 01351CAE mov eax,dword ptr ds:[0135B004h] 01351CB3 xor eax,ebp 01351CB5 mov dword ptr [ebp-4],eax CMyString MyString = GetMyString();01351CB8 push 4 01351CBA lea ecx,[MyString] 01351CBD call CMyString::__autoclassinit2 (01351212h) 01351CC2 lea eax,[MyString] 01351CC5 push eax 01351CC6 call GetMyString (0135120Dh) 01351CCB add esp,4 }CMyString GetMyString(){013519C0 push ebp 013519C1 mov ebp,esp 013519C3 push 0FFFFFFFFh 013519C5 push 1356568h 013519CA mov eax,dword ptr fs:[00000000h] 013519D0 push eax 013519D1 sub esp,0DCh 013519D7 push ebx 013519D8 push esi 013519D9 push edi 013519DA lea edi,[ebp-0E8h] 013519E0 mov ecx,37h 013519E5 mov eax,0CCCCCCCCh 013519EA rep stos dword ptr es:[edi] 013519EC mov eax,dword ptr ds:[0135B004h] 013519F1 xor eax,ebp 013519F3 mov dword ptr [ebp-10h],eax 013519F6 push eax 013519F7 lea eax,[ebp-0Ch] 013519FA mov dword ptr fs:[00000000h],eax 01351A00 mov dword ptr [ebp-0E4h],0 CMyString MyString;01351A0A push 4 01351A0C lea ecx,[MyString] 01351A0F call CMyString::__autoclassinit2 (01351212h) 01351A14 lea ecx,[MyString] 01351A17 call CMyString::CMyString (013513CFh) 01351A1C mov dword ptr [ebp-4],0 MyString.setString("World");01351A23 push 1358B30h 01351A28 lea ecx,[MyString] 01351A2B call CMyString::setString (01351136h) return MyString;01351A30 lea eax,[MyString] 获取局部变量的首地址 01351A33 push eax 将对象的地址作为参数01351A34 mov ecx,dword ptr [ebp+8] 01351A37 call CMyString::CMyString (01351276h) 调用隐含的参数对象的拷贝构造函数,以局部对象的地址作为参数 01351A3C mov ecx,dword ptr [ebp-0E4h] 01351A42 or ecx,1 01351A45 mov dword ptr [ebp-0E4h],ecx 01351A4B mov dword ptr [ebp-4],0FFFFFFFFh 01351A52 lea ecx,[MyString] 01351A55 call CMyString::~CMyString (01351069h) 01351A5A mov eax,dword ptr [ebp+8] 将参数作为返回值}虽然编译器会对返回值为对象类型的函数进行调整,修改其参数与返回值,但是它留下了一个与返回指针类型不同的特征,那就是在函数中使用拷贝构造函数。返回值和参数为对象指针类型的函数,不会使用以参数为目标的拷贝构造函数,而是直接使用指针保存对象首地址。
0 0
- 学习C++反汇编-构造函数
- c反汇编学习汇编
- cpp反汇编分析之构造函数
- cpp反汇编之构造函数2
- 反汇编学习之路之构造函数与析构函数(一)
- 反汇编学习(3) -- add函数反汇编
- 反汇编C语言的函数
- 学习C++反汇编-析构函数
- 学习C++反汇编-虚函数
- 从反汇编的角度看C++语法(构造函数)
- 汇编学习第四课之main函数反汇编
- c&c++反汇编与逆向分析学习笔记(4)--启动函数和用户入口
- 反汇编 c++/c 确定main函数的位置
- 函数反汇编
- 函数调用反汇编
- 启动函数反汇编
- 函数调用反汇编
- 反汇编---汇编基础学习
- 使用git和github管理自己的项目---真实开发环境的策略
- 6. 自定义函数
- JSP学习笔记五之application和page对象
- Spring MVC 通过@Value注解读取.properties配置
- oracle中pl/sql程序高级类型的使用
- 学习C++反汇编-构造函数
- 集训队专题(7)1003 Task Schedule
- 机器学习: 贝叶斯决策 2
- 对象 接口 抽象类
- hdu 1584 蜘蛛牌【dfs+简单剪枝】
- Nginx一个server主机上80、433http、https共存
- 空间统计史话:元首的黑科技
- yii2 strace 追踪,本地文件
- 编译原理学习(1)