Visual C++: Is global variables initialization order deterministic during DLL loading?

398 views Asked by At

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?

1

There are 1 answers

0
HackTheStack On BEST ANSWER

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:

Ordered dynamic initialization, which applies to all other non-local variables: within a single translation unit, initialization of these variables is always sequenced in exact order their definitions appear in the source code.

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.