What is a "destructor group" symbol in gcc name mangling

1.9k views Asked by At

https://stackoverflow.com/a/6614369/1091587 has a quick rundown of the destructor types (D0, D1, D2) that appear when you read the symbol table of a program compiled using “gcc3”-type name mangling. There are also corresponding constructors C0/C1/C2. With g++-4.7 (possibly earlier), there appears a new ctor/dtor pair, namely C5/D5, however only as a debugging symbol.

$ 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()

The demangler source calls the D5 object a “gnu_v3_object_dtor_group”, but what exactly is a dtor group and what is it good for? clang++-3.3 does not emit it, and http://gcc.gnu.org/ml/gcc-patches/2011-11/msg00383.html suggests it might have something to do with the new transactional memory feature in gcc.

1

There are 1 answers

0
Igor Skochinsky On

This LLVM patch and this GCC bug provide more background. By following the links I found Bug 3187 - gcc lays down two copies of constructors which seems to be the origin of it all:

Two (sometimes three) identical copies of constructors and destructors are laid down. The linker doesn't fail this, but the binaries produced are 20% bigger (on our real-world example) than necessary.

You can find many discussions on the gcc-patches ML if you search for "PR c++/3187" (e.g.). Basically, C5/D5 is not a constructor/destructor by itself, but a COMDAT group containing two or more of "basic" constructors/destructors. This ensures that the functions in the group are either all used in the final binary, or all discarded (to enforce the "one definition rule").

The result of the discussions in the above bugs seems to be:

For any class an implementation has the option of using one comdat per constructor/destructor or using a C5/D5 comdat. I may make that decision based on any profitability criterion. If using a C5/D5 comdat the rules are

  • A C5 comdat must have C1 and C2.
  • If a class has a virtual destructor, the D5 comdat must have D0, D1 and D2
  • If a class has a non-virtual destructor, the D5 comdat must have only the D1 and D2 destructors. That is true even if the implementation uses D0 instead of a call to D1 + _ZdlPv to implement "delete *x"

You can see the comdats by e.g. dumping the file with 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

(This is with GCC 4.6 which is probably why it does not match the definition above)