虚继承构造函数的组装
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,并且在这种情况下不需要确定正确偏移量的额外代码。
这是使用虚拟基 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,并且在这种情况下不需要确定正确偏移量的额外代码。