Why is this the case?
Most linkers (AIX linker is a notable exception) discard information in the process of linking.
For example, suppose you have foo.o
with foo
in it, and bar.o
with bar
in it. Suppose foo
calls bar
.
After you link foo.o
and bar.o
together into a shared library, the linker merges code and data sections, and resolves references. The call from foo
to bar
becomes CALL $relative_offset
. After this operation, you can no longer tell where the boundary between code that came from foo.o
and code that came from bar.o
was, nor the name that CALL $relative_offset
used in foo.o
-- the relocation entry has been discarded.
Suppose now you want to link foobar.so
with your main.o
statically, and suppose main.o
already defines its own bar
.
If you had libfoobar.a
, that would be trivial: the linker would pull foo.o
from the archive, would not use bar.o
from the archive, and resolve the call from foo.o
to bar
from main.o
.
But it should be clear that none of above is possible with foobar.so
-- the call has already been resolved to the other bar
, and you can't discard code that came from bar.o
because you don't know where that code is.
On AIX it's possible (or at least it used to be possible 10 years ago) to "unlink" a shared library and turn it back into an archive, which could then be linked statically into a different shared library or a main executable.
If foo.o
and bar.o
are linked into a foobar.so
, wouldn't it make sense that the call from foo
to bar
is always resolved to the one in bar.o
?
This is one place where UNIX shared libraries work very differently from Windows DLLs. On UNIX (under common conditions), the call from foo
to bar
will resolve to the bar
in main executable.
This allows one to e.g. implement malloc
and free
in the main a.out
, and have all calls to malloc
use that one heap implementation consistently. On Windows you would have to always keep track of "which heap implementation did this memory come from".
The UNIX model is not without disadvantages though, as the shared library is not a self-contained mostly hermetic unit (unlike a Windows DLL).
Why would you want to resolve it to another bar
from main.o
?
If you don't resolve the call to main.o
, you end up with a totally different program, compared to linking against libfoobar.a
.