Understand virtual functions from an assembly perspective!

Source: Internet
Author: User

Today, we will understand the virtual functions from the perspective of assembly.

Working environment vc6

Method debug trace memory

Although the testing program code is a testing program, I hope you will still develop good habits and do not pollute the namespace.

Test code:

# Include "iostream"
Using STD: cout;
Using STD: Endl;

Class
{
Int M_a;
Public:
A (int x): M_a (x ){}

Virtual void display ()
{
Cout <"A is running! "<Endl;
}
};

Class B: public
{
Public:
B (INT y): A (y ){}

Void display ()
{
Cout <"B is running! "<Endl;
}
};

Class C: Public B
{
Public:
C (int z): B (z ){}

Void display ()
{
Cout <"C is running! "<Endl;
}
};

Int main ()
{
A Ca (1 );
B CB (2 );
C CC (3 );

A * P [3] ={& ca, & CB, & CC };

P [0]-> display ();
P [1]-> display ();
P [2]-> display ();

Return 0;
}

You don't need to say much about the output results. If you still cannot think of the correct results, first read the basic knowledge and read this article.

Let's take a look at the generated assembly code.

39: int main ()
40 :{
004011a0 push EBP
004011a1 mov EBP, ESP
004011a3 sub ESP, 64 h
004011a6 push EBX
004011a7 push ESI
004011a8 push EDI
004011a9 Lea EDI, [ebp-64h]
004011ac mov ECx, 19 h
004011b1 mov eax, 0 cccccccch
004011b6 rep STOs dword ptr [EDI]
41: A Ca (1 );
004011b8 Push 1
004011ba Lea ECx, [ebp-8]
004011bd call @ ILT + 95 (A: a) (00401064)
42: B CB (2 );
004011c2 push 2
004011c4 Lea ECx, [ebp-10h]
004011c7 call @ ILT + 10 (B: B) (0040100f)
43: c cc (3 );
004011cc Push 3
004011ce Lea ECx, [ebp-18h]
004011d1 call @ ILT + 105 (C: C) (0040366e)
44:
45: A * P [3] ={& ca, & CB, & CC };
004011d6 Lea eax, [ebp-8]
004011d9 mov dword ptr [ebp-24h], eax
004011dc Lea ECx, [ebp-10h]
004011df mov dword ptr [ebp-20h], ECx
004011e2 Lea edX, [ebp-18h]
004011e5 mov dword ptr [ebp-1Ch], EDX
46:
47: P [0]-> display ();
004011e8 mov eax, dword ptr [ebp-24h]
004011eb mov edX, dword ptr [eax]
004011ed mov ESI, ESP
004011ef mov ECx, dword ptr [ebp-24h]
004011f2 call dword ptr [edX]
004011f4 cmp esi, ESP
004011f6 call _ chkesp (004092c0)
48: P [1]-> display ();
004011fb mov eax, dword ptr [ebp-20h]
004011fe mov edX, dword ptr [eax]
00401200 mov ESI, ESP
00401202 mov ECx, dword ptr [ebp-20h]
00401205 call dword ptr [edX]
00401207 cmp esi, ESP
00401209 call _ chkesp (004092c0)
49: P [2]-> display ();
0040120e mov eax, dword ptr [ebp-1Ch]
00401211 mov edX, dword ptr [eax]
00401213 mov ESI, ESP
00401215 mov ECx, dword ptr [ebp-1Ch]
00401218 call dword ptr [edX]
0040121a cmp esi, ESP
0040121c call _ chkesp (004092c0)
50:
51: Return 0;
00401221 XOR eax, eax

We only need to look at the important code.

41: A Ca (1 );
004011b8 Push 1
004011ba Lea ECx, [ebp-8]
004011bd call @ ILT + 95 (A: a) (00401064)

Construct a Class A object, and first press stack constant 1 as the parameter.

Assign an address in the stack to ECx. At this time, ECx is used as the this pointer to this object. The current memory is full CC ....

Call the constructor of Class A. Because it is not virtual fnction, it is a constant address of call, to a jump table.

00401064 jmp a: A (00401260)
Enter the constructor of Class.

9: A (int x): M_a (x ){}
00401260 push EBP
00401261 mov EBP, ESP
00401263 sub ESP, 44 h
00401266 push EBX
00401267 push ESI
00401268 push EDI
00401269 push ECx
0040126a Lea EDI, [ebp-44h]
0040126d mov ECx, 11 h
00401272 mov eax, 0 cccccccch
00401277 rep STOs dword ptr [EDI]
00401279 pop ECx
004020.a mov dword ptr [ebp-4], ECx
0040127d mov eax, dword ptr [ebp-4]
00401280 mov ECx, dword ptr [EBP + 8]
00401283 mov dword ptr [eax + 4], ECx
00401286 mov edX, dword ptr [ebp-4]
00401289 mov dword ptr [edX], offset a: 'vftable' (0043201c)
0040128f mov eax, dword ptr [ebp-4]
00401292 pop EDI
00401293 pop ESI
00401294 pop EBX
00401295 mov ESP, EBP
00401297 pop EBP
00401298 RET 4

Let's just look at the most important lines.

004020.a mov dword ptr [ebp-4], ECx
0040127d mov eax, dword ptr [ebp-4]
00401280 mov ECx, dword ptr [EBP + 8]
00401283 mov dword ptr [eax + 4], ECx
00401286 mov edX, dword ptr [ebp-4]
00401289 mov dword ptr [edX], offset a: 'vftable' (0043201c)
0040128f mov eax, dword ptr [ebp-4]

At this time, ECx is the this pointer of this object. This pointer is given to a variable (implemented by stack). In this case, eax is also the this pointer.

MoV ECx, dword ptr [EBP + 8]
The parameter 1 that has just been pushed into the stack is assigned to ECx.

MoV dword ptr [eax + 4], ECx
This value is assigned to the 4 bytes starting from 4 to + 8 of the thisi pointer (because it is int type, it is 4 bytes .) because Class A has virtual functions, we know that the compiler will assign the vtable address of Class A to the first four bytes of Class A objects, these four bytes are what we often call vptr, which points to the virtual table. therefore, the four bytes after the vptr are the only data member (INT) that stores the object ).

At this time, the object's memory is CC 01 00 00 00 vptr has not been assigned a value

MoV edX, dword ptr [ebp-4]
This pointer to edX

MoV dword ptr [edX], offset a: 'vftable' (0043201c)
Give the virtual table address of Class A to vptr, which is the four bytes starting with this pointer.

Eax, dword ptr [ebp-4] or give this pointer to eax I think this is a waste statement

The memory of this object is

0012ff78 1C 20 43 00 01 00 00 00 virtual table pointer data member

Class B

42: B CB (2 );
004011c2 push 2
004011c4 Lea ECx, [ebp-10h]
004011c7 call @ ILT + 10 (B: B) (0040100f)

Similarly, stack 2 is used as the parameter, and the memory of the next 8-byte space used as the class B object is found.

And enter the jump table 0040100f jmp B: B (00401310)

Go to the constructor

20: B (INT y): A (y ){}
00401310 push EBP
00401311 mov EBP, ESP
00401313 sub ESP, 44 h
00401316 push EBX
00401317 push ESI
00401318 push EDI
00401319 push ECx
0040131a Lea EDI, [ebp-44h]
0040131d mov ECx, 11 h
00401322 mov eax, 0 cccccccch
00401327 rep STOs dword ptr [EDI]
00401329 pop ECx
0040132a mov dword ptr [ebp-4], ECx
0040132d mov eax, dword ptr [EBP + 8]
00401330 push eax
00401331 mov ECx, dword ptr [ebp-4]
00401334 call @ ILT + 95 (A: a) (00401064)
00401339 mov ECx, dword ptr [ebp-4]
0040133c mov dword ptr [ECx], offset B: 'vftable' (00432034)
00401342 mov eax, dword ptr [ebp-4]
00401345 pop EDI
00401346 pop ESI
00401347 pop EBX
00401348 add ESP, 44 h
0040134b cmp ebp, ESP
0040134d call _ chkesp (004092c0)
00401352 mov ESP, EBP
00401354 pop EBP
00401355 RET 4

Let's take a look at this section.

0040132a mov dword ptr [ebp-4], ECx
0040132d mov eax, dword ptr [EBP + 8]
00401330 push eax
00401331 mov ECx, dword ptr [ebp-4]
00401334 call @ ILT + 95 (A: a) (00401064)
00401339 mov ECx, dword ptr [ebp-4]
0040133c mov dword ptr [ECx], offset B: 'vftable' (00432034)
00401342 mov eax, dword ptr [ebp-4]

ECX is the this pointer of the object.

Give parameter 2 to eax and use the eax pressure stack as the parameter to call the base class constructor. The function is the same as the above mentioned, so the object memory is

1c 20 43 00 02 00 00 00 at this time, the virtual table Pointer Points to the vtable of Class.

ECX, dword ptr [ebp-4]

Give this pointer to ECx

Dword ptr [ECx], offset B: 'vftable' (00432034)
Give the vtable address of Class B to the 4-byte (vptr) Starting with this pointer, so the current object memory is

34 20 43 00 02 00 00

 

Class C and the front side are basically the same. The last memory of this object is 4C 20 43 00 03 00 00 00

The memory of the last three objects is

4c 20 43 00 03 00 00 00 00 34 20 43 00 00 00 00 burn l c... 4 C .....
0012ff78 1C 20 43 00 01 00 00

45: A * P [3] ={& ca, & CB, & CC };
004011d6 Lea eax, [ebp-8]
004011d9 mov dword ptr [ebp-24h], eax
004011dc Lea ECx, [ebp-10h]
004011df mov dword ptr [ebp-20h], ECx
004011e2 Lea edX, [ebp-18h]
004011e5 mov dword ptr [ebp-1Ch], EDX

Assign the this pointer of three objects to an array of three 4-byte pointers.

 

 

47: P [0]-> display ();
004011e8 mov eax, dword ptr [ebp-24h]
004011eb mov edX, dword ptr [eax]
004011ed mov ESI, ESP
004011ef mov ECx, dword ptr [ebp-24h]
004011f2 call dword ptr [edX]
004011f4 cmp esi, ESP
004011f6 call _ chkesp (004092c0)
48: P [1]-> display ();
004011fb mov eax, dword ptr [ebp-20h]
004011fe mov edX, dword ptr [eax]
00401200 mov ESI, ESP
00401202 mov ECx, dword ptr [ebp-20h]
00401205 call dword ptr [edX]
00401207 cmp esi, ESP
00401209 call _ chkesp (004092c0)
49: P [2]-> display ();
0040120e mov eax, dword ptr [ebp-1Ch]
00401211 mov edX, dword ptr [eax]
00401213 mov ESI, ESP
00401215 mov ECx, dword ptr [ebp-1Ch]
00401218 call dword ptr [edX]
0040121a cmp esi, ESP
0040121c call _ chkesp (004092c0)
50:
51: Return 0;
00401221 XOR eax, eax

Here is the virtual function call. Because the virtual table is different, the function called in the output result is different.

First look

47: P [0]-> display ();
004011e8 mov eax, dword ptr [ebp-24h]
004011eb mov edX, dword ptr [eax]
004011ed mov ESI, ESP
004011ef mov ECx, dword ptr [ebp-24h]
004011f2 call dword ptr [edX]
004011f4 cmp esi, ESP
004011f6 call _ chkesp (004092c0)

Give the this pointer of the first object to eax,

MoV edX, dword ptr [eax]

The content of the four bytes starting with this pointer is given to EDX. At this time, edX is the vptr, that is, the vtable address.

MoV ECx, dword ptr [ebp-24h]

Assign this pointer to ECx

Call dword ptr [edX]

The position of the virtual function of each class in the virtual table depends on the position declared in the class. The position of no virtual function is the ID in the vtable, because the test code defines only one virtual function for each class, the 4-byte starting from the vtable indicated by EDX is called as a virtual function address.

Trace memory

0012ff78 1C 20 43 00

Tracking [eax] edX = 0043201c

Tracking [edX] 0043201c 5f 10 40 00

Trace 0040105f jmp a: Display (004012b0)

Therefore, the display () function of Class A is called.

The two subsequent calls use vtable to call virtual functions.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.