views:

3788

answers:

5

This is a second-hand question from an OS development site, but it made me curious since I couldn't find a decent explanation anywhere.

When compiling and linking a free-standing C++ program using gcc, sometimes a linker error like this occurs:

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

This is apparently because this symbol is defined in libstdc++, which is missing in a free-standing environment. Fixing the problem simply requires defining this symbol somewhere:

void *__gxx_personality_v0;

Which is nice, but I don't like things that just magically work... So the question is, what is the purpose of this symbol?

+4  A: 

It's part of the exception handling. The gcc EH mechanism allows to mix various EH models, and a personality routine is invoked to determine if an exception match, what finalization to invoke, etc. This specific personality routine is for C++ exception handling (as opposed to, say, gcj/Java exception handling).

Martin v. Löwis
+2  A: 

A quick grep of the libstd++ code base revealed the following two usages of __gx_personality_v0:

In 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 *);

In 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 ...
}

(Note: it's actually a little more complicated than that; there's some conditional compilation that can change some details).

So, as long as your code isn't actually using exception handling, defining the symbol as void* won't affect anything, but as soon as it does, you're going to crash - __gxx_personality_v0 is a function, not some global object, so trying to call the function is going to jump to address 0 and cause a segfault.

Adam Rosenfield
Not necessarily jump to 0; the global is uninitialized so it could be any value, really.
strager
strager, globals are zero initialized if the programmer doesn't initialize them
Johannes Schaub - litb
@litb: this is only true if the kernel implements zeroing the bss section :-P. But yes, they should be 0 initialized for sanity sake.
Evan Teran
@Evan Teran: No, a conforming C implementation will always initialize globals to 0. See §5.1.2 and §6.7.8 paragraph 10 of the C99 standard.
Adam Rosenfield
+1  A: 

Are you compiling with gcc or g++? I remember getting similar errors compiling a C++ program with gcc accidentally.

Greg Rogers
+2  A: 

Exception handling is included in free standing implementations.

The reason of this is that you possibly use gcc to compile your code. If you compile with the option -### you will notice it is missing the linker-option -lstdc++ when it invokes the linker process . Compiling with g++ will include that library, and thus the symbols defined in it.

Johannes Schaub - litb
@Johannes Schaub - litb: I always thought compiling with g++ was only needed when you specifically wanted to tell the compiler that the code was C++ (for example- missing extension). Now it seems that compiling C++ code with gcc misses inclusion of come libraries. Apart from missing some libraries, are there some other "side-effects" of compiling my `file.cpp` with `gcc` instead of `g++`?
Lazer
@eSkay as far as i know, the linking of `libstdc++` is the only difference between the two.
Johannes Schaub - litb
+7  A: 

It is used in the stack unwiding tables, which you can see for instance in the assembly output of my answer to another question. As mentioned on that answer, its use is defined by the Itanium C++ ABI, where it is called the Personality Routine.

The reason it "works" by defining it as a global NULL void pointer is probably because nothing is throwing an exception. When something tries to throw an exception, then you will see it misbehave.

Of course, if nothing is using exceptions, you can disable them with -fno-exceptions (and if nothing is using RTTI, you can also add -fno-rtti). If you are using them, you have to (as other answers already noted) link with g++ instead of gcc, which will add -lstdc++ for you.

CesarB