The Holy Grail of Linux Binary Compatibility: `musl` + `dlopen`

Combining static linking with dynamic loading at runtime is a challenge because a statically linked musl libc does not support dlopen.
This problem prevents us from shipping the interpreter in our static builds (see Shipping the interpreter).

However, there appear to be workarounds. One example is explained in this post from a project that integrates the Godot Graphics engine with Golang. Golang has strong support for static linking and graphics libraries usually require dynamic libraries. So they have similar needs to make combining them possible.

This also sparked a bit of a discussion on Hacker News: The Holy Grail of Linux Binary Compatibility: Musl and Dlopen | Hacker News

So this could be a feasible alternative to Portable, dynamically linked packages on Linux - #4 by straight-shoota for shipping a statically linked interpreter with support for loading dynamic libraries.

5 Likes

Since a statically linked musl binary has no dynamic linker, standard dlopen will always fail (it’s a stub that returns NULL). The workaround is to embed a userspace ELF loader into your binary.

Most people use foreign-dlopen for this:

https://github.com/pfalcon/foreign-dlopen

It basically re-implements dlopen by manually parsing the ELF headers, mapping the library into memory, and resolving symbols itself.

Caveat: It’s hacky. You risk symbol collisions and Thread Local Storage (TLS) issues because the loaded library expects a dynamic runtime environment that your static binary doesn’t fully provide.

1 Like

There’s also GitHub - graphitemaster/detour: A detour through the Linux dynamic linker

1 Like