In C++, I know that the compiler can choose to initialize static objects in any order that it chooses (subject to a few constraints), and that in general you cannot choose or determine the static initialization order.
However, once a program has been compiled, the compiler has to have made a decision about what order to initialize these objects in. Is there any way to determine, from a compiled program with debugging symbols, in what order static constructors will be called?
The context is this: I have a sizeable program that is suddenly segfaulting before main() when it is built under a new toolchain. Either this is a static initialization order problem, or it is something wrong with one of the libraries that it is loading. However, when I debug with gdb, the crash location is simply reported as a raw address without any symbolic information or backtrace. I would like to decide which of these two problems it is by placing a breakpoint at the constructor of the very first statically-initialized object, but I don't know how to tell which object that is.
In G++ on Linux, static constructor and destructor ordering is determined by function pointers in the .ctors and .dtors sections. Note that with sufficient debugging available, you can actually get a backtrace:
(gdb) bt
#0 0xb7fe3402 in __kernel_vsyscall ()
#1 0xb7d59680 in *__GI_raise (sig=6)
at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#2 0xb7d5cd68 in *__GI_abort () at abort.c:88
#3 0x08048477 in foo::foo() ()
#4 0x0804844e in __static_initialization_and_destruction_0(int, int) ()
#5 0x0804846a in global constructors keyed to foo_inst ()
#6 0x0804850d in __do_global_ctors_aux ()
#7 0x08048318 in _init ()
#8 0x080484a9 in __libc_csu_init ()
#9 0xb7d4470c in __libc_start_main (main=0x8048414 <main>, argc=1,
ubp_av=0xbfffcbc4, init=0x8048490 <__libc_csu_init>,
fini=0x8048480 <__libc_csu_fini>, rtld_fini=0xb7ff2820 <_dl_fini>,
stack_end=0xbfffcbbc) at libc-start.c:181
#10 0x08048381 in _start () at ../sysdeps/i386/elf/start.S:119
This is with debugging symbols for libc and libstdc++ installed. As you can see, the crash here occured in the foo::foo() constructor for the static object foo_inst.
If you want to break into the initialization process, you could then set a breakpoint on __do_global_ctors_aux and step through its disassembly, I suppose. Or just wait for it to crash to get the backtrace like the above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With