[cfe-commits] [libcxxabi] r147148 - in /libcxxabi/trunk: CREDITS.TXT src/cxa_exception.cpp

John McCall rjmccall at apple.com
Fri Dec 23 00:02:22 PST 2011


On Dec 22, 2011, at 9:14 PM, Howard Hinnant wrote:
> On Dec 22, 2011, at 7:36 PM, John McCall wrote:
>> On Dec 22, 2011, at 4:10 PM, Dave Zarzycki wrote:
>>> Howard,
>>> 
>>> Does the ABI require that it be prefixed with __gxx_*?
>> 
>> Not at the Itanium ABI level, but at the level of of drop-in compatibility
>> with libstdc++, yes.  GCC and Clang emit code with references to
>> exactly this symbol.  The "gxx" is best interpreted as "personality that
>> consumes LSDA information in the v0 format output by G++".
>> 
>> John.
> 
> Thanks John, yes.  I found this by scanning the clang sources.  But this brings up an additional question:
> 
> I also found __gxx_personality_sj0 in the clang sources.  Does this also need to be provided?  And if so, how does it differ from __gxx_personality_v0?
> 
> For that matter, clang has all of these:
> 
> const EHPersonality EHPersonality::GNU_C("__gcc_personality_v0");
> const EHPersonality EHPersonality::GNU_C_SJLJ("__gcc_personality_sj0");
> const EHPersonality EHPersonality::NeXT_ObjC("__objc_personality_v0");
> const EHPersonality EHPersonality::GNU_CPlusPlus("__gxx_personality_v0");
> const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ("__gxx_personality_sj0");
> const EHPersonality EHPersonality::GNU_ObjC("__gnu_objc_personality_v0",
>                                            "objc_exception_throw");
> const EHPersonality EHPersonality::GNU_ObjCXX("__gnustep_objcxx_personality_v0");
> 
> And I don't know how to handle all of these, or even know if I should try.

Exception propagation needs to be able to walk the stack of "exception scopes" (i.e. cleanups / catches), figure out what's active in any given call frame, and potentially restore the processor to a state consistent with any given scope.

One way to do this is to provide some way to map an IP back to a table of exception information about that function, and have that table tell you (1) the return address for the caller, (2) how to restore the register state of the caller, and (3) what scopes are active for this IP.  The dominant standard for this on UNIXy platforms is to use DWARF, or at least something kindof approximating DWARF.  This technique imposes relatively minimal overhead on the non-exception path, but it heavily penalizes the exception path, inflates binary sizes even for code not using exceptions, and involves a lot of runtime and compiler complexity.

Another way to do this is for the compiler to generate instructions that dynamically maintain this stack in a way that's directly manipulable by libUnwind.  GCC calls this setjmp/longjmp EH, although in practice it uses special, faster variants that work magically in tandem with the compiler.  This technique imposes more overhead on the non-exception paths, but it penalizes the exception path less and (more importantly) is quite easy to bring up.  There are still exception tables, but they have a slightly different format, and the personality function has different work to do.

To make this more concrete, Apple uses SJ/LJ exclusively on ARM;  we only use it there because that's all that GCC's ARM backend supported at the time.  There are other platforms that use SJ/LJ exceptions.  I don't really know them all.

(There is yet another exception scheme that uses the true system setjmp/longjmp, which is used for ObjC exceptions on PPC and i386.  It doesn't use personality functions at all and does not interoperate with C++ exceptions, so it does not otherwise figure into this discussion.  I bring it up only to stave off possible confusion.)

So in general, blah_personality_sj0 is meant to consume SJ/LJ tables and do SJ/LJ resumption, and everything else (with one exception) uses DWARF.  The unwinders can't co-exist, so you either provide one symbol or the other depending on whether you've been compiled for a platform that uses SJ/LJ or one that uses DWARF.  The only reason to use different symbol names is to protect against horrific compiler misconfigurations.  The Darwin ObjC people decided they didn't care, so they always use the same symbol name:  __objc_personality_v0 follows DWARF behavior on DWARF platforms and SJ/LJ behavior on SJ/LJ platforms.

So, breaking it down by personality symbol:

These five symbols are not provided by the C++ standard library:

__gcc_personality_v0 is the C personality function for DWARF unwinding.  It is provided by libc on platforms that use DWARF unwinding.
__gcc_personality_sj0 is the C personality function for SJ/LJ unwinding.  It is provided by libc on platforms that use SJ/LJ unwinding.
__objc_personality_v0 is the Darwin ABI ObjC/ObjC++ personality function, which interoperates with and piggybacks on the C++ personality function.  It is provided by libobjc and uses either SJ/LJ or DWARF unwinding, depending on what platform it was compiled for.
__gnu_objc_personality_v0 is the GNUStep ABI ObjC personality function for the DWARF unwinder.  It is provided by GNUStep's libobjc.  AFAIK, GNUStep does not support any platforms that use non-DWARF unwinding.
__gnustep_objcxx_personality_v0 is the GNUStep ABI ObjC++ personality function, which IIRC is just like the last one except it interoperates with C++ exceptions correctly.

However, one of these symbols must be provided, depending on the target platform:

__gxx_personality_v0 is the C++ personality function for DWARF unwinding.
__gxx_personality_sj0 is the C++ personality function for SJ/LJ unwinding.

As a future note, there is a lot of room for improvement over the G++ personality functions.  We may someday want to explore a Clang-specific personality function, which we would then expect the C++ standard library to provide just as it provides a G++-specific one.

John.



More information about the cfe-commits mailing list