Assume I build the simple DLL, consisting of two translation units:
first
// foo.cpp
struct Foo
{
//...
} g_foo;
// ... other stuff
and second
// bar.cpp
struct Bar
{
//...
} g_bar;
// ... other stuff
I'm aware of the fact that C++ standard doesn't specify the order of global variables initialization. The question is: once I have the built Windows DLL, is the order of global variables initialization performed during LoadLibrary
call deterministic (every LoadLibrary
call will launch initialization of the variables g_foo
and g_bar
in the same order) or it may depend on some loader/system settings?
I'm aware of the fact that C++ standard doesn't specify the order of global variables initialization. To be precise, it does when the global variables are within a single translation unit:
Your DLL code above, where you have two different global variables within two different translation units, will result in two different .OBJ files before link. Then, when the .OBJ files are linked together to form a .DLL, the C++ "pre-main" runtime code will be attached to the .DLL. When the .DLL is bound to the address space of the process by process-launch or by LoadLibrary
, this stub code will have access to a table within your DLL, which, before invocation of DllMain, it will iterate-through, invoking link-time-synthesized static non-member functions in the table, each non-member function having the job of running a class member constructor in the table for the corresponding global object. Naturally, during removal of DLL from your process address space, either by process-exit or by FreeLibrary
, the non-member functions will be similarly invoked, but in reverse (LIFO) order.
Given that this table is "baked" into the .DLL by LINK.EXE, the order of construction for global variables within the DLL, whether they are from same translation unit, or different, will be predetermined. It will not be predictable before link-time, as you noted, but whatever it becomes after link-time, that is what it will remain for the life of the .DLL because only LINK.EXE has the ability to construct that global variable constructor table, and once it is constructed, it is constructed.
If anyone is wondering which comes first: the construction of global variables, or the programmer-supplied DllMain, it is the former. The C++ run-time code is what invokes the programmer-supplied DllMain, as can be seen in the link provided by @Algirdas Preidžius.