虚继承构造函数的组装

Assembly of constructor for virtual inheritance

这是使用虚拟基 class 的简单继承(Compiler Explorer 上的代码 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 的值是多少?

为什么会有分支语句?

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

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

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