c++虚继承汇编及内存布局分析(基于visual studio 2019)(三)

同时存在虚继承和虚函数

namespace test3  // 加入虚函数
{
    class Grand1
    {
    public:
        virtual int G1Show(int param)
        {
            int res = param;
            return res;
        }
        int g1;
    };

    class Base1 : virtual public Grand1
    {
    public:
        int b1;
    };

    class Base2 : virtual public Grand1
    {
    public:
        int b2;
    };

    class Derive : public Base1, public Base2
    {
    public:
        int d;
    };

    int main()
    {
        Derive d1;

        std::cout << sizeof(Base1) << " " << sizeof(Base2) << " " << sizeof(Derive) << std::endl;  // 16(2个int+1个虚基类表指针+1个虚函数表指针)  16(2个int+1个虚基类表指针+1个虚函数表指针)  28(4个int+1个虚基类表指针+1个虚函数表指针)
        return 0;
    }

    /*
    
    class test3::Derive     size(28):
        +---
 0      | +--- (base class test3::Base1)
 0      | | {vbptr}
 4      | | b1
        | +---
 8      | +--- (base class test3::Base2)
 8      | | {vbptr}
12      | | b2
        | +---
16      | d
        +---
        +--- (virtual base test3::Grand1)
20      | {vfptr}  虚函数表所在位置
24      | g1
        +---

test3::Derive::$vbtable@Base1@:
 0      | 0
 1      | 20 (Derived(Base1+0)Grand1)

test3::Derive::$vbtable@Base2@:
 0      | 0
 1      | 12 (Derived(Base2+0)Grand1)

test3::Derive::$vftable@:
        | -20
 0      | &test3::Grand1::G1Show
vbi:       class  offset o.vbptr  o.vbte fVtorDisp
   test3::Grand1      20       0       4 0

    */

}

int main()
{
    test3::main();
}

 

汇编代码:

        Derive d1;  d1的地址 00AFFB9C
00F82C1F  push        1  
00F82C21  lea         ecx,[d1]  
00F82C24  call        test3::Derive::Derive (0F8132Fh)    进入构造函数的汇编代码进行分析

 

 

Project4.exe!test3::Derive::Derive(void):
00F821F0  push        ebp  
00F821F1  mov         ebp,esp  
00F821F3  sub         esp,0CCh  
00F821F9  push        ebx  
00F821FA  push        esi  
00F821FB  push        edi  
00F821FC  push        ecx  
00F821FD  lea         edi,[ebp-0Ch]  
00F82200  mov         ecx,3  
00F82205  mov         eax,0CCCCCCCCh  
00F8220A  rep stos    dword ptr es:[edi]  
00F8220C  pop         ecx  
00F8220D  mov         dword ptr [this],ecx  
00F82210  cmp         dword ptr [ebp+8],0  
00F82214  je          __$EncStackInitStart+37h (0F82234h)  此处没有跳转,上一句[ebp+8]不等于0 
00F82216  mov         eax,dword ptr [this]  
00F82219  mov         dword ptr [eax],offset test3::Derive::`vbtable' (0F89BB8h)   虚基类表1指针进行保存到对象内起始位置
00F8221F  mov         eax,dword ptr [this]  
00F82222  mov         dword ptr [eax+8],offset test3::Derive::`vbtable' (0F89BC4h)  虚基类表2指针进行保存到对象内起始位置后8个字节处
00F82229  mov         ecx,dword ptr [this]  
00F8222C  add         ecx,14h  
00F8222F  call        test3::Grand1::Grand1 (0F81460h)  跳转到虚基类Grand1的构造函数进行分析
00F82234  push        0  
00F82236  mov         ecx,dword ptr [this]  
00F82239  call        test3::Base1::Base1 (0F811EAh)  跳转到Base1构造函数进行分析
00F8223E  push        0  
00F82240  mov         ecx,dword ptr [this]  
00F82243  add         ecx,8  
00F82246  call        test3::Base2::Base2 (0F81280h)  Base2构造函数类似Base1
00F8224B  mov         eax,dword ptr [this]  
00F8224E  mov         ecx,dword ptr [eax]  
00F82250  mov         edx,dword ptr [ecx+4]  
00F82253  mov         eax,dword ptr [this]  
00F82256  mov         dword ptr [eax+edx],offset test3::Derive::`vftable' (0F89BB0h)  虚函数表
00F8225D  mov         eax,dword ptr [this]  
00F82260  pop         edi  
00F82261  pop         esi  
00F82262  pop         ebx  
00F82263  add         esp,0CCh  
00F82269  cmp         ebp,esp  
00F8226B  call        __RTC_CheckEsp (0F812BCh)  
00F82270  mov         esp,ebp  
00F82272  pop         ebp  
00F82273  ret         4  
00F82276  int         3  
00F82277  int         3  
00F82278  int         3  
00F82279  int         3  

 

 

Project4.exe!test3::Grand1::Grand1(void):
00F822A0  push        ebp  
00F822A1  mov         ebp,esp  
00F822A3  sub         esp,0CCh  
00F822A9  push        ebx  
00F822AA  push        esi  
00F822AB  push        edi  
00F822AC  mov         dword ptr [this],ecx  
00F822AF  mov         eax,dword ptr [this]  
00F822B2  mov         dword ptr [eax],offset test3::Grand1::`vftable' (0F89B74h)  虚函数表赋值
00F822B8  mov         eax,dword ptr [this]  
00F822BB  pop         edi  
00F822BC  pop         esi  
00F822BD  pop         ebx  
00F822BE  mov         esp,ebp  
00F822C0  pop         ebp  
00F822C1  ret  
00F822C2  int         3  
00F822C3  int         3  

 

Project4.exe!test3::Base1::Base1(void):
00F81FE0  push        ebp  
00F81FE1  mov         ebp,esp  
00F81FE3  sub         esp,0CCh  
00F81FE9  push        ebx  
00F81FEA  push        esi  
00F81FEB  push        edi  
00F81FEC  push        ecx  
00F81FED  lea         edi,[ebp-0Ch]  
00F81FF0  mov         ecx,3  
00F81FF5  mov         eax,0CCCCCCCCh  
00F81FFA  rep stos    dword ptr es:[edi]  
00F81FFC  pop         ecx  
00F81FFD  mov         dword ptr [this],ecx  
00F82000  cmp         dword ptr [ebp+8],0  
00F82004  je          __$EncStackInitStart+2Dh (0F8201Ah)  je跳转指令,[ebp+8]==0,会跳转到00F8201A,黄色部分不会执行,已经在Derive的构造函数中执行过了
00F82006  mov         eax,dword ptr [this]  
00F82009  mov         dword ptr [eax],offset test3::Base1::`vbtable' (0F89B88h)  
00F8200F  mov         ecx,dword ptr [this]  
00F82012  add         ecx,8  
00F82015  call        test3::Grand1::Grand1 (0F81460h)  
00F8201A  mov         eax,dword ptr [this]  
00F8201D  mov         ecx,dword ptr [eax]  
00F8201F  mov         edx,dword ptr [ecx+4]  
00F82022  mov         eax,dword ptr [this]  
00F82025  mov         dword ptr [eax+edx],offset test3::Base1::`vftable' (0F89B80h)  
00F8202C  mov         eax,dword ptr [this]  
00F8202F  pop         edi  
00F82030  pop         esi  
00F82031  pop         ebx  
00F82032  add         esp,0CCh  
00F82038  cmp         ebp,esp  
00F8203A  call        __RTC_CheckEsp (0F812BCh)  
00F8203F  mov         esp,ebp  
00F82041  pop         ebp  
00F82042  ret         4  
00F82045  int         3  
00F82046  int         3  
00F82047  int         3  

 

 

Derive d1对象起始地址为00affb9c, 00f89bb8为虚基类表1, 00f89bc4为虚基类表2, 00f86bb0为虚函数表

 

posted @ 2021-10-12 13:41  AdamTang  阅读(116)  评论(0编辑  收藏  举报