When exactly does gcc __attribute __ ((constructor)) start?

Say I have libA.so with a GCC constructor.

My program "program" depends on libA.so, so when I run it, libA.so opens and its constructor runs. Now I also have the libC.so module, which also depends on libA. I run dlopen("libC.so") , which loads libC, and according to my experiments, also executes the libA constructor .

Dependencies are as follows:

  • libA has a constructor
  • libB also has a constructor
  • libC depends on libA and libB
  • depends on libA
  • libC program links via dlopen ()

Now when I run the program:

  • The libA constructor starts before main () starts.
  • The libB constructor is started by dlopen ()

Dlopen seems to execute library constructors when they are loaded into memory. This is indicated somewhere, and how does the linker check which libraries are already loaded?

(Why I ask: at some point I got a constructor executed twice in a situation in some not quite clear conditions. Do I correctly believe that this was completely broken and should not happen in a normal situation?)

+6
source share
1 answer

For ELF __attribute__((constructor)) files, the marked functions are ultimately run from the DT_INIT tag (initialization function). Similarly for __attribute((destructor)) and the DT_FINI tag (completion function).

Initialization functions are started after the moves are made, and before the control returns to the program, which for downloadable shared objects of the program load time before switching to control to main() , and for the runtime, the loaded shared objects can probably be interpreted as before returning from dlopen() . The initialization functions from DT_NEEDED shared objects are run before the initialization functions in the current shared object.

Termination functions are started from the atexit() handlers after the custom atexit() handlers. The completion functions are executed in the reverse order of their respective initialization functions.

The ELF standard states the following:

The dynamic linker ensures that it will not perform any initialization or completion functions more than once.

If you see otherwise, then this is a mistake.

+5
source

All Articles