Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ compilation static variable and shared objects

Description :

a. Class X contains a static private data member ptr and static public function member getptr()/setptr().
In X.cpp, the ptr is set to NULL.

b. libXYZ.so (shared object) contains the object of class X (i.e libXYZ.so contains X.o).

c. libVWX.so (shared object) contains the object of class X (i.e libVWX.so contains X.o).

d. Executable a.exe contains X.cpp as part of translation units and finally is linked to libXYZ.so, libVWX.so

PS:
1. There are no user namespaces involved in any of the classes.
2. The libraries and executable contain many other classes also.
3. no dlopen() has been done. All libraries are linked during compile time using -L and -l flags.

Problem Statement:

  1. When compiling and linking a.exe with other libraries (i.e libXYZ.so and libVWX.so), I expected a linker error (conflict/occurance of same symbol multiple times) but did not get one.

  2. When the program was executed - the behavior was strange in SUSE 10 Linux and HP-UX 11 IA64.
    In Linux, when execution flow was pushed across all the objects in different libraries, the effect was registered in only one copy of X.
    In HPUX, when execution flow was pushed across all the objects in different libraries, the effect was registered in 3 differnt copies of X (2 belonging to each libraries and 1 for executable)

PS : I mean during running the program, the flow did passed thourgh multiple objects belonging to a.exe, libXYZ.so and libVWX.so) which interacted with static pointer belonging to X.

Question:

  • Is Expecting linker error not correct? Since two compilers passed through compilation silently, May be there is a standard rule in case of this type of scenario which I am missing. If so, Please let me know the same.
  • How does the compiler (gcc in Linux and aCC in HPUX) decide how many copies of X to keep in the final executable and refer them in such scenarios.
  • Is there any flag supported by gcc and aCC which will warn/stop compilation to the users in these kind of scenarios?

Thanks for your help in advance.

like image 879
kumar_m_kiran Avatar asked Feb 26 '26 06:02

kumar_m_kiran


1 Answers

I'm not too sure that I've completely understood the scenario. However, the default behavior on loading dynamic objects under Linux (and other Unices) is to make all symbols in the library available, and to only use the first encountered. Thus, if you both libXYZ.so and libVWX.so contain a symbol X::ourData, it is not an error; if you load them in that order, libVWX.so will use the X::ourData from libXYZ.so, instead of its own. Logically, this is a lot like a template definition in a header: the compiler chooses one, more or less by chance, and if any of the definitions is not the same as all of the others, it's undefined behavior. This behavior can be overridden by passing the flag RTLD_LOCAL to dlopen.

With regards to your questions:

  • The linker is simply implementing the default behavior of dlopen (that which you get when the system loads the library implicitely). Thus, no error (but the logical equivalent of undefined behavior if any of the definitions isn't the same).

  • The compiler doesn't decide. The decision is made when the .so is loaded, depending on whether you specify RTLD_GLOBAL or RTLD_LOCAL when calling dlopen. When the runtime calls dlopen implicitly, to resolve a dependency, it will use RTLD_GLOBAL if this occurs when loading the main executable, and what ever was used to load the library when the dependency comes from a library. (This means, of course, that RTLD_GLOBAL will propagate until you invoke dlopen explicitly.)

like image 119
James Kanze Avatar answered Feb 27 '26 20:02

James Kanze