c++虚继承汇编及内存布局分析(基于visual studio 2019)
作者:互联网
汇编指令说明:
1
LEA 取有效地址指令 (Load Effective Address )
指令格式:LEA 目的,源
指令功能:取源操作数地址的偏移量,并把它传送到目的操作数所在的单元。
LEA 指令要求原操作数必须是存储单元,而且目的操作数必须是一个除段寄存器之外的16位或32位寄存器。当目的操作数是16位通用寄存器时,那么只装入有效地址的低16位。使用时要注意它与MOV指令的区别,MOV指令传送的一般是源操作数中的内容而不是地址。
2
mov eax, dword ptr [eax]
dword ptr is a size directive that indicates the size of what is being moved
You're loading from memory, as indicated by the []
"contents-of" characters.
It loads eax
with the contents of memory (a 32-bit dword
in this case) that is currently pointed to by eax
.
Perhaps a graphical picture would help:
Before:
eax: 0x12345678
memory @ 0x12345678: 0xffffffff
After:
eax: 0xffffffff (eax存储的内容变为0xffffffff)
memory @ 0x12345678: 0xffffffff
源代码说明:
1 #include <iostream> 2 3 class Base1 4 { 5 public: 6 //Base1() 7 //{ 8 // b1 = 1; 9 //} 10 int b1; 11 }; 12 13 class Base2: virtual public Base1 14 { 15 public: 16 //Base2() 17 //{ 18 // b2 = 2; 19 //} 20 int b2; 21 }; 22 23 class Base3 : virtual public Base1 24 { 25 public: 26 //Base3() 27 //{ 28 // b3 = 3; 29 //} 30 int b3; 31 }; 32 33 class Derive : public Base2, public Base3 34 { 35 public: 36 //Derive() 37 //{ 38 // d = 4; 39 //} 40 int d; 41 }; 42 43 int main() 44 { 45 Base2 b2; 46 b2.b1 = 0xff; 47 48 Derive d; 49 50 std::cout << sizeof(d) << std::endl; // 4*4 + 2*4 = 24 4个int和2个虚基类表(Base2 和 Base3去掉virtual后此处变成20) 51 return 0; 52 } 53 54 /* 55 56 报告Derive类的类结构 57 58 cl /d1 reportSingleClassLayoutDerive object_book_004_菱形继承.cpp 59 60 用于 x86 的 Microsoft (R) C/C++ 优化编译器 19.29.30037 版 61 版权所有(C) Microsoft Corporation。保留所有权利。 62 63 object_book_004_菱形继承.cpp 64 65 class Derive size(24): 66 +--- 67 0 | +--- (base class Base2) 68 0 | | {vbptr} 保存指针,指向后面的Derive::$vbtable@Base2@:位置,保存8个字节 0 20 (20表示离现在位置偏移量,偏移20后到达+--- (virtual base Base1)) 69 4 | | b2 70 | +--- 71 8 | +--- (base class Base3) 72 8 | | {vbptr} 保存指针,指向后面的Derive::$vbtable@Base3@:位置,保存8个字节 0 12 73 12 | | b3 74 | +--- 75 16 | d 76 +--- 77 +--- (virtual base Base1) 78 20 | b1 79 +--- 80 81 Derive::$vbtable@Base2@: 82 0 | 0 83 1 | 20 (Derived(Base2+0)Base1) 84 85 Derive::$vbtable@Base3@: 86 0 | 0 87 1 | 12 (Derived(Base3+0)Base1) 88 vbi: class offset o.vbptr o.vbte fVtorDisp 89 Base1 20 0 4 0 90 91 */
汇编代码:
ctrl+alt+D 反汇编窗口 (调试中可用)Base2 b2;
00D94C3F push 1
00D94C41 lea ecx,[b2] // ecs存储了b2的首地址 (008ffc84)
00D94C44 call Base1::Base1 (0D9124Eh) // 调用Base1的默认构造函数(编译器自行生成的默认构造函数)
b2.b1 = 0xff;
00D94C49 mov eax,dword ptr [b2] // 将b2中的前4个字节的值 00D97B30 赋值给 eax寄存器
00D94C4C mov ecx,dword ptr [eax+4] // 将00D97B30 + 4 指向的值赋值给ecx (此值为00000008,表示虚基类的偏移量距离b2首地址为8)
00D94C4F mov dword ptr b2[ecx],0FFh // 将ff赋值给b2+ecx指向的内容
Base1的默认构造函数
Project4.exe!Base2::Base2(void):
00D91850 push ebp
00D91851 mov ebp,esp
00D91853 sub esp,0CCh
00D91859 push ebx
00D9185A push esi
00D9185B push edi
00D9185C mov dword ptr [this],ecx // 将ecx中的b2首地址的值赋值给this指针([this] 表示this保存的内容,及对象首地址 )
00D9185F cmp dword ptr [ebp+8],0
00D91863 je Base2::Base2+1Eh (0D9186Eh)
00D91865 mov eax,dword ptr [this] // this指针的值赋值给eax
00D91868 mov dword ptr [eax],offset Base2::`vbtable' (0D97B30h) // 将虚基类表的地址赋值给this指向的前4个字节,可以看到下图为开始 30 7b d9 00 与此处的0D97B30h一致
00D9186E mov eax,dword ptr [this]
00D91871 pop edi
00D91872 pop esi
00D91873 pop ebx
00D91874 mov esp,ebp
00D91876 pop ebp
00D91877 ret 4
00D9187A int 3
00D9187B int 3
.... 重复int3
参考链接:
https://www.jianshu.com/p/3e89d834df85
assembly - What does mov eax, dword ptr [eax] do? - Stack Overflow
标签:Base2,mov,c++,eax,visual,studio,b2,dword,ptr 来源: https://www.cnblogs.com/AdamTang/p/15355780.html