Для чего __gxx_personality_v0?

Это вопрос из вторых рук с сайта разработки ОС, но мне было любопытно, потому что я не мог найти достойного объяснения где угодно.

При компиляции и связывании отдельно стоящей программы на С++ с использованием gcc иногда возникает такая ошибка компоновщика:

out/kernel.o:(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'

Это, по-видимому, потому, что этот символ определен в libstdС++, который отсутствует в свободностоящей среде. Исправление проблемы просто требует определения этого символа где-то:

void *__gxx_personality_v0;

Это хорошо, но мне не нравятся вещи, которые просто магически работают... Итак, вопрос в том, какова цель этого символа?

Ответ 1

Он используется в неперекрывающихся таблицах, которые вы можете увидеть, например, в сборке моего ответа на другой вопрос. Как упоминалось в этом ответе, его использование определяется Itanium С++ ABI, где оно называется "Личность" .

Причина, по которой он "работает", определяя его как глобальный указатель void NULL, вероятно, потому, что ничего не выбрасывает исключение. Когда что-то пытается выбросить исключение, вы увидите, что оно ошибочно.

Конечно, если ничего не использует исключения, вы можете отключить их с помощью -fno-exceptions (и если ничего не используется RTTI, вы также можете добавить -fno-rtti). Если вы используете их, вы должны (как уже отмечалось, другие ответы) ссылаться на g++ вместо gcc, что добавит -lstdc++ для вас.

Ответ 2

Это часть обработки исключений. Механизм gcc EH позволяет смешивать различные модели EH, и вызывается индивидуальная процедура, чтобы определить, соответствует ли совпадение, какую завершающую процедуру вызывать и т.д. Эта специфическая рутина для обработки исключений С++ (в отличие от, скажем, gcj/Java обработка исключений).

Ответ 3

Обработка исключений включена в свободностоящие реализации.

Причина этого заключается в том, что вы можете использовать gcc для компиляции кода. Если вы скомпилируете с опцией -###, вы заметите, что отсутствует компоновщик -lstdc++, когда он вызывает процесс компоновщика. Компиляция с помощью g++ будет включать эту библиотеку и, следовательно, символы, определенные в ней.

Ответ 4

Быстрый grep базы кода libstd++ показал следующие два использования __gx_personality_v0:

В libsupС++/unwind-cxx.h

// GNU C++ personality routine, Version 0.                                      
extern "C" _Unwind_Reason_Code __gxx_personality_v0
     (int, _Unwind_Action, _Unwind_Exception_Class,
      struct _Unwind_Exception *, struct _Unwind_Context *);

В libsupС++/eh_personality.cc

#define PERSONALITY_FUNCTION    __gxx_personality_v0
extern "C" _Unwind_Reason_Code
PERSONALITY_FUNCTION (int version,
                      _Unwind_Action actions,
                      _Unwind_Exception_Class exception_class,
                      struct _Unwind_Exception *ue_header,
                      struct _Unwind_Context *context)
{
  // ... code to handle exceptions and stuff ...
}

(Примечание: это на самом деле немного сложнее, чем это, там есть условная компиляция, которая может изменить некоторые детали).

Итак, пока ваш код фактически не использует обработку исключений, определение символа как void* не повлияет ни на что, но как только это произойдет, вы собираетесь сбой - __gxx_personality_v0 является функция, а не какой-либо глобальный объект, поэтому попытка вызвать функцию будет переходить к адресу 0 и вызывать segfault.

Ответ 5

У меня была эта ошибка один раз, и я узнал происхождение:

Я использовал компилятор gcc, и мой файл был вызван CLIENT.C, несмотря на то, что я выполнял программу на C, а не программу на С++.

gcc распознает расширение .C как программу С++ и расширение .C как программу C (будьте осторожны с маленькими c и большими C).

Итак, я переименовал мою программу CLIENT.C и работал.

Ответ 6

Ответы правильны: он используется в обработке исключений. руководство для GCC версии 6 содержит дополнительную информацию (которая больше не присутствует в руководстве по версии 7). Ошибка может возникнуть при связывании внешней функции, которая - неизвестна для GCC - выбрасывает исключения Java.