Can I change 'rpath' in an already compiled binary?
Solution 1
There is a tool called chrpath
which can do this - it's probably available in your distribution's packages.
Solution 2
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 3
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 avoided -
RUNPATH
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
Related videos on Youtube
Rich Homolka
Updated on September 25, 2021Comments
-
Rich Homolka over 2 years
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?
-
wildplasser over 11 yearsWrap it into a shellscript that sets LD_LIBRARY_PATH and calls the binary. Put the shell script in a place that is in the callers's PATH.
-
Will almost 8 yearsLD_LIBRARY_PATH is inherited by child processes. You might not want that.
-
Rich Homolka almost 8 years@will yeah that and I already said I don't want to do that. :)
-
-
maxschlepzig over 10 yearsEspecially,
patchelf
is able to add an rpath to a binary that does not contain an rpath, yet - wherechrpath
only seem to be able to modify an already present entry. -
Stuart Berg almost 10 yearsAs a general note, it's worth understanding the subtle distinction between
rpath
andrunpath
. Basically, one can overrideLD_LIBRARY_PATH
and the other can't. For details, see blog.tremily.us/posts/rpath -
Stuart Berg almost 10 yearsThe annoying thing is that both
chrpath
andpatchelf
are sloppy with their terminology. For example, thepatchelf
command shown above will changerunpath
but notrpath
unless you also provide the--force-rpath
option. -
user7610 almost 10 years@superbatfish Yes, but the difference usually doesn't matter. This entry from the CHANGELOG of
patchelf
explains it: "--set-rpath
,--shrink-rpath
and--print-rpath
now preferDT_RUNPATH
overDT_RPATH
, which is obsolete. When updating, if both are present, both are updated. If only DT_RPATH is present, it is converted toDT_RUNPATH
unless--force-rpath
is specified. If neither is present, aDT_RUNPATH
is added unless--force-rpath
is specified, in which case aDT_RPATH
is added." The name of the option was probably kept unchanged for compatibility reasons. -
Andrew Hundt over 8 yearsHow do you add more than one?
-
user7610 over 8 years@AndrewHundt Path separator on UNIX is a colon. See examples at nixos.org/patchelf.html.
patchelf --set-rpath /opt/my-libs/lib:/foo/lib program
This causes the dynamic linker to search in /opt/my-libs/lib and /foo/lib for the shared libraries needed by program.` -
don bright over 8 yearsthis is so good. i am experimenting with running it on a bunch of .so files and a binary executable. i can go ubuntu -> debian -> fedora with no problem so far.
-
Kevin Tonon over 8 yearsJust a note for mac users,
install_name_tool
can do this with the-rpath
flag -
Kenneth Hoste over 8 yearsBy far the best answer, this should be the accepted answer instead!
-
Konstantin Burlachenko almost 8 yearsWhat does $ORIGIN mean?
-
user7610 almost 8 years@bruziuz
$ORIGIN
expands to the directory containing the program or shared object. Expansion happens when you execute the binary, not when you runpatchel
. To prevent shell expansion when running patchelf, the rpath is single quoted. It's explained in man pages. man7.org/linux/man-pages/man8/ld.so.8.html -
phyatt over 6 yearsIf you get the error:
<binary>: no rpath or runpath tag found.
, you can't usechrpath
to replace it, but you can usepatchelf
in this case:patchelf --set-rpath /path/to/libaries <binary>
-
taranaki over 5 yearsI prefer chrpath if possible since, while it's more universal, patchelf has some long standing bug that dramatically inflates the size of your libraries/executables.
-
jww about 5 years
-Wl,-R,<desired-rpath> -Wl,--enable-new-dtags
setsDT_RUNPATH
, and that is the one most folks should use.RUNPATH
can be overridden byLD_LIBRARY_PATH
, so folks should not use--force-rpath
. -
Daniel Trugman about 5 years@jww I see that I didn't add a comment about the deprecation of RPATH, so I added one just now. Thanks!
-
Alan De Smet over 4 yearsNote that the example
<desired-path>
uses a colon; it should be a comma (that is:/my/libs,/my/other/libs
). -
Daniel Trugman over 4 years@AlanDeSmet, I don't know about the comma, but the colon works for me.
-
hagello over 3 years@taranaki: Which version of patchelf are you talking about?
-
hagello over 3 yearschrpath has got a severe limitation: it can only replace an RPATH with one of equal or shorter length (man page of rpath version 0.16)
-
taranaki over 3 years@hagello I don't remember, and it may be fixed by now.
-
Rob over 3 yearsRPATH might be deprecated, but using RUNPATH can lead to "unexpected" corner cases. See, for example, qt.io/blog/2011/10/28/rpath-and-runpath .
-
hagello over 3 yearsRecently, I encountered a trap when using
$ORIGIN
and symbolic links to shared libraries: Be aware that$ORIGIN
denotes the directory of the symbolic link, which is not necessarily the directory containing the program of shared library (yes, I'm talking to you, @user7610). The lesson is: If you want to use symbolic links to shared libraries, try to keep both in the same directory. Else you have to usepatchelf --set-rpath
orLD_LIBRARY_PATH
. (At least for my version of the dynamic linker.) -
CristiFati over 2 years"... colon (not comma) separated ...".