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

 

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

 

 

 

 

参考链接:

https://www.jianshu.com/p/3e89d834df85

assembly - What does mov eax, dword ptr [eax] do? - Stack Overflow

 

 
上一篇:刷题总结(9.30)


下一篇:RHEL & Ubuntu Install Root Certificates