Dynamic linking without libc adventures

Sorry for the delay, I didn’t notice the latest replies.

Good to know (it is the path I chose to go for). It should be noted that I cannot spend more than a few hours a week on this, so please don’t expect anything in the short term. All of this is mostly an experiment.

I tried that, but the final executable ends up with no INTERP header set. I can see the --dynamic-linker /lib64/ld-linux-x86-64.so.2 flag passed to zig build-exe, but not to the subsequent ld.lld call. I did not investigate why, though.

The project’s goals have shifted a bit, and I decided to focus on implementing dlopen functionality from static position-independent executables on x86_64-linux. I can take advantage of the fact that in this case, I can prepare execution if I need to, as initialization is in zig space (cf. std.os.linux.pie.relocate and std.os.linux.tls.initStatic calls in lib/std/start.zig).


Some notes:

  • Dynamically loading shared libraries from a static executable is NOT a good idea. The first thing to try when you feel the need to do that is probably to statically compile everything needed. But what do you do if you want to use OpenGL or Vulkan? You have no choice but to use the system-provided dynamic libraries which come with graphic drivers. I believe the same can be said as soon as hardware drivers are involved. That’s why today my main test case is a simple program that uses OpenGL with GLFW.

  • Dynamic libraries will likely require the system’s libc. If the main executable also bundles libc (a static one like musl), a lot of care will need to be taken. Everything shared between dynamic libraries (and shared between the main executable and a dynamic library) should be carefully handled to not break any convention. This includes, for example, thread-local storage, static things like brk in malloc implementations, etc. I believe analyzing libraries and symbols loaded when the custom dlopen implementation is called and making smart decisions when doing relocations can help circumvent those difficulties. As I already can parse, load, and (almost) relocate dynamic libraries and their dependencies recursively, this is where I basically am today. My first milestone is to make my specific test case work.

  • For reference, here is a post closely related to this one (at least in terms of goals): Loading `libvulkan.so.1` on Linux with `std.ElfDynLib`, and an old discussion I found while researching this topic: static linking and dlopen