Today there are c ++ programs:
Class ca
{
Public:
CA (INT n1 = 0): _ N1 (N1 ){}
Virtual void vf1 (){}
PRIVATE:
Int _ N1;
};
Class casub: CA
{
Public:
Casub (INT n1 = 0, int n2 = 1): Ca (N1), _ N2 (N2 ){}
Virtual void vf1 (){}
Virtual void VF2 (){}
PRIVATE:
Int _ N2;
};
Int main (INT argc, char * argv [])
{
Casub; // set the breakpoint followed by Goto Analysis 1:
Casub-> vf1 (); // set the breakpoint and inbound here, Goto Analysis 2:
Casub * pcasub = new casub;
Pcasub-> vf1 (); // set the breakpoint and inbound, Goto Analysis 3
Pcasub-> VF2 (); // set the breakpoint and inbound here, Goto Analysis 3
Return 0;
}
Vc6.0 disassembly is as follows (various compiler details may be different, but the methods should be similar ):
========================================================== =========== Analysis 1: (constructor Analysis)
... // Main Function
00401068 Push 1; press the parameter from right to left, the legendary _ stdcall method?
0040106a push 0
00401_c Lea ECx, [ebp-0Ch]; The Legend of this pointer
00400000f call @ ILT + 10 (casub: casub) (0040100f); Call Constructor
...
... // Casub Constructor
004010a0 push EBP
004010a1 mov EBP, ESP
004010a3 sub ESP, 44 h
004010a6 push EBX
004010a7 push ESI
004010a8 push EDI
004010a9 push ECx
004010aa Lea EDI, [ebp-44h]
004010ad mov ECx, 11 h
004010b2 mov eax, 0 cccccccch
004010b7 rep STOs dword ptr [EDI]
// For the analysis above, see the previous article.
004010b9 pop ECx
004010ba mov dword ptr [ebp-4], ECx; this pointer is stored in the first position of the temporary zone in the stack
004010bd mov eax, dword ptr [EBP + 8]; take the N1 parameter. Note that there is a four-byte return address between EBP and N1.
004010c0 push eax
004010c1 mov ECx, dword ptr [ebp-4]
004010c4 call @ ILT + 25 (CA: Ca) (0040101e); N1 is pushed into the stack again, and the constructor of the base class CA is called (this pointer is the same)
004010c9 mov ECx, dword ptr [ebp-4]
004010cc mov edX, dword ptr [EBP + 0ch]; Take parameter N2
004010cf mov dword ptr [ECx + 8], EDX; initialize the N2 parameter of casub (because the virtual function table pointer occupies 4 bytes starting with this + 8)
004010d2 mov eax, dword ptr [ebp-4]
004010d5 mov dword ptr [eax], offset casub: 'vftable' (0041f01c); initial virtual function table pointer
// The following sections do not analyze the value
004010db mov eax, dword ptr [ebp-4]
004010de pop EDI
004010df pop ESI
004010e0 pop EBX
004010e1 add ESP, 44 h
004010e4 cmp ebp, ESP
004010e6 call _ chkesp (004011f0)
004010eb mov ESP, EBP
004010ed pop EBP
004010ee RET 8
...
========================================================== ============ Analysis 2: (How do class objects call virtual functions)
; Casub. vf1 ();
00401089 Lea ECx, [ebp-18h]
00401_c call @ ILT + 15 (casub: vf1) (00401014)
// The assembly code above shows that there is no dynamic binding. The Compiler directly calls the vf1 function address of the casub class.
========================================================== ============ Analysis 3: (How do class pointer objects call virtual functions)
; Pcasub-> vf1 ();
004010d6 mov edX, dword ptr [ebp-1Ch]; pacsub into edX
004010d9 mov eax, dword ptr [edX]; pacsub virtual function table pointer into eaxp [that is, the virtual table entry address]
004010db mov ESI, esp;
004010dd mov ECx, dword ptr [ebp-1Ch]; this pointer (pacsub)
004010e0 call dword ptr [eax]; here it is interpreted as [eax + 0] Because vf1 contains 1st items in the table.
...
; Pcasub-> VF2 ();
004010d6 mov edX, dword ptr [ebp-1Ch]
004010d9 mov eax, dword ptr [edX]
004010db mov ESI, ESP
004010dd mov ECx, dword ptr [ebp-1Ch]
004010e0 call dword ptr [eax + 4]; 2nd items in VF2 table