How do I set DT_RPATH or DT_RUNPATH?
When you are compiling a program, you create object files and then link them together. You may use GNU ld(1) to link them, there are also other linkers, LLVM linker. A linker combines object files into executable. GNU ld(1) is part of binutils with documentation available here.
When you execute an already compiled ready to use executable then the dynamic linker ld.so(8) finds the libraries on the system that the executable depends on, loads them and executes the executable. ld.so(8) is a shared library usually distributed as part of C standard library, usually on linux that's glibc, but there are also other, like musl.
I think it's confusing that both these programs are named "linker". One is like "compiling linker" and the other is "executable linker".
How do I set DT_RPATH or DT_RUNPATH?
Edit the elf file to include specific section.
When creating the elf file with GNU ld, nowadays you set RUNPATH section with -rpath=something
. You can set RPATH
section with --disable-new-dtags -rpath=something
. RPATH is deprecated, so normally -rpath
sets RUNPATH. https://www.javaer101.com/en/article/1127068.html *This does not check out on my system and I have to compile with gcc -Wl,--enable-new-dtags -Wl,-rpath=/tmp
to set RUNPATH...
You can also set sections in any ELF file after compilation. See Can I change 'rpath' in an already compiled binary?
whether they are the same as -rpath and -rpath-link?
From ld documentation:
The difference between -rpath and -rpath-link is that directories specified by -rpath options are included in the executable and used at runtime, whereas the -rpath-link option is only effective at link time.
And the documentation also explains how -rpath-link
works. It's to specify directories for searching dependent shared libraries.
Finally there is an LD_RUN_PATH environment variable
When compiling an executable GNU ld(1) also searches libraries in directories specified in this variable.
How to set RPATH and RUNPATH with GCC/LD?
Is there a way to force the old behavior?
Yes. You can use this option -Wl,--disable-new-dtags
to tell the new linker to use the old behavior, i.e. RPATH.
Is it possible to tell the old version of linker to produce the new output (i.e. RUNPATH instead of RPATH)?
Yes. Use -Wl,--enable-new-dtags
to tell the old linker to use the new behavior, i.e. RUNPATH.
I verified the executable with readelf
and these two options seem to control what will be written in the ELF Dynamic section. I think the problem was caused by a change in the defaults for the new version, although, interestingly, the manual page for ld
would suggest that it should still be the same:
--enable-new-dtags
--disable-new-dtags
This linker can create the new dynamic tags in ELF. But the older ELF systems may not understand them. If you specify
--enable-new-dtags, the new dynamic tags will be created as needed and
older dynamic tags will be omitted. If you specify --disable-new-dtags, no new dynamic tags will be created. By default, the new dynamic tags are not created. Note that those options are
only available for ELF systems.
use RPATH but not RUNPATH?
When you ship a binary, it's good to provide means for the users to accommodate the binary to the specifics of their own system, among other things, adjusting library search paths.
A user can generally tweak LD_LIBRARY_PATH
and /etc/ld.so.conf
, both of which are with lower precedence than DT_RPATH
, i.e. you can't override what is hardcoded in the binary, whereas if you use DT_RUNPATH
instead, a user can override it with LD_LIBRARY_PATH
.
(FWIW, I think ld.so.conf
should also take precedence over DT_RUNPATH
, but, anyway, at least we've got LD_LIBRARY_PATH
).
Also, I strongly disagree with the suggestion above to use DT_RPATH
. IMO, its best to use nether DT_RPATH
not DT_RUNPATH
in shipped binaries.
unless
you ship all your dependent libraries with your executables and wish to ensure that things JustWork(tm) after installation, in this case use DT_RPATH
.
Is there a way to load user library's from specific location ONLY on running the binary
The search order for dynamic libraries in Linux (from ld.so man page) is the following
- Using the DT_RPATH dynamic section attribute of the binary
if present and DT_RUNPATH attribute does not exist. Use of
DT_RPATH is deprecated.- Using the environment variable LD_LIBRARY_PATH. Except if
the executable is a setuid/setgid binary, in which case it
is ignored.- Using the DT_RUNPATH dynamic section attribute of the binary
if present.- From the cache file /etc/ld.so.cache which contains a
compiled list of candidate libraries previously found in the
augmented library path. If, however, the binary was linked
with -z nodeflib linker option, libraries in the default
library paths are skipped.
- In the default path /lib, and then /usr/lib. If the binary
was linked with -z nodeflib linker option, this step is
skipped.
When linking, to set
- DT_RUNPATH: use -Wl,--enable-new-dtags -Wl,-R$(RUNPATH)
- DT_RPATH: use -Wl,--disable-new-dtags -Wl,-R$(RPATH)
In theory, it is better to use DT_RUNPATH as the LD_LIBRARY_PATH, on which the user has a control, has precedence. But here you want to avoid the user control, so use the DT_RPATH. In you link line:
-Wl,--disable-new-dtags -Wl,-R/opt/my_prog/lib
Can I change 'rpath' in an already compiled binary?
There is a tool called chrpath
which can do this - it's probably available in your distribution's packages.
How to force .so dependency to be in same directory as library
The .dynamic
section of an ELF file (.so
libraries on Linux use ELF format) contains information to help the library find its dependencies. .dynamic
entries with type DT_NEEDED
contain the names of other .so
files for the dynamic linker to find, but they do not contain any information on where to find those files. For that, as you mentioned, you can use LD_LIBRARY_PATH
, but the ELF format also provides a way to specify it in the file itself.
A .dynamic
entry with type DT_RUNPATH
gives the dynamic linker a path to a directory where the dynamic linker should look for DT_NEEDED
files. DT_RUNPATH
allows a special variable, $ORIGIN
, which refers to the file's current directory. This allows you to use relative paths, without requiring the user to invoke an executable from a specific working directory.
You use the -rpath
linker flag to specify a DT_RUNPATH
entry. In order to pass the literal string $ORIGIN
, however, you must wrap it in single quotes to prevent your shell from interpreting it as an environment variable.
Assuming you are using gcc
, you should use add this argument to the link step:
-Wl,-rpath,'$ORIGIN'
Related Topics
Triggering Autokey Script via Mouse Button - How To
Bash: How to Traverse Directory Structure and Execute Commands
How to Do a One Way Diff in Linux
Compile Linux Kernel (2.6) Module Including Non Kernel Headers
Find Command to Find Files and Concatenate Them
Jenkins to Run Maven Build on Linux or Windows
Why Does Docker Prompt "Permission Denied" When Backing Up the Data Volume
No Error on Xcb_Grab_Key But Event Loop Not Catching (Global Hotkey)
Ldconfig Only Links Files Starting with Lib*
How Many Instructions Does Linux Kernel Need in Order to Handle an Interrupt on an Arm Cortex A9
How to Set Runpath of a Binary
How to Monitor Newly Created File in a Directory with Bash
Case in Bash: "Line 4: Syntax Error Near Unexpected Token ')'"
How to Disable Specific Warning When -Wall Is Enabled
Mod_Rewrite with Relative Path Redirects
Synchronizing Four Shell Scripts to Run One After Another in Unix