為了搞清楚VC中類的實(shí)現(xiàn)專門寫了一個(gè)最簡(jiǎn)單的類,用來(lái)觀察它的實(shí)現(xiàn)過(guò)程,代碼如下:
// test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "CTest.h"
int main(int argc, char* argv[])
{
CTest aTest;
aTest.a(1,2);
return 0;
}
// CTest.h: interface for the CTest class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_CTEST_H__2CCCDCFC_6C3A_48BC_9CD0_E7A8E63431D9__INCLUDED_)
#define AFX_CTEST_H__2CCCDCFC_6C3A_48BC_9CD0_E7A8E63431D9__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CTest
{
public:
CTest();
virtual ~CTest();
public:
void b();
void a(int one,int two);
};
#endif // !defined(AFX_CTEST_H__2CCCDCFC_6C3A_48BC_9CD0_E7A8E63431D9__INCLUDED_)
// CTest.cpp: implementation of the CTest class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CTest.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CTest::CTest()
{
}
CTest::~CTest()
{
}
void CTest::b()
{
printf("b is be called by a");
}
void CTest::a(int one,int two)
{
printf("call b");
b();
}
下面是相應(yīng)的反匯編代碼:
--- 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] //這是用來(lái)保存aTest的this指針,因?yàn)槭蔷植孔兞克允潜4嬖赱ebp-10h]中
00401080 call @ILT+30(CTest::CTest) (00401023) //調(diào)用aTest的構(gòu)造函數(shù),由編譯器自動(dòng)產(chǎn)生的CALL
00401085 mov dword ptr [ebp-4],0
10: aTest.a(1,2);
0040108C push 2
0040108E push 1
00401090 lea ecx,[ebp-10h] //把a(bǔ)Test的this指針用ecx進(jìn)行傳遞
00401093 call @ILT+5(CTest::a) (0040100a)
11: return 0;
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的生存周期到了,自動(dòng)調(diào)用析構(gòu)函數(shù),同樣是由編譯器分析之后自加上去
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
下面再來(lái)分析一下VC中對(duì)函數(shù)的調(diào)用:
可以看到上面有對(duì)三個(gè)函數(shù)的調(diào)用分別為:
00401080 call @ILT+30(CTest::CTest) (00401023)
00401093 call @ILT+5(CTest::a) (0040100a)
004010A9 call @ILT+25(CTest::~CTest) (0040101e)
可以看到他們都跳到了以@ILT為基的一個(gè)地址去了,那么跳過(guò)去之后可以看到:
@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)
這個(gè)@ILT其實(shí)就是一個(gè)靜態(tài)的表,它記錄了一些函數(shù)的入口然后跳過(guò)去,每個(gè)跳轉(zhuǎn)jmp占一個(gè)字節(jié),然后就是一個(gè)四字節(jié)的內(nèi)存地址,所以加起為五個(gè)字節(jié),這樣就實(shí)現(xiàn)了類的機(jī)制。
下面再來(lái)分析一下,類的成員函數(shù)調(diào)用另一成員函數(shù)的情況:
27: void CTest::a(int one,int two)
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靜態(tài)表格
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所以棧是由程序自己來(lái)平衡的
只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。 | ||
![]() |
||
網(wǎng)站導(dǎo)航:
博客園
IT新聞
Chat2DB
C++博客
博問(wèn)
管理
|
||
相關(guān)文章:
|
||