Что такое символ "группа деструкторов" в названии gcc

/questions/11879843/gnu-gcc-g-pochemu-on-generiruet-neskolko-dtors/11879846#11879846 содержит краткое изложение типов деструкторов (D0, D1, D2), которые появляются, когда вы читаете таблицу символов программы, скомпилированной с использованием искажения имен типа "gcc3". Существуют также соответствующие конструкторы 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 ответ

Этот патч LLVM и эта ошибка GCC обеспечивают больше фона. Перейдя по ссылкам, которые я обнаружил, ошибка 3187 - gcc устанавливает две копии конструкторов, которые, кажется, являются источником всего этого:

Две (иногда три) идентичные копии конструкторов и деструкторов заложены. Компоновщик не подведет это, но произведенные двоичные файлы на 20% больше (на нашем реальном примере), чем необходимо.

Вы можете найти много дискуссий о gcc-patches ML, если вы ищете "PR C++/3187" ( например). По сути, C5/D5 сам по себе не конструктор / деструктор, а группа COMDAT, содержащая два или более "базовых" конструктора / деструктора. Это гарантирует, что все функции в группе либо используются в конечном двоичном файле, либо все отбрасываются (для обеспечения соблюдения "правила одного определения").

Результатом обсуждений в вышеупомянутых ошибках, кажется, являются:

Для любого класса реализация имеет возможность использовать один comdat для каждого конструктора / деструктора или использовать C5/D5 comdat. Я могу принять это решение на основе любого критерия прибыльности. При использовании C5 / D5 comdat правила

  • Comdat C5 должен иметь C1 и C2.
  • Если у класса есть виртуальный деструктор, то у D5 comdat должны быть D0, D1 и D2
  • Если в классе есть не виртуальный деструктор, то в комитате D5 должны быть только деструкторы 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, возможно, поэтому он не соответствует определению выше)

Другие вопросы по тегам