c++虚继承汇编及内存布局分析(基于visual studio 2019)(二)
c++代码
namespace test2 { class Grand1 { public: int g1; }; class Grand2 { public: int g2; }; class Base1 : virtual public Grand1, public Grand2 虚继承且普通继承 { public: int b1; }; class Base2 : virtual public Grand1 { public: int b2; }; class Derive : public Base1, public Base2 { public: int d; }; int main() { Base1 b1; b1.g1 = 0x11111111; b1.g2 = 0x22222222; b1.b1 = 0x33333333; std::cout << sizeof(Base1)<<" "<<sizeof(Base2)<<" "<<sizeof(Derive) << std::endl; // 16(3个int+1个虚基类表指针) 12(2个int+1个虚基类表指针) 28(4个int+1个虚基类表指针) return 0; } /* class test2::Base1 size(16): +--- 0 | +--- (base class test2::Grand2) 0 | | g2 地址00effcb8 | +--- 4 | {vbptr} 地址00effcbc 虚基类表指针,存储的是00f89b5c 8 | b1 地址00effcc0 +--- +--- (virtual base test2::Grand1) 12 | g1 与虚基类表指针存储地址的差距为12-4=8 +--- test2::Base1::$vbtable@: 地址00f89b5c 0 | -4 虚基类表前4个字节内容,表示对象首地址与虚基类表指针首地址的差距 1 | 8 (Base1d(Base1+4)Grand1) 虚基类表5-8字节内容,表示虚基类对象地址与虚基类表指针首地址的差距 vbi: class offset o.vbptr o.vbte fVtorDisp test2::Grand1 12 4 4 0 */ } int main() { test2::main(); }
汇编代码分析:
Base1 b1; // b1的地址为0x00effcb8 00F8623F push 1 00F86241 lea ecx,[b1] 00F86244 call test2::Base1::Base1 (0F8145Bh) b1.g1 = 0x11111111; 00F86249 mov eax,dword ptr [ebp-14h] // 将虚基类指针赋值给eax寄存器,ebp为栈底指针
(类似于上一篇文章中的 00D94C49 mov eax,dword ptr [b2] // 将b2中的前4个字节的值 00D97B30 赋值给 eax寄存器) 00F8624C mov ecx,dword ptr [eax+4] 00F8624F mov dword ptr [ebp+ecx-14h],11111111h b1.g2 = 0x22222222; 00F86257 mov dword ptr [b1],22222222h \\ 说明g2位于b1对象的起始位置 b1.b1 = 0x33333333; 00F8625E mov dword ptr [ebp-10h],33333333h
虚基类表存储内容 -4 (补码fffffffc)和 8
参考链接: