C++ Linux Double Destruction of Static Variable. Linking Symbols Overlap

c++ linux double destruction of static variable. linking symbols overlap

OK, I have found solution:

http://gcc.gnu.org/wiki/Visibility

For example if change

static CTest test;

to

__attribute__ ((visibility ("hidden"))) static CTest test;

problem will gone.
Linux:

CTest() this=-1646158468
CTest() this=6296196
use
use
~CTest() this=6296196, is Alive
~CTest() this=-1646158468, is Alive

nm output before fix was:

0000000000200dd4 B _ZN5CTest4testE

after fix:

0000000000200d7c b _ZN5CTest4testE

Difference is changed global symbol "B" to local symbol "b".

Instead of adding "attribute ((visibility ("hidden")))" to symbols, it is possible to use compiler option "-fvisibility=hidden". That option makes gcc to behave much more like Windows env.

Static variable is initialized twice

You are including libA.a into libB.so. By doing this, both libB.so and libA.a contain ClassA.o, which defines the static member.

In the link order you specified, the linker pulls in ClassA.o from the static library libA.a, so ClassA.o initialization code is run before main(). When the first function in the dynamic libB.so is accessed, all initializers for libB.so are run. Since libB.so includes ClassA.o, ClassA.o's static initializer must be run (again).

Possible fixes:

  1. Don't put ClassA.o into both libA.a and libB.so.

    g++ -shared -o libB.so ClassB.o
  2. Don't use both libraries; libA.a is not needed.

    g++ -o test Test.cpp libB.so

Applying either of the above fixes the problem:

ClassA::ClassA() this=0x600e58
main()
ClassA::test() this=0x600e58
ClassB::ClassB() this=0x7fff1a69f0cf
ClassB::test() this=0x7fff1a69f0cf
ClassB::test: call staticA.test()
ClassA::test() this=0x600e58
main: END
ClassB::~ClassB() this=0x7fff1a69f0cf
ClassA::~ClassA() this=0x600e58

C global static variable initialization is done by linker?

The value 0000000000000000 (in object file f1.o) is a relative address (of the static variable), so is an offset, and that file also contains relocation directives related to it. The code for getting the argument x to print has also some relocation on it (on some load machine instruction).

In that object file you probably have a .data section. That section should start with a word (having the 0 offset you observed in f1.o) containing 10.

Read much more about linkers (I recommend Levine's Linkers and loaders book). The linking process (to get the ELF executable) is processing relocation directives. Read also more about the ELF format, starting with elf(5) (after having read the ELF wikipage). Study also the ABI specifications (for Linux x86-64 see here from this answer) which details possible relocation directives.

You may want to compile your f1.c with gcc -Wall -S -fverbose-asm -O1 f1.c then look at the emitted assembler file f1.s

You may also want to inspect the object file f1.o and the ELF executable a.out with various tools like readelf(1) and objdump(1). Both accept numerous options (notably the -r option to objdump to show relocation directives).

Dynamic linking (of the C standard library libc.*.so) introduces some additional complexity in the ELF executable. See also ld-linux(8) (which does some linking job at start of runtime) and vdso(7). You may also want to read Drepper's How To Write Shared Libraries paper.

The freely available textbook Operating Systems: Three Easy Pieces could also be worthwhile to read (it explains what a process is and how its execution proceeds).

new returns NULL when initializing static global variable in windows?

are you sure its returning null. It might be the whole static initializer thing. The order of static initializer invocations is not defined from file to file. If you have static code that is using rlog_verbose then gRootCHannel might well be NULL simply because the initializer hasn't been called yet.



Related Topics



Leave a reply



Submit