Relative-to-executable path to ld-linux dynamic linker/interpreter

孤街浪徒 提交于 2019-12-23 22:29:07

问题


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:

  1. The $ORIGIN trick does not work
  2. 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)
  3. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!