In the section "Is musl compatible with glibc?" the musl
FAQ states that:
Binary compatibility is much more limited, but it will steadily increase with new versions of musl. At present, some glibc-linked shared libraries can be loaded with musl, but all but the simplest glibc-linked applications will fail if musl is dropped-in in place of /lib/ld-linux.so.2.
How can I make this more tractable in terms of functions and definitions that I can use, and compiler or linker options that I need to set to get this compatibility.
What is an example of "all but the simplest" applications? Is there actually some minimal (possibly only academic) scenario that I can construct, where I build a C binary that has shared linkage against libc and which works both with glibc and musl?
Or in other words, can I construct some minimal C binary that uses at least one function from libc, is not statically linked, and that I can drop into both a Debian and Alpine environment and it will be able to start?
This is mainly an academic exercise to help me understand the differences between both libraries.
Somehow I am having a hard time accepting, that it should be easier to create a portable POSIX shell script than a portable C application.
2
Answers
Not a
C
binary. Your binary just can’t use anything from GLIBC, and aC
binary will use at leastcrt0.o
.You can however construct such binary in assembly. E.g. a binary built from this source and using
nasm
wouldn’t care whether it’s linked statically or dynamically.
On the other hand, a binary built from this source:
is not guaranteed to work.
What’s the difference? The first binary will not have
crt0.o
linked into it, and should work fine when linked dynamically so long aslibc.so
itself initializes correctly.I played a bit more and got a binary that works on my Gentoo machine and an Alpine docker container. It required (in Alpine) creating symlinks to the dynamic loader and libc using the names expected by my Gentoo system (
/lib64/ld-linux-x86-64.so.2
and/lib64/libc.so.6
), but my test program worked as expected:I can probably get a program compiled in Alpine to work on Gentoo as well, but I haven’t played with the symlinks yet. I also tested a program that claims to implement producers consumers, and that appears to work as well.
As for the limits of what will work, I suspect that’s going to depend a lot on each libc. If glibc changes
pthread_create
to be a macro directly calling something else, I think that’s legal but that would cause issues with musl binary compatibility.I’m not sure you can do this with any generic enviornment and dynamic linkage, even with clever use of
LD_PRELOAD
(didn’t test this too heavily though). And as a practical matter, I suspect far fewer problems just compling one version against glibc, and another against musl.