Для чого __gxx_personality_v0?


103

Це б / у питання з веб-сайту розробки ОС, але мене викликало цікавість, оскільки я ніде не міг знайти гідного пояснення.

Під час компіляції та зв’язування стоячої програми C ++ за допомогою gcc іноді виникає помилка лінкера на зразок цього:

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

Це, мабуть, тому, що цей символ визначений у libstdc ++, якого немає у вільно стоячому середовищі. Для усунення проблеми просто потрібно десь визначити цей символ:

void *__gxx_personality_v0;

Що приємно, але мені не подобаються речі, які просто магічно працюють ... Тож питання полягає в тому, яка мета цього символу?

Відповіді:


93

Він використовується в таблицях розгортання стека, які ви можете побачити, наприклад, у складі моєї відповіді на інше питання . Як було сказано у цій відповіді, його використання визначається Itanium C ++ ABI , де воно називається рутиною особистості .

Причина, що "працює", визначаючи її як глобальний недійсний покажчик NULL, ймовірно, тому, що ніщо не кидає виняток. Коли щось намагається викинути виняток, то ви побачите, що це неправильно.

Звичайно, якщо нічого не використовує винятки, ви можете відключити їх -fno-exceptions(а якщо RTTI нічого не використовує, ви також можете додати -fno-rtti). Якщо ви користуєтесь ними, вам доведеться (як інші відповіді вже зазначалися) g++замість цього посилання gcc, що додасть -lstdc++вам.


2
Дякую за пораду о -fno-exceptions. Я додав CPPFLAGS += -fno-exceptionsу свій makefile, і це вирішило помилку.
Алан Кіннаман

12

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


11

Обробка винятків включена у вільно реалізовані реалізації.

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


Я завжди думав, що компіляція з g ++ потрібна лише тоді, коли ви спеціально хотіли сказати компілятору, що код є C ++ (наприклад, відсутнє розширення). Тепер, здається, що компіляція коду C ++ з gcc втрачає включення бібліотек, що надходять. Крім відсутні деякі бібліотеки, є деякі інші «побічні ефекти» компіляція My file.cppз gccзамість g++?
Лазер

1
@eSkay, наскільки я знаю, посилання libstdc++є єдиною різницею між ними.
Йоханнес Шауб - ліб

6

Швидке схвалення libstd++бази коду показало наступні два використання __gx_personality_v0:

У libsupc ++ / unind-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; глобальна неініціалізована, тому вона може мати будь-яку цінність.
strager

6
Більш важко, глобальні знаки нулю ініціалізуються, якщо програміст не ініціалізує їх
Йоханнес Шауб - ліб

@litb: це справедливо лише в тому випадку, якщо ядро ​​реалізує нульовий розділ bss :-P. Але так, їх слід 0 ініціалізувати заради корисності.
Еван Теран

9
@ Еван Теран: Ні, відповідна реалізація C завжди ініціалізує глобальні точки до 0. Див. § 5.1.2 та § 6.7.8 параграф 10 стандарту C99.
Адам Розенфілд

6

У мене була помилка один раз, і я з'ясував походження:

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

gcc розпізнає .Cрозширення як програму C ++, а .cрозширення як програму C (будьте уважні до малого c та великого C).

Тому я перейменував свою файлову CLIENT.cпрограму, і вона спрацювала.


2

Наведені вище відповіді правильні: він використовується в обробці винятків. У посібнику для GCC версії 6 є додаткова інформація (якої більше немає в посібнику з версією 7). Помилка може виникнути при підключенні зовнішньої функції, яка - невідома GCC - видаляє винятки Java.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.