When using external libraries, you often have to decide whether you use the static or the dynamic version of the library. Typically, you can not exchange them: If the library is build as dynamic library, you can not link statically against it.
Why is this the case?
Example: I am building a C++ program on windows and use a library that provides a small .lib
file for the linker and a large .dll
file that must be present when running my executable. If the library code in the .dll
can be resolved at runtime, why can't it be resolved at compile time and directly put into my executable?
When you want to “link a static library with dynamic library”, you really want to include the symbols defined in the static library as a part of the dynamic library, so that the run-time linker gets the symbols when it is loading the dynamic library.
The major disadvantages of static linking are increases in the memory required to run an executable, network bandwidth to transfer it, and disk space to store it.
By using dynamic linking, you can upgrade the routines in the shared libraries without relinking. This form of linking is the default and no additional options are needed. Static linking means that the code for all routines called by your program becomes part of the executable file.
Dynamic linking has the following advantages over static linking: Multiple processes that load the same DLL at the same base address share a single copy of the DLL in physical memory. Doing this saves system memory and reduces swapping.
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
andbar.o
are linked into afoobar.so
, wouldn't it make sense that the call fromfoo
tobar
is always resolved to the one inbar.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
frommain.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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With