__gxx_personality_v0的作用是什么?


103

这是一个来自OS开发站点的二手问题,但是由于我在任何地方都找不到合适的解释,这使我感到好奇。

使用gcc编译和链接独立的C ++程序时,有时会发生如下链接错误:

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

这显然是因为该符号是在libstdc ++中定义的,而在独立环境中则缺少该符号。解决问题仅需在以下位置定义此符号:

void *__gxx_personality_v0;

哪个很好,但是我不喜欢魔术般工作的东西...所以问题是,这个符号的目的是什么?

Answers:


93

它在堆栈展开表中使用,例如,您可以在我对另一个问题的回答的汇编输出中看到这些表。如该答案所述,其使用由Itanium C ++ ABI定义,在此称为“ 个性例程”

通过将其定义为全局NULL void指针而“起作用”的原因可能是因为没有东西引发异常。当某些东西试图引发异常时,您会发现它的行为异常。

当然,如果什么都没有使用异常,则可以使用禁用它们-fno-exceptions(如果什么也没有使用RTTI,也可以添加-fno-rtti)。如果您正在使用它们,则必须(如已经提到的其他答案)链接g++而不是gcc,这将为-lstdc++您增加。


2
感谢您的提示-fno-exceptions。我将其添加CPPFLAGS += -fno-exceptions到我的makefile中,从而解决了该错误。
艾伦·金纳曼

12

这是异常处理的一部分。gcc EH机制允许混合各种EH模型,并调用个性例程来确定是否匹配异常,要调用的终结处理等。此特定的个性例程用于C ++异常处理(与gcj / Java相反)异常处理)。


11

独立实现中包括异常处理。

这是因为您可能会gcc用来编译代码。如果使用该选项进行编译,-###则会发现它-lstdc++在调用链接器进程时丢失了链接器选项。进行编译g++将包括该库,并因此包含其中定义的符号。


我一直认为仅当您特别想告诉编译器代码是C ++时(例如,缺少扩展名),才需要使用g ++进行编译。现在看来,用gcc编译C ++代码会错过对come库的包含。除了缺少某些库之外,还有其他的“ file.cpp用... gcc代替”编译我的“副作用” g++吗?
拉泽尔

1
据我所知,@ eSkay的链接libstdc++是两者之间的唯一区别。
Johannes Schaub-litb 2010年

6

快速的grep libstd++代码库显示了以下两种用法__gx_personality_v0

在libsupc ++ / 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 *);

在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并导致段错误。


不一定要跳到0;全局未初始化,因此它可以是任何值。
斯特拉格

6
斯特拉格,如果程序员不初始化全局变量,则全局变量将初始化为零
Johannes Schaub-litb

@litb:仅当内核实现对bss部分:-P归零时,这才是正确的。但是,是的,出于理智考虑,应将它们初始化为0。
Evan Teran

9
@Evan Teran:不,符合C的实现将始终将全局变量初始化为0。请参见C99标准的第5.1.2节和第6.7.8节第10段。
亚当·罗森菲尔德2009年

6

我曾经有此错误,我找出了原因:

我正在使用gcc编译器,CLIENT.C尽管我正在执行C程序而不是C ++程序,但仍调用了我的文件。

gcc将.C扩展名识别为C ++程序,将扩展名识别.c为C程序(请注意小C和大C)。

因此,我重命名了文件CLIENT.c程序,它开始工作了。


2

上面的答案是正确的:它用于异常处理。GCC版本6 的手册具有更多信息(版本7手册中不再存在)。当链接外部函数(对于GCC未知)会引发Java异常时,会出现该错误。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.