_Attribute_((Constructor)) Call Order Confusion

__attribute__((constructor)) call order confusion

You might try using linker scripts for ld. You can read more about it here, but I guess what you are looking for is

.ctors : { *(SORT(.ctors)) MyLastInitChance.o(SORT(.ctors)) }
.dtors : { *(SORT(.dtors)) MyLastInitChance.o(SORT(.dtors)) }

in SECTIONS{...} block. That should rearrange .ctors sections so file provided will call it's constructors as the last one. Obviously more advanced solutions are also available if you find yorself in need for one;)

HINT: writing your own link-script is tedious. Use ld's --verbose option that prints out used link script and modify it. Then add your linking script using -T switch.

GCC __attribute__((constructor)) is called before object constructor

__attribute__((constructor)) is a compiler extension, and so you left the realms of standard C++. It looks like GCC's constructor functions are run before global initialization.

The way to fix it is to use another vanilla C++ construct, for example a global object whose initialization is properly sequenced by defining it in the same TU as your other global:

Ala a;

static void initialize_shared_library() {
printf("initializing shared library\n");
printf("a.i=%d\n", a.getI());
printf("end of initialization of the shared library\n");
}

static int const do_init = (initialize_shared_library(), 0);

C++ static initialization vs __attribute__((constructor))

foo will be printed first, as the objects are initialized in the order of their declarations. Run and see:

  • Ideone online demo

By the way, __attribute__((constructor)) is not Standard C++. It is GCC's extension. So the behavior of your program depends on how GCC has defined it. In short, it is implementation-defined, according to it foo is printed first.

The doc says,

The constructor attribute causes the function to be called automatically before execution enters main (). Similarly, the destructor attribute causes the function to be called automatically after main () has completed or exit () has been called. Functions with these attributes are useful for initializing data that will be used implicitly during the execution of the program.

You may provide an optional integer priority to control the order in which constructor and destructor functions are run. A constructor with a smaller priority number runs before a constructor with a larger priority number; the opposite relationship holds for destructors. So, if you have a constructor that allocates a resource and a destructor that deallocates the same resource, both functions typically have the same priority. The priorities for constructor and destructor functions are the same as those specified for namespace-scope C++ objects (see C++ Attributes).

I think the text in bold implies, the objects are initialized in the order of their declarations, as I said before, which is pretty much confirmed by online demo also.

I guess you would also like to read this:

  • 7.7 C++-Specific Variable, Function, and Type Attributes

If you want to control/alter the initialization order, you can use init_priority attribute, providing priority. Taken from the page:

Some_Class  A  __attribute__ ((init_priority (2000)));
Some_Class B __attribute__ ((init_priority (543)));

Here, B is initialized before A.

__attribute__((constructor)) how it change entry point?

Functions marked as "constructor" are placed in a special section in the executable file. The "start" function will then invoke those functions one by one, before it calls main.

The same with "destructor" functions, they are again placed in a special section and called by the code executing after exit is called or main returns.

Multiple shared library constructors not being called

This is normal and expected. In the C language, each external identifier can have at most one definition; if there are more, the behavior is undefined. ELF dynamic linking is (rather painstakingly) designed to yield behavior as close as possible to static linking, where despite more than one library defining an external identifier with the same name, the behavior may very well be well-defined due to only one definition getting used (static libraries are simply archives of object files, where only the object files needed to provide definitions for undefined symbol references get pulled into the link). This means the first definition (in link order) gets used whenever definitions exist in more than one linked shared library.

That's the explanation for what you're seeing, but the solution is much simpler. There is no reason for constructors to have external linkage to begin with. Make them all static and it doesn't matter what their names are. And for external identifiers in your libraries that do need to be external, make sure they're named according to some pattern where they won't clash.

How does GCC implement __attribute__((constructor)) on MinGW?

For MinGW targets (and other COFF targets, like Cygwin) compiler just emits each constructor function address in .ctors COFF section:

$ cat c1.c
void c1() {
}
$ x86_64-w64-mingw32-gcc -c c1.c
$ objdump -x c1.o | grep ctors
# nothing
$ cat c1.c
__attribute__((constructor)) void c1() {
}
$ x86_64-w64-mingw32-gcc -c c1.c
$ objdump -x c1.o | grep ctors
5 .ctors 00000008 0000000000000000 0000000000000000 00000150 2**3

GNU ld linker (for MinGW targets) is then configured (via its default linker script) to combine these sections into regular .text section with __CTOR_LIST__ symbol pointing to the first item, and having the last item terminated with zero. (Probably .rdata section would be clearer since these are just addresses of functions, not CPU instructions, but for some reason .text is used. In fact LLVM LLD linker targeting MinGW places them in .rdata.)

LD linker:

$ x86_64-w64-mingw32-ld --verbose
...
.text ... {
...
__CTOR_LIST__ = .;
LONG (-1); LONG (-1);
KEEP (*(.ctors));
KEEP (*(.ctor));
KEEP (*(SORT_BY_NAME(.ctors.*)));
LONG (0); LONG (0);
...
...
}

Then it is up to C runtime library to run these constructors during initialization, by using this __CTOR_LIST__ symbol.

From mingw-w64 C runtime:

extern func_ptr __CTOR_LIST__[];

void __do_global_ctors (void)
{
// finds the last (zero terminated) item
...
// then runs from last to first:
for (i = nptrs; i >= 1; i--)
{
__CTOR_LIST__[i] ();
}
...
}

(also, it is very similar in Cygwin runtime)

This can be also seen in the debugger:

$ echo $MSYSTEM
MINGW64

$ cat c11.c
#include <stdio.h>

__attribute__((constructor))
void i1() {
puts("i 1");
}

int main() {
puts("main");
return 0;
}

$ gcc c11.c -o c11

$ gdb ./c11.exe
(gdb) b i1
(gdb) r
(gdb) bt
#0 0x00007ff603591548 in i1 ()
#1 0x00007ff6035915f2 in __do_global_ctors () at C:/_/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/gccmain.c:44
#2 0x00007ff60359164f in __main () at C:/_/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/gccmain.c:58
#3 0x00007ff60359139b in __tmainCRTStartup () at C:/_/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:313
#4 0x00007ff6035914f6 in mainCRTStartup () at C:/_/M/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:202
(gdb)

Note that in some environments (not MinGW and not Linux) it is instead the responsibility of GCC (its compiler runtime libgcc, more specifically its static part called crtbegin.o and crtend.o) and not C runtime to run these constructors.

Also, for comparison, on ELF targets (like Linux) GCC compiler used similar mechanism like the one described above for MinGW (it used ELF .ctors sections, although the rest was a bit different), but since GCC 4.7 (released in 2012) it uses slightly different mechanism (ELF .init_array section).

How do I get the GCC __attribute__ ((constructor)) to work under OSX?

(a) Your code works for me compiling and running on SnowLeopard in Xcode 3.2.

(b) I'm not sure when stdout is guaranteed to have been set up. You're running code before main. Why not update a global variable here, then print it out in main to see if your code ran.

Template object declaration and initialization: manually call template constructor to bypass standard constructors calls order

Reading C++: When (and how) are C++ Global Static Constructors Called? and http://www.parashift.com/c++-faq-lite/static-init-order.html

There seems to be something called "static initialization order fiasco". The order of initialization varies between compilations, therefore it is not certain when a variable is initialized before use.

A suggestion from http://www.parashift.com/c++-faq-lite/static-init-order-on-first-use.html is to create a function containing a static variable that will ensure initialization happens before first use.

From that, and using dense_hash_map from this question, here is a snippet of code that prevents this problem:

typedef dense_hash_map<const char*, int, hash<const char*>, eqstr> hashtable;

//singleton function
hashtable *month_singleton() {
static hashtable *months = NULL;
//initialization, happens on first run
if (months == NULL) {
months = new hashtable();
months.set_empty_key(NULL);
}
return months;
}

__attribute__((constructor)) static void monthly_constructor()
{
months_singleton()["january"] = 31;
}


Related Topics



Leave a reply



Submit