Dynamically Loading Static Library

dynamically loading static library?

A static library is more or less just a collection of object files. If you want to use a static library in a program, you have to link the executable with it. The executable will then contain the static library (or the parts that you used).

If you want to load a static library at runtime using dlopen, you will have to first create a dynamic library libfoo.so containing it.

Is the static loading of shared libraries linked like dynamic loading or static linking?

When you do static loading and dynamic linking of a shared library

You don't do 'static loading' of a shared library.

Even though it looks to you as an end-user that e.g. libc.so.6 is 'static loaded' at process startup, it is not in fact the case. Rather, the kernel 'static loads' the main binary and ld-linux.so, and then ld-linux dynamic loads all the other shared libraries.

does this linking patch my binary's references like in the static loading & linking scenario, or does it work by way of function pointers like in the case of dynamic loading

It depends.

Usually shared libraries are linked from position-independent code (PIC), and work the way of function pointers (the pointers are stored in the GOT -- global offset table).

But sometimes shared libraries are linked from non-PIC code, and require "text relocations", which work similar to "static linking".

Why cant you statically link dynamic libraries?

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.

segfault after linking static library into both exe and shared lib

So it seems like there are two copies of the global static variable?

Yes, that is expected.

Shouldn't the executable override the symbol from shared library so there is only one global static variable in the executable during dynamic linking?

A static variable by definition has local linkage -- it is not accessible from any other compilation unit, and is not exported from the shared library(ies).

You would have to make this variable (and any other similar variables) non-static and exported from both shared libraries. Only then will the dynamic loader bind all references to this variable to a single instance.

Note that linking separate copies of libglib-2.0.a into shared libraries without controlling symbol visibility is asking for trouble. Whatever you hoped to achieve by doing that, you are not achieving.

there is another executable that does the same as above, which seems to behave okay

Ah, programming by coincidence. The mine you stepped on didn't explode, so it should be ok to continue doing that.



Related Topics



Leave a reply



Submit