c ++的构造函数和析构函数汇编[重复]
Posted
技术标签:
【中文标题】c ++的构造函数和析构函数汇编[重复]【英文标题】:Constructor and destructor assembly of c++ [duplicate] 【发布时间】:2013-11-25 18:37:24 【问题描述】:c++ 代码
#include <cstdio>
#include <cstdlib>
struct trivialStruct
trivialStruct();
~trivialStruct();
int *a;
float *b;
float *c;
;
trivialStruct::trivialStruct() : a((int*)malloc(sizeof(int))), b((float*)malloc(sizeof(float))), c((float*)malloc(sizeof(float)))
*a = 100;
*b = 200;
*c = 300;
trivialStruct::~trivialStruct()
free(a);
free(b);
free(c);
a = nullptr;
b = nullptr;
c = nullptr;
int main()
trivialStruct A;
printf("%d, %f, %f", *A.a, *A.b, *A.c);
return 0;
组装
.section __TEXT,__text,regular,pure_instructions
.globl __ZN13trivialStructC1Ev
.align 4, 0x90
__ZN13trivialStructC1Ev: ## @_ZN13trivialStructC1Ev
.cfi_startproc
## BB#0: ## %entry
push RBP
Ltmp3:
.cfi_def_cfa_offset 16
Ltmp4:
.cfi_offset rbp, -16
mov RBP, RSP
Ltmp5:
.cfi_def_cfa_register rbp
push R15
push R14
push RBX
push RAX
Ltmp6:
.cfi_offset rbx, -40
Ltmp7:
.cfi_offset r14, -32
Ltmp8:
.cfi_offset r15, -24
mov RBX, RDI
mov EDI, 4
call _malloc
mov R14, RAX
mov QWORD PTR [RBX], R14
mov EDI, 4
call _malloc
mov R15, RAX
mov QWORD PTR [RBX + 8], R15
mov EDI, 4
call _malloc
mov QWORD PTR [RBX + 16], RAX
mov DWORD PTR [R14], 100
mov DWORD PTR [R15], 1128792064
mov DWORD PTR [RAX], 1133903872
add RSP, 8
pop RBX
pop R14
pop R15
pop RBP
ret
.cfi_endproc
.globl __ZN13trivialStructC2Ev
.align 4, 0x90
__ZN13trivialStructC2Ev: ## @_ZN13trivialStructC2Ev
.cfi_startproc
## BB#0: ## %entry
push RBP
Ltmp12:
.cfi_def_cfa_offset 16
Ltmp13:
.cfi_offset rbp, -16
mov RBP, RSP
Ltmp14:
.cfi_def_cfa_register rbp
push R15
push R14
push RBX
push RAX
Ltmp15:
.cfi_offset rbx, -40
Ltmp16:
.cfi_offset r14, -32
Ltmp17:
.cfi_offset r15, -24
mov RBX, RDI
mov EDI, 4
call _malloc
mov R14, RAX
mov QWORD PTR [RBX], R14
mov EDI, 4
call _malloc
mov R15, RAX
mov QWORD PTR [RBX + 8], R15
mov EDI, 4
call _malloc
mov QWORD PTR [RBX + 16], RAX
mov DWORD PTR [R14], 100
mov DWORD PTR [R15], 1128792064
mov DWORD PTR [RAX], 1133903872
add RSP, 8
pop RBX
pop R14
pop R15
pop RBP
ret
.cfi_endproc
.globl __ZN13trivialStructD1Ev
.align 4, 0x90
__ZN13trivialStructD1Ev: ## @_ZN13trivialStructD1Ev
.cfi_startproc
## BB#0: ## %entry
push RBP
Ltmp21:
.cfi_def_cfa_offset 16
Ltmp22:
.cfi_offset rbp, -16
mov RBP, RSP
Ltmp23:
.cfi_def_cfa_register rbp
push RBX
push RAX
Ltmp24:
.cfi_offset rbx, -24
mov RBX, RDI
mov RDI, QWORD PTR [RBX]
call _free
mov RDI, QWORD PTR [RBX + 8]
call _free
mov RDI, QWORD PTR [RBX + 16]
call _free
mov QWORD PTR [RBX + 16], 0
mov QWORD PTR [RBX + 8], 0
mov QWORD PTR [RBX], 0
add RSP, 8
pop RBX
pop RBP
ret
.cfi_endproc
.globl __ZN13trivialStructD2Ev
.align 4, 0x90
__ZN13trivialStructD2Ev: ## @_ZN13trivialStructD2Ev
.cfi_startproc
## BB#0: ## %entry
push RBP
Ltmp28:
.cfi_def_cfa_offset 16
Ltmp29:
.cfi_offset rbp, -16
mov RBP, RSP
Ltmp30:
.cfi_def_cfa_register rbp
push RBX
push RAX
Ltmp31:
.cfi_offset rbx, -24
mov RBX, RDI
mov RDI, QWORD PTR [RBX]
call _free
mov RDI, QWORD PTR [RBX + 8]
call _free
mov RDI, QWORD PTR [RBX + 16]
call _free
mov QWORD PTR [RBX + 16], 0
mov QWORD PTR [RBX + 8], 0
mov QWORD PTR [RBX], 0
add RSP, 8
pop RBX
pop RBP
ret
.cfi_endproc
.section __TEXT,__literal8,8byte_literals
.align 3
LCPI4_0:
.quad 4641240890982006784 ## double 200
LCPI4_1:
.quad 4643985272004935680 ## double 300
.section __TEXT,__text,regular,pure_instructions
.globl _main
.align 4, 0x90
_main: ## @main
.cfi_startproc
## BB#0: ## %entry
push RBP
Ltmp34:
.cfi_def_cfa_offset 16
Ltmp35:
.cfi_offset rbp, -16
mov RBP, RSP
Ltmp36:
.cfi_def_cfa_register rbp
lea RDI, QWORD PTR [RIP + L_.str]
movsd XMM0, QWORD PTR [RIP + LCPI4_0]
movsd XMM1, QWORD PTR [RIP + LCPI4_1]
mov ESI, 100
mov AL, 2
call _printf
xor EAX, EAX
pop RBP
ret
.cfi_endproc
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "%d, %f, %f"
.subsections_via_symbols
命令 clang++ -S -O2 -std=c++11 -mllvm --x86-asm-syntax=intel -fno-exceptions main.cpp
如你所见,有两部分代码是相同的(构造函数和析构函数)
-
__ZN13trivialStructC1Ev: ## @_ZN13trivialStructC1Ev
__ZN13trivialStructC2Ev: ## @_ZN13trivialStructC2Ev
__ZN13trivialStructD1Ev: ## @_ZN13trivialStructD1Ev
__ZN13trivialStructD2Ev: ## @_ZN13trivialStructD2Ev
我不知道为什么编译器会生成两部分代码,而不仅仅是一部分? 我不熟悉汇编,但看起来这只是让代码变成 更胖(也许更慢)。
【问题讨论】:
尝试优化代码的大小(将-Os
传递给g++)。此外,更少的代码并不总是更好 - 分支可能非常昂贵。
请注意,代码不会变慢。如果不使用构造函数,链接器可能会删除符号(阅读链接器的文档),即使它们没有被删除,它们也会占用内存中的一些空间,但永远不会被评估(即不会导致其他代码被逐出缓存)。
【参考方案1】:
这是您平台的 ABI 的一部分,并且超出了标准。构造函数和析构函数都可以在二进制文件中生成多个符号。例如,Itanium C++ABI 将生成最多 3 个构造函数/析构函数:
完整的对象构造函数 基础对象构造函数 完整的对象分配构造函数 删除析构函数 完整的对象析构函数 基础对象析构函数不同的符号承担的职责略有不同,因为实现可能需要根据对象的创建/销毁方式执行不同的操作。在您的特定情况下,代码非常简单,所有构造函数都可能生成完全相同的代码,但它们需要存在以符合 ABI,并且 ABI 具有它们以支持更复杂的用例。
例如,一个完整的对象构造函数会初始化虚基,而基对象构造函数会跳过这部分构造。如果存在多重/虚拟继承和虚函数,则完整对象中的 vptr 可能必须根据子对象的实例化方式来跳过不同的中间表集。
如果您想要ABI 要求以外的其他解释,您应该查看特定 ABI 的文档。您还可以查看C++ 对象模型的内部,即使它是旧的,也包含对要解决的问题和提供的一些解决方案的良好描述。
【讨论】:
以上是关于c ++的构造函数和析构函数汇编[重复]的主要内容,如果未能解决你的问题,请参考以下文章