什么是gcc名称修改中的“析构函数组”符号

时间:2013-10-21 01:41:10

标签: c++ constructor g++ destructor demangler

https://stackoverflow.com/a/6614369/1091587快速概述了在读取使用“gcc3”类型名称修改编译的程序的符号表时出现的析构函数类型(D0,D1,D2)。还有相应的构造函数C0 / C1 / C2。使用g ++ - 4.7(可能更早),会出现一个新的ctor / dtor对,即C5 / D5,但只作为调试符号。

$ cat i.cpp 
class X { public: virtual ~X() {}; };
int main(void) { X x; return 0; };
$ g++ -c i.cpp 
$ nm i.o | grep 5
0000000000000000 n _ZN1XC5Ev
0000000000000000 n _ZN1XD5Ev
$ c++filt -n _ZN1XC5Ev _ZN1XD5Ev
X::X()
X::~X()

demangler源将D5对象称为“gnu_v3_object_dtor_group”,但究竟什么是dtor组,它有什么用呢? clang ++ - 3.3不会发出它,http://gcc.gnu.org/ml/gcc-patches/2011-11/msg00383.html表明它可能与gcc中的新事务内存功能有关。

1 个答案:

答案 0 :(得分:2)

This LLVM patchthis GCC bug提供了更多背景信息。通过跟踪链接,我发现Bug 3187 - gcc lays down two copies of constructors似乎是它的全部起源:

  

两个(有时三个)相同的构造函数和析构函数副本   已经奠定了。链接器不会失败,但会生成二进制文件   比我们现实世界的例子大20%(

如果您搜索“PR c ++ / 3187”(e.g.),您可以在gcc-patches ML上找到很多讨论。基本上,C5 / D5本身不是构造函数/析构函数,而是包含两个或更多“基本”构造函数/析构函数的COMDAT group。这可以确保组中的函数全部用在最终二进制文件中,或者全部丢弃(以强制执行“一个定义规则”)。

上述错误中的讨论结果似乎是:

  

对于任何类,实现都可以选择使用一个comdat   构造函数/析构函数或使用C5 / D5 comdat。我可能会这样做   基于任何盈利标准的决定。如果使用C5 / D5 comdat   规则是

     
      
  • C5 comdat必须有C1和C2。
  •   
  • 如果一个类有一个虚拟析构函数,那么D5 comdat必须有D0,D1和D2
  •   
  • 如果类具有非虚拟析构函数,则D5 comdat必须只有D1和D2析构函数。即使是这样也是如此   实现使用D0而不是调用D1 + _ZdlPv来实现   “delete * x”
  •   

您可以通过以下方式查看comdats:使用readelf -G转储文件:

COMDAT group section [    1] `.group' [_ZN1XD5Ev] contains 2 sections:
   [Index]    Name
   [   10]   .text._ZN1XD2Ev
   [   12]   .text._ZN1XD0Ev

COMDAT group section [    2] `.group' [_ZN1XC5Ev] contains 1 sections:
   [Index]    Name
   [   14]   .text._ZN1XC2Ev

(这与GCC 4.6有关,这可能与上述定义不符)