The musl C library has only an approximative implementation of symbol versioning. This can result in symbols being bound together that have different symbol versions, something which would not happen in a full implementation. Projects which expect to be built with musl are therefore better off with avoiding symbol versioning altogether. (Not supporting symbol versioning is by itself not necessarily a bad choice for a toolchain; it all depends on the target audience.)
However, the Alpine Linux toolchain compiles binutils with full symbol versioning support: GAS suppports the .symver
directive, and the link editor handles version scripts and assigns symbol versions (just as it would on GNU/Linux). A simple compiler/assembler or linker check shows that symbol versioning is supported. As a result, some of the shared objects which Alpine Linux includes in the distribution do in fact use symbol versioning, although the musl dynamic loader will ignore this data. (The data just bloats the binaries.)
In some cases, software fails to run (after building just fine) because it uses compatibility symbols (symbols without a default version) in ways that are not supported by the musl dynamic linker. Here's a small example of what does not work:
cat > symver.c <<EOF
void
compat_function (void)
{
}
__asm__ (".symver compat_function,compat_function@SYMVER");
void
call_compat_function (void)
{
return compat_function ();
}
EOF
echo "SYMVER { };" > symver.map
cat > main.c <<EOF
extern void call_compat_function (void);
int
main (void)
{
call_compat_function ();
}
EOF
gcc -fpic -shared -o symver.so -Wl,--version-script=symver.map symver.c
gcc -Wl,--rpath=. -o main main.c symver.so
./main
Execution fails with Error relocating ./symver.so: compat_function: symbol not found
. It runs successfully without the .symver
directive.
How is this combination of binutils support for symbol versioning in combination with a dynamic linker that does not support it supposed to work in practice? Should projects check for a *-musl
target triplet and disable symbol versioning?
A run-time check for dynamic linker support would do the job, but it would break cross-compiling. Should this be fixed in Alpine Linux itself, by disabling symbol versioning support in binutils?