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.
Leave a Reply
You must be logged in to post a comment.