I have two questions highlighted below. I'm using 64-bit Linux.
I saw on another post that MUSL
was mentioned as a libc
implementation.
I tried using this with the following Hello world assembly program that uses two libc
functions, write
and _exit
.
.data
hello:
.ascii "Hello, world\n"
.text
.globl _start
_start:
movl $13, %edx
movl $hello, %esi
movl $1, %edi
call write
movl $0, %edi
call _exit
I assembled the code with:
# Command 1
$ as -o hello.o hello.s
I then ran ld
to generate an executable that statically links MUSL
libc
.
# Command 2
$ ld hello.o /usr/lib/x86_64-linux-musl/libc.a
That generated an a.out
file that works as expected, outputting "Hello, world" when executed.
I also tried a different invocation of the preceding ld
command, using -static -lc
instead of specifying the path directly, and also using -L
to give the path to MUSL
so that glibc
is not used, since the latter is already on ld
's search path.
# Command 3
$ ld hello.o -L/usr/lib/x86_64-linux-musl/ -static -lc
That worked as expected.
Next I tried to dynamically link MUSL
libc
.
# Command 4
$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 hello.o \
/usr/lib/x86_64-linux-musl/libc.so
That appears to work as expected. I can run a.out
, and calling ldd
on a.out
shows that MUSL
's libc
is linked.
Lastly, I tried an analogous modification relative to the statically linked version earlier, using -lc
and -L
instead of specifying the path to the .so
file directly.
# Command 5
$ ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 hello.o \
-L/usr/lib/x86_64-linux-musl -lc
The program does not run properly, outputting the error:
bash: ./a.out: No such file or directory
When I run that same ld
command with the --verbose
flag, the output is the same as when passing --verbose
to the earlier ld
command (Command 4
that generated a working executable).
Running ldd
on a.out
also outputs an error:
./a.out: error while loading shared libraries: /usr/lib/x86_64-linux-gnu/libc.so: invalid ELF header
Question 1: Why does calling ld
with -L
and -lc
in this case not match the behavior from earlier, where I specified the .so
file directly?
I noticed that if I change the specified dynamic linker to /lib/ld-musl-x86_64.so.1
, the generated a.out
runs as expected.
# Command 6
$ ld -dynamic-linker /lib/ld-musl-x86_64.so.1 hello.o \
-L/usr/lib/x86_64-linux-musl -lc
However, calling ldd
on the generated a.out
produces the following error, which was not the case earlier when I did not use -lc
and -L
in Command 4
:
./a.out: error while loading shared libraries: /usr/lib/x86_64-linux-gnu/libc.so: invalid ELF header
Question 2: Why does ld
fail on this binary, but worked earlier when I passed the path of the .so
file to ldd
and used a different dynamic linker?
The problem I encountered was due to using -L
with the linker, but not having that path available for loading libc.so
at runtime.
I noticed this by calling readelf --dynamic --program-headers
on the programs generated by Command 4
and Command 5
.
# Command 4
0x0000000000000001 (NEEDED) Shared library: [/usr/lib/x86_64-linux-musl/libc.so]
# Command 5
0x0000000000000001 (NEEDED) Shared library: [libc.so]
I was able to resolve the issue for the program generated by Command 5
by using an environment variable, LD_LIBRARY_PATH=/usr/lib/x86_64-linux-musl
, when running the program, or alternatively by passing an extra argument to ld
, -rpath /usr/lib/x86_64-linux-musl
.