问题
I want to ship and archive binaries (executables with libraries) which are backward and forward compatible with as many Linux distributions as possible and the whole package relocatable.
As I understand system libraries like libc
also need to be shipped because the executable will crash given a different version of libc
. Meanwhile libc
seems to be coupled with ld-linux
(e.g. binaries compiled on Debian testing already does not work on Ubuntu 18.04 LTS), so I need to package ld-linux
too.
My solution is to put all executables and libraries into one directory and set rpath to $ORIGIN
(either by linking with -Wl,rpath=$ORIGIN
or setting with chrpath
or patchelf
). This makes the libraries relocatable together with the executable and works for all the libraries except ld-linux
which is the linker itself.
It is possible to change the dynamic-linker path by -Wl,--dynamic-linker=/my/path/ld-linux.so
or set it with patchelf
but the path has to be absolute:
- The
$ORIGIN
trick does not work - The relative path like
./
works but only when the current directory is the same as the loader itself (the executable crashes with errors when started from elsewhere) - I can write a shell script to detect all paths and launch the executable with
/my/path/ld-linux.so /my/path/myexecutable $@
, but it means yet another layer of indirection and overhead I would like to avoid.
Is there a way to set the path to ld-linux relative to the executable directly into executable?
Maybe there is a way to statically link the ld-linux loader?
回答1:
As I understand system libraries like libc also need to be shipped because the executable will crash given a different version of libc.
That is incorrect: GLIBC guarantees backward compatibility (an executable built on an older system will continue to work on newer versions of GLIBC).
The only sane way to achieve what you want is to compile against the oldest version of GLIBC you wish to support.
Meanwhile libc seems to be coupled with ld-linux
Correct: libc.so.6
and ld-linux
are part of GLIBC, must come from the same build, and any mismatch can lead to catastrophic failure (SIGSEGV
inside libc.so.6
, or inside ld-linux
).
I need to package ld-linux too.
That is complicated: the absolute path to ld-linux
is hard-coded into the a.out
, and can't be changed. Making a relocatable a.out
that can tolerate changes to the path to ld-linux
is impossible (short of explicit loader invocation you've already tried; which doesn't work well for executables that re-exec themselves).
Update:
I could try building on an old Ubuntu LTS and get most of backward compatibility, but then I would not get the new C++17 compilers, which basically defeats the whole point of modern software engineering.
You could install newer compiler on the older system, and get C++17 with older GLIBC.
One difficulty with that is that you may require a newer libstdc++.so.6
.
The good news is that -Wl,-rpath=$ORIGIN
works fine -- it's only GLIBC that is hard to relocate. You could also link the executable against libstdc++.a
with --static-libstdc++
.
However, there might be licensing implications in doing either (but then again your plan already included distributing all the libraries, so that issue is not new).
来源:https://stackoverflow.com/questions/54840445/relative-to-executable-path-to-ld-linux-dynamic-linker-interpreter