1回顶部 为了搞清楚VC中类的实现专门写了一个最简单的类,用来观察它的实现过程,代码如下:
2回顶部 CTest::~CTest() { } void CTest::b() { printf("b is be called by a"); } void CTest::a(int one,int two) { printf("call b"); b(); } 下面是相应的反汇编代码: --- D:\myown\test\test.cpp ------------ 1: // test.cpp : Defines the entry point for the console application. 2: // 3: 4: #include "stdafx.h" 5: #include "CTest.h" 6: 7: int main(int argc, char* argv[]) 8: { 00401050 push ebp 00401051 mov ebp,esp 00401053 push 0FFh 00401055 push offset __ehhandler$_main (00410c89) 0040105A mov eax,fs:[00000000] 00401060 push eax 00401061 mov dword ptr fs:[0],esp 00401068 sub esp,48h 0040106B push ebx 0040106C push esi 0040106D push edi 0040106E lea edi,[ebp-54h] 00401071 mov ecx,12h 00401076 mov eax,0CCCCCCCCh 0040107B rep stos dword ptr [edi] 9: CTest aTest; 0040107D lea ecx,[ebp-10h] //这是用来保存aTest的this指针,因为是局部变量所以是保存在[ebp-10h]中 00401080 call @ILT+30(CTest::CTest) (00401023) //调用aTest的构造函数,由编译器自动产生的CALL 00401085 mov dword ptr [ebp-4],0 10: aTest.a(1,2); 0040108C push 2 0040108E push 1 00401090 lea ecx,[ebp-10h] //把aTest的this指针用ecx进行传递 00401093 call @ILT+5(CTest::a) (0040100a) 11: return 0; 3回顶部 00401098 mov dword ptr [ebp-14h],0 0040109F mov dword ptr [ebp-4],0FFFFFFFFh 004010A6 lea ecx,[ebp-10h] //同样是this指针 004010A9 call @ILT+25(CTest::~CTest) (0040101e) //aTest的生存周期到了,自动调用析构函数,同样是由编译器分析之后自加上去 004010AE mov eax,dword ptr [ebp-14h] 12: } 004010B1 mov ecx,dword ptr [ebp-0Ch] 004010B4 mov dword ptr fs:[0],ecx 004010BB pop edi 004010BC pop esi 004010BD pop ebx 004010BE add esp,54h 004010C1 cmp ebp,esp 004010C3 call __chkesp (00401670) 004010C8 mov esp,ebp 004010CA pop ebp 004010CB ret 下面再来分析一下VC中对函数的调用: 可以看到上面有对三个函数的调用分别为: 00401080 call @ILT+30(CTest::CTest) (00401023) 00401093 call @ILT+5(CTest::a) (0040100a) 004010A9 call @ILT+25(CTest::~CTest) (0040101e) 可以看到他们都跳到了以@ILT为基的一个地址去了,那么跳过去之后可以看到: @ILT+0(??_GCTest@@UAEPAXI@Z): 00401005 jmp CTest::`scalar deleting destructor' (00401130) @ILT+5(?a@CTest@@QAEXHH@Z): 0040100A jmp CTest::a (00401230) @ILT+10(_main): 0040100F jmp main (00401050) @ILT+15(?b@CTest@@QAEXXZ): 00401014 jmp CTest::b (004011e0) @ILT+20(??_GCTest@@UAEPAXI@Z): 00401019 jmp CTest::`scalar deleting destructor' (00401130) @ILT+25(??1CTest@@UAE@XZ): 0040101E jmp CTest::~CTest (004011a0) @ILT+30(??0CTest@@QAE@XZ): 00401023 jmp CTest::CTest (004010f0) 这个@ILT其实就是一个静态的表,它记录了一些函数的入口然后跳过去,每个跳转jmp占一个字节,然后就是一个四字节的内存地址,所以加起为五个字节,这样就实现了类的机制。 下面再来分析一下,类的成员函数调用另一成员函数的情况: 27: void CTest::a(int one,int two) 4回顶部 28: { 00401230 push ebp 00401231 mov ebp,esp 00401233 sub esp,44h 00401236 push ebx 00401237 push esi 00401238 push edi 00401239 push ecx 0040123A lea edi,[ebp-44h] 0040123D mov ecx,11h 00401242 mov eax,0CCCCCCCCh 00401247 rep stos dword ptr [edi] 00401249 pop ecx 0040124A mov dword ptr [ebp-4],ecx 29: printf("call b"); 0040124D push offset string "call b" (00422038) 00401252 call printf (00401830) 00401257 add esp,4 30: b(); 0040125A mov ecx,dword ptr [ebp-4] //不要想这里的[ebp-4]肯定是this指针, 0040125D call @ILT+15(CTest::b) (00401014) // 又是@ILT静态表格 31: } 00401262 pop edi 00401263 pop esi 00401264 pop ebx 00401265 add esp,44h 00401268 cmp ebp,esp 0040126A call __chkesp (00401670) 0040126F mov esp,ebp 00401271 pop ebp 00401272 ret 8 //由于是STDCALLR所以栈是由程序自己来平衡的 |
鏀惰棌鎴愬姛鏌ョ湅鏀惰棌>>
正在阅读:C++类机制的实现细节C++类机制的实现细节
2004-04-23 10:17
出处:CSDN
责任编辑:linjixiong