This section studies the execution flow of C + + non-static member functions and virtual functions through disassembly;
The code snippet is as follows
Class Animal{public: virtual void print () { cout << "Animal::p rint" << Endl; } void Print2 () { cout << "Animal::p rint2" << Endl; }}; Class Dog:public Animal{public: Dog (): _age (1) { } virtual void print () { cout << " Dog::p rint "<< _age << Endl; } void Print2 () { cout << "Dog::p rint2" << Endl; } Private: int _age;}; int main (void) { Dog D; animal* P1 = &d; P1->print (); P1->print2 (); cout << "_age Address:" << ((int*) &d+1) << "value:" << * ((int*) &d+1) << Endl; cout << "Virtual fun address:" << (int*) &d << Endl; cout << "Virtual fun[1" Address: "<< (int*) * (int*) &d << Endl; cout << "Virtual fun[2" Address: "<< ((int*) * (int*) &d+1) << Endl; }
The output is as follows:
[Email protected]:~/desktop$./testdog::p rint 1Animal::p rint2 _age address:0xbfc5c7f8 value:1virtual Fun ADDRESS:0XBFC 5c7f4virtual fun[1] address:0x8048c30virtual fun[2] Address:0x8048c34
Explain the points:
(1) This section will only study the disassembly code for P1->print () and P1->print2 (), for the cout output portion of the Mian function, just for verification;
The virtual function table for the dog class is as follows:
The function stack frames called by print and Print2 are as follows:
Disassembly of main function
The relevant parts of print and Print2 are disassembled as follows
0804882C <main>: 804882c:8d 4c 0x4 Lea (%ESP),%ecx 8048830:83 e4 f0 and $0xfffffff0, %esp 8048833:ff FC Pushl-0x4 (%ECX) 8048836:55 push%ebp #放入ebp 8048837:89 e5 mov%esp,%ebp 8048839:53 push%ebx 804883a:51 push%ecx 804883b: $0X10,%ESP 804883e:83 EC 0c Sub $0xc,%esp 8048841:8d EC l ea-0x14 (%EBP),%eax 8048844:50 push%eax 8048845:e8 0a 8048a54 V> #调用dog的构造函数 804884a:83 C4 add $0x10,%esp 804884d:8d EC lea-0x14 (%EBP),%eax 8 048850:89 f4 mov%eax,-0xc (%EBP) #将Dog D address assigned to P1 8048853:8b, F4 mov-0xc (%EBP),%eax #取p1 8048856:8b XX mov (%eax),%eax #取virtual虚函数表的地址 8048858:8b XX mov (%e AX),%eax #取第一个虚函The function address of the number 804885a:83 EC 0c Sub $0xc,%esp 804885d:ff f4 pushl-0xc (%EBP) #将 P1 as a parameter #取0x8048c3处的内容执行, that is, the execution of the first virtual function, is actually the function address 08048a7e, that is, _zn3dog5printev function address, call dog::p rint 8048860:ff D0 *%eax 8048862:83 C4 Add $0x10,%esp 8048865:83 EC 0c Sub $0xc,%esp 8048868:ff PUSHL-0XC (%EBP) 804886b:e8 A8, call 8048a18 <_ZN6Animal6print2Ev> #调用Animal::p Rint2 804 8870:83 C4 Add $0x10,%esp 8048873:8d EC lea-0x14 (%EBP),%eax
The constructor of dog is disassembled as follows
08048a54 <_zn3dogc1ev>: 8048a54:55 push %ebp 8048a55:89 e5 mov %esp,%ebp 8048a57:83 EC Sub $0x8,%esp 8048a5a:8b mov 0x8 (%EBP),%eax #取Dog D address 8048a5d:83 EC 0c Sub $0xc,%esp 8048a60:50 push %eax 8048a61:e8 e0 FF FF call 8048a46 <_ZN6AnimalC1Ev> #调用Animal的构造函数 8048a66:83 C4 add $0x10,%esp 8048a69:8b mov 0x8 (%EBP),%eax 8048a6c:c7 8c mo VL $0x8048c30, (%eax) #Dog虚函数表地址 8048a72:8b mov 0x8 (%EBP),%eax 8048a75:c7-XX movl $0x1,0x4 (%eax) #_age为1 8048a7c:c9 leave 8048a7d:c3 ret
The animal constructor is disassembled as follows
08048a46 <_zn6animalc1ev>: 8048a46:55 push %ebp 8048a47:89 e5 mov %esp,%ebp 8048a49:8b 45 08 mov 0x8 (%EBP),%eax 8048a4c:c7 8c movl $0x8048c40 , (%eax) #Animal虚函数表地址 8048a52:5d pop %ebp 8048a53:c3 ret
The table of the dog virtual function is disassembled as follows
08048c28 <_ztv3dog>: 8048c28:00 xx add %al, (%eax) 8048c2a:00 add %al, (%eax) 8048c2c:4c Dec %esp 8048c2d:8c mov %es, (%eax,%ecx,1) 8048c30:7e 8a jle 8048BBC <_io_stdin_used+ 0x28> 8048c32:04 Add $0x8,%al 8048c34:00 add %al, (%EAX)
Explain the points:
(1) GCC uses small-end storage, so the content of 0X8048C30 at 0x08048a7e;
8048c30:7e 8a jle 8048bbc <_IO_stdin_used+0x28> 8048c32:04 add $0x8,%al small big
(2) We know that the address of the virtual function table is 0X8048C30, and print is the first function of the table of the dog virtual function, so call *%eax actually executes the address of the function 0X8048C30 address, that is, the 08048a7e address, exactly corresponding to the dog:: The function address of print;
Dog::p rint functions are disassembled as follows
08048a7e <_zn3dog5printev>: 8048a7e:55 push%ebp 8048a7f:89 e5 mov%esp,%ebp 8 048A81:53 push%ebx 8048a82:83 EC $0X4,%ESP 8048A85:8B mov 0x8 (%EBP),%eax #获得Dog D's address 8048a88:8b mov 0x4 (%eax),%EBX #此时_age的值在ebx中 8048a8b:83 EC 08 Sub $0x8,%esp 8048a8e:68 B7 8b Push $0x8048bb7 8048a93:68 push $0x8049180 #调用co UT address 8048a98:e8 1f FC FF FF call 80486BC <[email protected]> 8048a9d:83 c4 Add $0x10 ,%ESP 8048aa0:83 EC sub $0x8,%esp 8048aa3:53 push%ebx 8048aa4:50 Push%eax 8048aa5:e8 B2 FB ff FF call 804865c <[email protected]> 8048aaa:83 c4 Add $0X10,%ESP 8048aad:83 EC $0x80486ec Sub $0x8,%esp 8048ab0:68 EC (push 8048ab5:50) Push%eax8048ab6:e8 FC FF FF call 80486DC <[email protected]> 8048abb:83 c4 Add $0x10,%esp 8048ABE:8B 5d FC Mov-0x4 (%EBP),%ebx 8048ac1:c9 leave 8048AC2:C3 ret
Animal::p Rint2 functions are disassembled as follows
08048a18 <_zn6animal6print2ev>: 8048a18:55 push %ebp 8048a19:89 e5 mov %esp,%ebp 8048a1b:83 EC Sub $0x8,%esp 8048a1e:83 EC a sub $0x8,%esp 8048a21:68 A7 8b push $0x8048ba7 8048a26 : $0x8049180 8048a2b:e8 8c FC FF FF call 80486BC <[email protected]> 8048a30: C4 add $0x10,%esp 8048a33:83 EC Geneva Sub $0x8,%esp 8048a36:68 EC 0x80486ec 8048a3b:50 push %eax 8048a3c:e8 9b FC FF FF call 80486DC <[email protected]> 8048a41:83 C4 add $0x10,%esp 8048a44:c9 leave 8048a45:c3 ret
Disassembly Analysis C + + member functions and virtual functions