GCC Exception Frames

When an exception is thrown in C++ and caught by one of the calling functions, the supporting libraries need to unwind the stack. With gcc this is done using a variant of DWARF debugging information. The unwind information is loaded at runtime, but is not read unless an exception is thrown. That means that the unwind library needs to have some way of finding the appropriate unwind information at runtime.

On some systems, this is done by registering the exception frame information when the program starts. The registration is done with a variant of the handling of C++ constructors. This becomes interesting when one shared library can throw an exception which is caught by another shared library. It is possible for such a case to arise when the executable itself never throws exceptions and therefore has no frames to register. Obviously the unwinder needs to be able to find the unwind information for both shared libraries, which means that both shared libraries need to use the same registration functions. With gcc this is normally ensured by putting the unwind code in a shared library, libgcc_s.so. Each shared library, and sometimes the executable, will use libgcc_s.so. That ensures a single copy of the registration and unwind functions, so the library will be able to reliably unwind across shared libraries. With gcc the use of libgcc_s.so can be controlled with the -shared-libgcc and -static-libgcc options. Normally the right thing will happen by default.

That approach has a cost: there is an extra shared library, and there is a small cost of registering the unwind information at program startup or library load time (and unregistering it if a shared library is unloaded via dlclose). There is now a better way, which requires linker support.

Both gold and the GNU linker support the command line option --eh-frame-hdr. With this option, when the linker sees the .eh_frame sections used to hold the unwind information, it automatically builds a header. This header is a sorted array mapping program counter addresses to unwind information. The header is recorded as a program segment of type PT_GNU_EH_FRAME. (This is a little bit ugly since the .eh_frame sections are recognized only by name; ideally they should have a special section type.)

At runtime, the unwind library can use the dl_iterate_phdr function to find the program segments of the executable and all currently loaded shared libraries. It can use that to find the PT_GNU_EH_FRAME segments, and use the sorted array in those segments to quickly find the unwind information.

This approach means that no registration functions are required. It also means that it is not necessary to have a single shared library, since dl_iterate_phdr is available no matter which shared library throws the exception.

This all only works if you have a linker which supports generating PT_GNU_EH_FRAME sections, if all the shared libraries and the executable are linked by such a linker, and if you have a working dl_iterate_phdr function in your C library or dynamic linker. I think that pretty much restricts this approach to GNU/Linux and possibly other free operating systems. For those scenarios, I hope that gcc will soon be able to stop using libgcc_s.so by default.


Posted

in

by

Tags:

Comments

3 responses to “GCC Exception Frames”

  1. ncm Avatar

    Sorry, where is dl_iterate_phdr defined, and why couldn’t the present contents of libgcc_s.so be there, too, similarly obviating libgcc_s.so without need to build with –eh-frame-hdr? I think I’m still missing some context.

  2. Ian Lance Taylor Avatar

    dl_iterate_phdr is provided by the dynamic linker. It is declared in .

    I guess you are suggesting: why not put the unwind code in the dynamic linker? In principle we could do that someday. In practice that would fix the ABI and API not merely the ABI of the unwind information, which is already fixed, but also the ABI and API of the unwinder. That might be desirable at some point, but for now I think it would be better to let the compiler continue own it.

Leave a Reply