2008-11-30 6 views
79

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

При компиляции и компоновки свободно стоящей программы на C++ с использованием GCC, иногда ошибка линкера, как это происходит:

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

Это, по-видимому, потому что этот символ определен в libstdC++, который отсутствует в FREE- постоянная окружающая среда. Решение проблемы просто требует определения этого символа где:

void *__gxx_personality_v0; 

Что приятно, но мне не нравится то, что просто волшебно работать ... Так что вопрос в том, какова цель этого символа?

ответ

73

Используется в неперекрывающихся таблицах стека, которые вы можете увидеть, например, в сборочном выходе my answer to another question. Как упоминалось в этом ответе, его использование определяется Itanium C++ ABI, где оно называется Personality Routine.

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

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

10

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

4

Быстрый Grep базового кода libstd++ выявил следующие два обычаи __gx_personality_v0:

В libsupC++/размотки-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 *); 

В libsupC++/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.

+0

Не обязательно прыгать на 0; глобальный неинициализирован, поэтому на самом деле это может быть любая ценность. – strager 2008-11-30 17:53:15

+6

strager, globals инициализируются нулем, если программист не инициализирует их – 2008-11-30 18:25:25

+0

@litb: это верно только в том случае, если ядро ​​реализует обнуление секции bss: -P. Но да, они должны быть инициализированы ради сани. – 2009-03-27 15:29:54

8

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

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

4

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

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

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

Поэтому я переименовал файл CLIENT.c, и он сработал.

1

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

Смежные вопросы