c++虚函数表汇编及内存布局分析(基于visual studio 2019)(五)多继承虚函数内存分布

原始代码

namespace test3
{
class Base1
{
public:
    virtual void e() { std::cout << "e" << std::endl; }
    virtual void f() { std::cout << "f" << std::endl; }
    virtual void g() { std::cout << "g" << std::endl; }
    int b1;
};

class Base2
{
public:
    virtual void h() { std::cout << "h" << std::endl; }
    virtual void i() { std::cout << "i" << std::endl; }
    int b2;
};

class Derive : public Base1, public Base2  // 多继承
{
public:
    int d1;
};

int main()
{
    Derive d;
    int i = 100;
    Base2* b2 = &d;

    b2->h();

    std::cout << sizeof(Base1) <<" " << sizeof(Base2)<<" " << sizeof(Derive) << std::endl;  // 8(1个int+1个虚函数表指针) 8(同上)  20(8+8+1个int  Derive中有2个虚函数表
    return 0;
}
/*
虚函数表定义在虚函数出现的类里

class test3::Base1      size(8):
        +---
 0      | {vfptr}
 4      | b1
        +---

test3::Base1::$vftable@:
        | &Base1_meta
        |  0
 0      | &test3::Base1::e
 1      | &test3::Base1::f
 2      | &test3::Base1::g

test3::Base1::e this adjustor: 0
test3::Base1::f this adjustor: 0
test3::Base1::g this adjustor: 0

class test3::Base2      size(8):
        +---
 0      | {vfptr}
 4      | b2
        +---

test3::Base2::$vftable@:
        | &Base2_meta
        |  0
 0      | &test3::Base2::h
 1      | &test3::Base2::i

test3::Base2::h this adjustor: 0
test3::Base2::i this adjustor: 0

Derive中包含的虚函数表指针分布在其继承的Base1和Base2内存布局里

class test3::Derive     size(20):
        +---
 0      | +--- (base class test3::Base1)
 0      | | {vfptr}
 4      | | b1
        | +---
 8      | +--- (base class test3::Base2)
 8      | | {vfptr}
12      | | b2
        | +---
16      | d1
        +---

test3::Derive::$vftable@Base1@:
        | &Derive_meta
        |  0
 0      | &test3::Base1::e
 1      | &test3::Base1::f
 2      | &test3::Base1::g


 test3::Derive::$vftable@Base2@:
        | -8   应该表示虚函数表指针距离Derive起始位置的距离
 0      | &test3::Base2::h
 1      | &test3::Base2::i


*/
}

 

汇编代码分析

Derive d;
0020351F  lea         ecx,[d]  
00203522  call        test3::Derive::Derive (02013C0h)  
    int i = 100;
00203527  mov         dword ptr [i],64h  
    Base2* b2 = &d;
0020352E  lea         eax,[d]  
00203531  test        eax,eax  
00203533  je          __$EncStackInitStart+47h (0203543h)  
00203535  lea         ecx,[d]  
00203538  add         ecx,8  
0020353B  mov         dword ptr [ebp-0FCh],ecx  
00203541  jmp         __$EncStackInitStart+51h (020354Dh)  
00203543  mov         dword ptr [ebp-0FCh],0  
0020354D  mov         edx,dword ptr [ebp-0FCh]  在栈中找到d对象中Base2部分的起始地址,然后赋值给b2
00203553  mov         dword ptr [b2],edx  

    b2->h();
00203556  mov         eax,dword ptr [b2]  拿到虚函数表地址
00203559  mov         edx,dword ptr [eax]  
0020355B  mov         esi,esp  
0020355D  mov         ecx,dword ptr [b2]  ecx中保存b2的起始位置,进入h函数后赋值给this指针
00203560  mov         eax,dword ptr [edx]  准备调用虚函数表
00203562  call        eax  
00203564  cmp         esi,esp  
00203566  call        __RTC_CheckEsp (020133Eh)  

 

posted @ 2021-11-02 14:16  AdamTang  阅读(62)  评论(0编辑  收藏  举报