To answer the 2 questions left
1) when and how the linking is done?2) who calls the constructor and destructor?
It took me a long journey to exploring the ELF, dynamic linking, PIC, GOT, ...
Quite an interesting journey, and I find Eli Bendersky's Website, who is obviously have the most clear description of PIC within all the material I've read in web, he wrote a lot of blog in a wide range and play with "Project Euler" like me :), It worth a read, very pleasant reading, of his blog on PIC (Position Independent Code)
Another learning source is:
I will only try to explain a bit concern with this double delete problem.
1) when and how the linking is done?
In our case, link is done via dynamic linking
Static Link:
Everything is address, e.g. functions, variables, in binary, link 2 binary will cause address shift then need "relocation" to make the code workNote, binary has different segment for different purpose, e.g. .text for code and .data for data
![]()
Dynamic link:
It's a different story in dynamic link code do not need relocation, it can simply executed wherever it's loaded, this is so called PIC, position independent code, and it's because
- extra layer of address indirection- address in code are all relative address
That is Address in .text are referenced to .got, and .got point to the real address need to be accessed
.text - code.got - global offset table.bss - memory allocated for data
To determine the address of global variable in .bss, linker/loader need a symbol table for help, which is a collection of symbol table from all shared library to load
The symbol table is a hash table with symbols of same hash key listed after the key in table
And to resolve a symbol, it search the symbol from this hash table and find the first one matched
Thus, when loading 2 shared library with global object of the same name, the 2 object are pointed to the same address as the same symbol obviously has the same hash value
2) who calls the constructor and distructor
well there are 2 additional segment in shared library of C++ program to construct and destruct the global object.init.finitset LD_DEBUG will help us have a clear view of this
setenv LD_DEBUG libs./testAnd we will have following output
====================================9598: calling init: ./libsub2.so
9598:
Object::Object, this = 0x8049aa0; buffer = 157999112
9598:
9598: calling init: ./libsub1.so
9598:
Object::Object, this = 0x8049aa0; buffer = 157999128
9598:
9598: initialize program: ./test
9598:
9598:
9598: transferring control: ./test
9598:
Hello World
9598:
9598: calling fini: ./test [0]
9598:
9598:
9598: calling fini: ./libsub1.so [0]
9598:
Object::~Object, this = 0x8049aa0; buffer = 157999128
9598:
9598: calling fini: ./libsub2.so [0]