从逆向分析角度看C++拷贝构造函数
来源:互联网 发布:郑州java培训排名 编辑:程序博客网 时间:2024/05/01 00:19
一段C++代码:
//: HowMany_2.cpp#include <iostream>using namespace std;class HowMany { static int objectCount; public: HowMany() { ++objectCount; print("HowMany()"); } ~HowMany() { --objectCount; print("~HowMany()"); } HowMany(const HowMany& h) { ++objectCount; print("HowMany(const HowMany&)"); } void print(const char ss[]) { cout << ss << ": "; cout << "objectCount = " << objectCount << endl; return ; }};int HowMany::objectCount = 0;HowMany f(HowMany x) { x.print("x argument inside f()"); cout << "Return From f()" << endl; return x; // 有返回值 x}int main() { { HowMany h; cout << "Entering f()" << endl; HowMany h2 = f(h); } return 0;} ///:~
运行结果:
Assembly Code:
38: int main() {39: {40: HowMany h;004017FD lea ecx,[h]; [h] 为对象 h 的内存地址00401800 call @ILT+685(HowMany::HowMany) (004012b2); 调用构造函数00401805 mov dword ptr [ebp-4],041: cout << "Entering f()" << endl;0040180C push offset @ILT+200(std::endl) (004010cd)00401811 push offset string "Entering f()" (0046f090)00401816 push offset std::cout (0047ce98)0040181B call @ILT+660(std::operator<<) (00401299); 题外话,观察一下进栈顺序00401820 add esp,800401823 mov ecx,eax00401825 call @ILT+480(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e5)42: HowMany h2 = f(h);0040182A push ecx0040182B mov ecx,esp; 当前 ESP 所指的栈块作为临时对象Temp的内存地址0040182D mov dword ptr [ebp-18h],esp00401830 lea eax,[h]00401833 push eax; 将h的内存地址[h]压入堆栈00401834 call @ILT+0(HowMany::HowMany) (00401005); 调用拷贝构造函数,把h的内容拷贝到Temp的内存中00401839 mov dword ptr [ebp-1Ch],eax0040183C lea ecx,[h2]0040183F push ecx; 将h2的内存地址[h2]压入堆栈00401840 call @ILT+640(f) (00401285); 调用f()函数00401845 add esp,800401848 mov dword ptr [ebp-20h],eax43: }0040184B lea ecx,[h2]0040184E call @ILT+500(HowMany::~HowMany) (004011f9); 调用析构函数,销毁h200401853 mov dword ptr [ebp-4],0FFFFFFFFh0040185A lea ecx,[h]0040185D call @ILT+500(HowMany::~HowMany) (004011f9); 调用析构函数,销毁h44: // getchar();45: return 0;00401862 xor eax,eax46: } ///:~
fun()函数的工作机制:
32: HowMany f(HowMany x) {33: x.print("x argument inside f()");004015DB push offset string "x argument inside f()" (0046f030)004015E0 lea ecx,[ebp+0Ch]004015E3 call @ILT+575(HowMany::print) (00401244)34: cout << "Return From f()" << endl;004015E8 push offset @ILT+200(std::endl) (004010cd)004015ED push offset string "Return From f()" (0046f01c)004015F2 push offset std::cout (0047ce98)004015F7 call @ILT+660(std::operator<<) (00401299)004015FC add esp,8004015FF mov ecx,eax00401601 call @ILT+480(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e5)35: return x;00401606 lea eax,[ebp+0Ch]; [ebp+0C]为Temp的内存地址00401609 push eax0040160A mov ecx,dword ptr [ebp+8]; [ebp+8]为h2的内存地址,ecx指向h2内存块0040160D call @ILT+0(HowMany::HowMany) (00401005); 调用拷贝构造函数,将Temp的内容拷贝到h2的内存中00401612 mov ecx,dword ptr [ebp-10h]00401615 or ecx,100401618 mov dword ptr [ebp-10h],ecx0040161B mov byte ptr [ebp-4],00040161F lea ecx,[ebp+0Ch]; ecx保存Temp的内存地址00401622 call @ILT+500(HowMany::~HowMany) (004011f9); 调用析构函数,销毁Temp00401627 mov eax,dword ptr [ebp+8]; eax保存h2的内存地址36: }
对于运行结果
解析如下:
1. 对象h调用构造函数
2. 输出字符串“Entering f()”
3. 在进入f()函数之前,创建了一个临时对象Temp,调用拷贝构造函数,将对象h的内容拷贝到Temp中
4. 进入f()函数,在执行“return x”语句后,调用拷贝构造函数,将对象Temp的内容拷贝到h2中(完成了h2 = f(h)的工作)
5. 在f()函数结束前,为Temp调用析构函数,销毁Temp对象
6. 退出f()函数,在main函数结束前,先销毁对象h2,最后销毁对象h
----------------------------------------------------------------------------
逆向分析时执行“HowMany h2 = f(h);”语句过程中栈分布的记录:
*****
进入f()函数前(创建了一个临时对象Temp,调用拷贝构造函数,将对象h的内容拷贝到Temp中)
进入f()函数后
*********************************************************
再看<<Thinking in C++>>中的一段代码,更为清晰的讲解了拷贝构造函数的机制:
//: HowMany_2.cpp#include <string>#include <iostream>using namespace std;class HowMany { string name; static int objectCount; public: HowMany(const string& id = "") { name = id; ++objectCount; print("HowMany()"); } ~HowMany() { --objectCount; print("~HowMany()"); } HowMany(const HowMany& h) { name = h.name + "copy"; ++objectCount; print("HowMany(const HowMany&)"); } void print(const string& msg = "") { if (msg.length() != 0) { cout << msg << endl; } cout << '\t' << name << ": " << "objectCount = " << objectCount << endl; return ; }};int HowMany::objectCount = 0;HowMany f(HowMany x) { x.print("x argument inside f()"); cout << "Return From f()" << endl; return x;}int main() { { HowMany h("h"); cout << "Entering f()" << endl; HowMany h2 = f(h); cout << "Call f(), no return value" << endl; f(h); cout << "After call to f()" << endl; } // getchar(); return 0;} ///:~
运行结果:
解释如下:
1. 创建对象h,并调用构造函数
2. 输出“Entering f()”字符串
3. 进入f()函数前,创建一个临时对象Temp,并调用拷贝构造函数,将对象h的内容拷贝到Temp中
4. 进入f()函数后,在“return x”时,调用拷贝构造函数,将对象Temp的内容拷贝到h2中,在函数结束前调用析构函数,销毁对象Temp
5. 输出字符串
6.进入f()函数前,创建一个临时对象Temp,并调用拷贝构造函数,将对象h的内容拷贝到Temp中
7. 进入f()函数后,创建一个临时对象x,在“return x”时,调用拷贝构造函数,将对象Temp的内容拷贝到x中,在函数结束前调用析构函数,先销毁对象Temp,再销毁对象x
8. 在main函数结束前,调用析构函数,先销毁对象h2,再销毁对象h
- 从逆向分析角度看C++拷贝构造函数
- 从逆向分析角度看C++的析构函数
- 从逆向分析角度看C++虚函数
- 从逆向分析角度看C++ 中的引用
- 从反汇编的角度看C++语法(构造函数)
- 从内存角度看C函数的调用过程
- 【C++】拷贝构造函数
- C++:拷贝构造函数
- c++"拷贝构造函数
- C++: 拷贝构造函数
- 【C++】拷贝构造函数
- c++::拷贝构造函数
- 【C++】:拷贝构造函数
- 【C++】拷贝构造函数
- C++:拷贝构造函数
- 从一道面试题看深拷贝、浅拷贝构造函数问题 (经典)
- 编译器角度看C++复制构造函数
- 拷贝构造函数应用分析
- Google技术知多少
- 电子书下载:MySQL Stored Procedure Programming
- TI多媒体高性能处理器omap,am,dm的TRM的最新缩写词
- jsp指令与脚本元素
- 数据结构 学习笔记之:顺序栈的C语言实现
- 从逆向分析角度看C++拷贝构造函数
- 【PHP】列数字之碰到break
- 有哪几种情况只能用intialization list 而不能用assignment
- 有害的健康生活习惯
- 使用 OpenCL.Net 进行 C# GPU 并行编程
- Appserv安装图解教程(PHP)
- C#程序执行EXE文件
- java中的sizeof
- Linux C 面向连接的网络服务器端实现