Why cant you statically link dynamic libraries?
Asked Answered
R

1

11

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?

Rosado answered 29/1, 2019 at 14:58 Comment(3)
It could be that way. For example, exotic mainframe OS BS2000 has a single file-format called LLM (Link and Load Module) for object modules, executables and shared libraries.Outstand
Okay. So there are formats that can be used to create a single library file that can be used for both static and dynamic linking? Why isnt it commonly used? It sounds very useful to me.Rosado
Here is one reason: on many platforms, PIC-code is less effective than non-PIC code, so for static linking you might prefer to use non-PIC code, while shared objects have to PIC (exception is Win32).Outstand
P
5

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.

Profanatory answered 31/1, 2019 at 6:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.