什么是__gxx_personality_v0?

Bru*_*ton 98 c++ linker gcc kernel

这是来自操作系统开发网站的二手问题,但它让我很好奇,因为我无法在任何地方找到合适的解释.

使用gcc编译和链接独立的C++程序时,有时会出现这样的链接器错误:

out/kernel.o:(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'
Run Code Online (Sandbox Code Playgroud)

这显然是因为这个符号是在libstdc ++中定义的,它在独立环境中是缺失的.解决问题只需要在某处定义此符号:

void *__gxx_personality_v0;
Run Code Online (Sandbox Code Playgroud)

这很好,但我不喜欢那些神奇地工作的东西......所以问题是,这个符号的目的是什么?

Ces*_*arB 90

它用在堆栈展开表中,您可以在我对另一个问题的答案的汇编输出中看到它.正如在该答案中所提到的,它的使用是由Itanium C++ ABI定义的,它被称为Personality Routine.

它通过将其定义为全局NULL void指针而"工作"的原因可能是因为没有任何东西抛出异常.当某些东西试图抛出异常时,你会发现它行为异常.

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

  • 感谢您提供有关 `-fno-exceptions` 的提示。我在我的 makefile 中添加了 `CPPFLAGS += -fno-exceptions`,这解决了错误。 (3认同)

Mar*_*wis 11

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


Joh*_*itb 11

异常处理包含在独立实现中.

这样做的原因是您可能使用gcc编译代码.如果使用该选项进行编译,-###则会-lstdc++在调用链接器进程时发现它缺少linker-option .编译g++将包括该库,因此包含在其中定义的符号.


Ada*_*eld 6

libstd++代码库的快速grep 揭示了以下两个用法__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 *);
Run Code Online (Sandbox Code Playgroud)

在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 ...
}
Run Code Online (Sandbox Code Playgroud)

(注意:它实际上比这复杂一点;有一些条件编译可以改变一些细节).

所以,只要你的代码实际上没有使用异常处理,定义符号void*就不会影响任何东西,但是一旦它完成,你就会崩溃 - __gxx_personality_v0是一个函数,而不是一些全局对象,所以尝试调用该函数将跳转到地址0并导致段错误.

  • @Evan Teran:不,符合要求的C实现总是将全局变量初始化为0.参见C99标准的§5.1.2和§6.7.8第10段. (9认同)
  • 如果程序员没有初始化它们,则初始化为strager,globals为零 (6认同)

jlg*_*ego 6

我有一次这个错误,我发现了原点:

我正在使用gcc编译器,我的文件被调用,CLIENT.C尽管我正在做一个C程序而不是C++程序.

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

所以我重命名了我的文件CLIENT.c程序,它工作正常.