【问题标题】:Assembly of constructor for virtual inheritance虚拟继承构造函数的组装
【发布时间】:2019-08-29 15:18:13
【问题描述】:

这是一个使用虚拟基类的简单继承(编译器资源管理器上的代码 available)。

class B {
public:
    int i = 1;
};

class D : virtual public B {
public:
    int j = 2;
};

void Assign(B *b) {
    b->i = 2;
}

int main() {
    B *b = new D();
    Assign(b);
    return 0;
}

main() 函数的汇编列表如下所示:

09  main: # @main
10    push rbp
11    mov rbp, rsp
12    sub rsp, 32
13    mov eax, 16
14    mov edi, eax
15    mov dword ptr [rbp - 4], 0
16    call operator new(unsigned long)
17    xor esi, esi
18    mov ecx, 16
19    mov edx, ecx
20    mov rdi, rax
21    mov qword ptr [rbp - 24], rax # 8-byte Spill
22    call memset
23    mov rdi, qword ptr [rbp - 24] # 8-byte Reload
24    call D::D() [complete object constructor]
25    xor ecx, ecx
26    mov eax, ecx

27    mov rdx, qword ptr [rbp - 24] # 8-byte Reload
28    cmp rdx, 0
29    mov qword ptr [rbp - 32], rax # 8-byte Spill
30    je .LBB1_2
31    mov rax, qword ptr [rbp - 24] # 8-byte Reload
32    mov rcx, qword ptr [rax]
33    mov rcx, qword ptr [rcx - 24]
34    add rax, rcx
35    mov qword ptr [rbp - 32], rax # 8-byte Spill
36  .LBB1_2:
37    mov rax, qword ptr [rbp - 32] # 8-byte Reload
38    mov qword ptr [rbp - 16], rax

39    mov rdi, qword ptr [rbp - 16]
40    call Assign(B*)
41    xor eax, eax
42    add rsp, 32
43    pop rbp
44    ret

汇编第27-38行的作用是什么?

第 29 行 rax 的值是多少?

为什么会有分支语句?

【问题讨论】:

  • 你还能用-Og得到类似的代码吗? -O0 调试模式一团糟。 IDK 如果 gcc 会在 -O0 进行推测性去虚拟化,但它可能会。
  • 提示:注意“vtable for D”符号,第一个成员!
  • @curiousguy 你是什么意思?
  • @chaosink 派生类的 vtable 的第一个字段包含编译器在此处需要的信息:“vtable for D: .quad 12” 表示 base 位于 D 基类的偏移 +12 处( lax) 派生最多的对象D 中的子对象。 (在派生对象是其自身的子对象的情况下,用松散的子对象说起来更容易。)注意 vptr 不指向 vtable 的开头!按照历史惯例,vptr[0] 是第一个虚函数(如果有的话,或者虚函数数组的末尾)。偏移量为负偏移量 WRT vptr。

标签: c++ assembly constructor x86 virtual-inheritance


【解决方案1】:

第 27-38 行的作用是将D * 转换为B *。因为B 是一个虚拟基类,它可以从D 的开头有一个可变的偏移量。这 12 行以未优化的方式计算 B 对象的位置。

第 29 行 eax 的值为 0(参见第 25-26 行)。

第 30 行的分支语句是 NULL 指针检查的结果。如果指向 D 的指针为 NULL,则转换为 B * 也将为 NULL,并且在这种情况下不需要额外的代码来确定正确的偏移量。

【讨论】:

  • 如果您将D*B* 的转换拆分为单独的语句,则更容易查看。如果你把它放到一个 function 中就更容易了,这样你就可以在不删除它的情况下启用优化。 godbolt.org/z/4-deOJ
猜你喜欢
  • 2015-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-24
  • 2018-04-18
  • 2021-06-02
  • 2020-04-29
相关资源
最近更新 更多