summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2008-05-27 16:23:21 (GMT)
committerEelco Dolstra <e.dolstra@tudelft.nl>2008-05-27 16:23:21 (GMT)
commit704c22c6a8fc49a902b3b29636f7b78af97124a6 (patch)
tree2ee68ba82b2641110fe3af5cc416d9d348f26998
parent53f7311089de2dc767e20f1420c8118561b7a458 (diff)
downloadpatchelf-704c22c6a8fc49a902b3b29636f7b78af97124a6.zip
patchelf-704c22c6a8fc49a902b3b29636f7b78af97124a6.tar.gz
patchelf-704c22c6a8fc49a902b3b29636f7b78af97124a6.tar.bz2
* Support DT_RUNPATH (in fact, prefer DT_RUNPATH over DT_RPATH unless
--force-rpath is set).
-rw-r--r--README25
-rw-r--r--src/patchelf.cc58
-rwxr-xr-xtests/big-dynstr.sh2
-rwxr-xr-xtests/set-rpath.sh2
4 files changed, 73 insertions, 14 deletions
diff --git a/README b/README
index 73709a1..11dc16c 100644
--- a/README
+++ b/README
@@ -22,13 +22,13 @@ libraries. In particular, it can do the following:
AUTHOR
-Copyright 2004, 2005, 2006, 2007 Eelco Dolstra <eelco@cs.uu.nl>. See
-COPYING for the license.
+Copyright 2004, 2005, 2006, 2007, 2008 Eelco Dolstra <eelco@cs.uu.nl>.
+See COPYING for the license.
HOMEPAGE
-http://nix.cs.uu.nl/patchelf.html
+http://nixos.org/patchelf.html
BUGS
@@ -36,9 +36,28 @@ BUGS
Currently setting the RPATH on libraries ("--set-rpath") will usually
fail if the new RPATH is longer then the old RPATH.
+The `strip' command from binutils generated broken executables when
+applied to the output of patchelf (if `--set-rpath' or
+`--set-interpreter' with a larger path than the original is used).
+This appears to be a bug in binutils
+(http://bugs.strategoxt.org/browse/NIXPKGS-85).
+
RELEASE HISTORY
+0.4 (TBA):
+
+* IA-64 support (not tested) and related 64-bit fixes.
+
+* FreeBSD support.
+
+* `--set-rpath', `--shrink-rpath' and `--print-rpath' now prefer
+ DT_RUNPATH over DT_RPATH, which is obsolete. When updating, if both
+ are present, both are updated. If only DT_RPATH is present, it is
+ converted to DT_RUNPATH unless `--force-rpath' is specified. If
+ neither is present, a DT_RUNPATH is added unless `--force-rpath' is
+ specified, in which case a DT_RPATH is added.
+
0.3 (May 24, 2007):
* Support for 64-bit ELF binaries (such as on x86_64-linux).
diff --git a/src/patchelf.cc b/src/patchelf.cc
index 7088ca1..d8187bb 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -26,6 +26,8 @@ const unsigned int pageSize = 4096;
static bool debugMode = false;
+static bool forceRPath = false;
+
static string fileName;
@@ -715,16 +717,31 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
assert(strTabAddr == rdi(shdrDynStr.sh_addr));
- /* Walk through the dynamic section, look for the RPATH entry. */
+ /* Walk through the dynamic section, look for the RPATH/RUNPATH
+ entry.
+
+ According to the ld.so docs, DT_RPATH is obsolete, we should
+ use DT_RUNPATH. DT_RUNPATH has two advantages: it can be
+ overriden by LD_LIBRARY_PATH, and it's scoped (the DT_RUNPATH
+ for an executable or library doesn't affect the search path for
+ libraries used by it). DT_RPATH is ignored if DT_RUNPATH is
+ present. The binutils `ld' still generates only DT_RPATH,
+ unless you use its `--enable-new-dtag' option, in which case it
+ generates a DT_RPATH and DT_RUNPATH pointing at the same
+ string. */
static vector<string> neededLibs;
dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset));
- Elf_Dyn * dynRPath = 0;
- Elf_Dyn * rpathEntry = 0;
+ Elf_Dyn * dynRPath = 0, * dynRunPath = 0;
char * rpath = 0;
for ( ; rdi(dyn->d_tag) != DT_NULL; dyn++) {
if (rdi(dyn->d_tag) == DT_RPATH) {
dynRPath = dyn;
- rpathEntry = dyn;
+ /* Only use DT_RPATH if there is no DT_RUNPATH. */
+ if (!dynRunPath)
+ rpath = strTab + rdi(dyn->d_un.d_val);
+ }
+ else if (rdi(dyn->d_tag) == DT_RUNPATH) {
+ dynRunPath = dyn;
rpath = strTab + rdi(dyn->d_un.d_val);
}
else if (rdi(dyn->d_tag) == DT_NEEDED)
@@ -800,6 +817,12 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
}
debug("new rpath is `%s'\n", newRPath.c_str());
+
+ if (!forceRPath && dynRPath && !dynRunPath) { /* convert DT_RPATH to DT_RUNPATH */
+ dynRPath->d_tag = DT_RUNPATH;
+ dynRunPath = dynRPath;
+ dynRPath = 0;
+ }
if (newRPath.size() <= rpathSize) {
strcpy(rpath, newRPath.c_str());
@@ -813,12 +836,14 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
rdi(shdrDynStr.sh_size) + newRPath.size() + 1);
setSubstr(newDynStr, rdi(shdrDynStr.sh_size), newRPath + '\0');
- /* Update the DT_RPATH entry. */
- if (dynRPath)
- dynRPath->d_un.d_val = shdrDynStr.sh_size;
+ /* Update the DT_RUNPATH and DT_RPATH entries. */
+ if (dynRunPath || dynRPath) {
+ if (dynRunPath) dynRunPath->d_un.d_val = shdrDynStr.sh_size;
+ if (dynRPath) dynRPath->d_un.d_val = shdrDynStr.sh_size;
+ }
else {
- /* There is no DT_RPATH entry in the .dynamic section, so we
+ /* There is no DT_RUNPATH entry in the .dynamic section, so we
have to grow the .dynamic section. */
string & newDynamic = replaceSection(".dynamic",
rdi(shdrDynamic.sh_size) + sizeof(Elf_Dyn));
@@ -830,7 +855,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
debug("DT_NULL index is %d\n", idx);
Elf_Dyn newDyn;
- wri(newDyn.d_tag, DT_RPATH);
+ wri(newDyn.d_tag, forceRPath ? DT_RPATH : DT_RUNPATH);
newDyn.d_un.d_val = shdrDynStr.sh_size;
setSubstr(newDynamic, idx * sizeof(Elf_Dyn),
string((char *) &newDyn, sizeof(Elf_Dyn)));
@@ -923,6 +948,7 @@ int main(int argc, char * * argv)
[--set-rpath RPATH]\n\
[--shrink-rpath]\n\
[--print-rpath]\n\
+ [--force-rpath]\n\
[--debug]\n\
FILENAME\n", argv[0]);
return 1;
@@ -951,6 +977,20 @@ int main(int argc, char * * argv)
else if (arg == "--print-rpath") {
printRPath = true;
}
+ else if (arg == "--force-rpath") {
+ /* Generally we prefer to emit DT_RUNPATH instead of
+ DT_RPATH, as the latter is obsolete. However, there is
+ a slight semantic difference: DT_RUNPATH is "scoped",
+ it only affects the executable or library in question,
+ not its recursive imports. So maybe you really want to
+ force the use of DT_RPATH. That's what this option
+ does. Without it, DT_RPATH (if encountered) is
+ converted to DT_RUNPATH, and if neither is present, a
+ DT_RUNPATH is added. With it, DT_RPATH isn't converted
+ to DT_RUNPATH, and if neither is present, a DT_RPATH is
+ added. */
+ forceRPath = true;
+ }
else if (arg == "--debug") {
debugMode = true;
}
diff --git a/tests/big-dynstr.sh b/tests/big-dynstr.sh
index 9f76600..bb95366 100755
--- a/tests/big-dynstr.sh
+++ b/tests/big-dynstr.sh
@@ -11,7 +11,7 @@ cp libbar.so scratch/libsB/
oldRPath=$(../src/patchelf --print-rpath scratch/big-dynstr)
if test -z "$oldRPath"; then oldRPath="/oops"; fi
-../src/patchelf --set-rpath $oldRPath:$(pwd)/scratch/libsA:$(pwd)/scratch/libsB scratch/big-dynstr
+../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/scratch/libsA:$(pwd)/scratch/libsB scratch/big-dynstr
if test "$(uname)" = FreeBSD; then
export LD_LIBRARY_PATH=$(pwd)/scratch/libsB
diff --git a/tests/set-rpath.sh b/tests/set-rpath.sh
index b71e0f4..999acb4 100755
--- a/tests/set-rpath.sh
+++ b/tests/set-rpath.sh
@@ -11,7 +11,7 @@ cp libbar.so scratch/libsB/
oldRPath=$(../src/patchelf --print-rpath scratch/main)
if test -z "$oldRPath"; then oldRPath="/oops"; fi
-../src/patchelf --set-rpath $oldRPath:$(pwd)/scratch/libsA:$(pwd)/scratch/libsB scratch/main
+../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/scratch/libsA:$(pwd)/scratch/libsB scratch/main
#oldRPath=$(../src/patchelf --print-rpath scratch/libsA/libfoo.so)
#if test -z "$oldRPath"; then oldRPath="/oops"; fi