C++-Konstruktor in *.a und *.so

21/03/2016 - 17:57 von Stefan Reuther | Report spam
Hallo,

ein Kollege überraschte mich mit der Beobachtung, dass in einer
bestimmten Konstellation ein globaler Konstruktor mehrfach aufgerufen
wird. Konkret entstand das aus einer recht komplexen Hierarchie von
teilweise statischen, teilweise dynamischen Libraries, wobei eine
Objektdatei einmal über eine *.so, einmal über eine *.a ins Programm kam.

Minimal-Reproduktionsfall:
-
$ head so.cpp user.cpp
==> so.cpp <=#include <stdio.h>
struct foo {
foo() { printf("hello from %p", this); }
};
foo the_foo;

==> user.cpp <=#include <stdio.h>
class foo;
extern foo the_foo;
int main()
{
printf("%p", &the_foo);
}
$ gcc -fPIC -shared -o so.so so.cpp
$ g++ user.cpp so.cpp so.so
$ LD_LIBRARY_PATH=. ./a.out
hello from 0x804a01c
hello from 0x804a01c
0x804a01c
-

Nun gibt sich ja eigentlich der Unix-Linker im Normalfall viel Mühe,
dynamisches und statisches Linken gleich aussehen zu lassen, und hat im
demonstrierten Fall ja z.B. das Symbol 'the_foo' der *.so auch durch das
Symbol der a.out ersetzt. Dass er die Konstruktoren nicht auch
zusammenfasst überrascht mich trotz Kenntnis der ELF-Innereien ein wenig.

Gibt es einen Trick, wie man diesen Fehler wegbekommt?


Stefan
 

Lesen sie die antworten

#1 Marcel Mueller
21/03/2016 - 19:56 | Warnen spam
On 21.03.16 17.57, Stefan Reuther wrote:
ein Kollege überraschte mich mit der Beobachtung, dass in einer
bestimmten Konstellation ein globaler Konstruktor mehrfach aufgerufen
wird. Konkret entstand das aus einer recht komplexen Hierarchie von
teilweise statischen, teilweise dynamischen Libraries, wobei eine
Objektdatei einmal über eine *.so, einmal über eine *.a ins Programm kam.



Wenn Du dieselbe Objektdatei zweimal in ein Programm packst, gibt es
auch alle statischen Variablen darin mehrfach.


Nun gibt sich ja eigentlich der Unix-Linker im Normalfall viel Mühe,
dynamisches und statisches Linken gleich aussehen zu lassen, und hat im
demonstrierten Fall ja z.B. das Symbol 'the_foo' der *.so auch durch das
Symbol der a.out ersetzt. Dass er die Konstruktoren nicht auch
zusammenfasst überrascht mich trotz Kenntnis der ELF-Innereien ein wenig.

Gibt es einen Trick, wie man diesen Fehler wegbekommt?



Entweder eine Klasse bzw. ein Objektmodul nur ausschließlich in /einem/
Binàrobjekt nutzen, oder alles gemeinsam genutzte /immer/ in Shared
Libraries packen. Alles andere geht früher oder spàter schief. Das wàre
auch eine Verletzung der C++ ODR. Wobei C++ und Shared Libraries sowieso
so eine Sache ist. Es gibt zumindest keine garantierte Kompatibilitàt
zwischen verschiedenen Compilern und Versionen.


Marcel

Ähnliche fragen