Can I change 'rpath' in an already compiled binary?
LinuxLinkerElfLinux Problem Overview
I have an old executable that's scheduled for the scrap heap, but it's not there yet. It relies on some libs that have been removed from my environment, but I have some stub libs someplace where it works fine. Id like to point this executable to these stub libs. Yes, i could set LD_LIBRARY_PATH, but this executable is called from many scripts, and many users and I'd love to fix it in one spot.
I don't have source for this, and would be hard to get it. I was thinking - can I edit this file, using an ELF aware editor, and add a simple PATH to rpath to have it hit the new libs? Is this possible, or once you create an ELF binary, you fix things to locations and they can't be moved?
Linux Solutions
Solution 1 - Linux
There is a more universal tool than chrpath
called patchelf
. It was originally created for use in making packages for Nix and NixOS (packaging system and a GNU/Linux distribution).
In case there is no rpath in a binary (here called rdsamp), chrpath
fails:
chrpath -r '$ORIGIN/../lib64' rdsamp
rdsamp: no rpath or runpath tag found.
On the other hand,
patchelf --set-rpath '$ORIGIN/../lib64' rdsamp
succeeds just fine.
Solution 2 - Linux
There is a tool called chrpath
which can do this - it's probably available in your distribution's packages.
Solution 3 - Linux
Just like @user7610 said, the right way to go is the patchelf
tool.
But, I feel that I can give a more comprehensive answer, covering all the commands one needs to do exactly that.
For a comprehensive article on the subject, click here
First of all, many developers talk about RPATH
, but they actually mean RUNPATH
. These are two different optional dynamic sections, and the loader handles them very differently. You can read more about the difference between them in the link I mentioned before.
For now, just remember:
- If
RUNPATH
is set,RPATH
is ignored RPATH
is deprecated and should be avoidedRUNPATH
is preferred because it can be overridden byLD_LIBRARY_PATH
See the current R[UN]PATH
readelf -d <path-to-elf> | egrep "RPATH|RUNPATH"
Clear the R[UN]PATH
patchelf --remove-rpath <path-to-elf>
Notes:
- Removes both
RPATH
andRUNPATH
Add values to R[UN]PATH
patchelf [--force-rpath] --set-rpath "<desired-rpath>" <path-to-elf>
Notes:
-
<desired-path>
is a colon separated directories list, e.g:/my/libs:/my/other/libs
-
If you specify
--force-rpath
, setsRPATH
, otherwise setsRUNPATH
Solution 4 - Linux
This worked for me, replacing XORIGIN with $ORIGIN.
chrpath -r '\$\ORIGIN/../lib64' httpd