diff --git a/default.nix b/default.nix index 71d1a80a..00ec5b61 100644 --- a/default.nix +++ b/default.nix @@ -1,3 +1,3 @@ -(import (fetchTarball https://github.com/edolstra/flake-compat/archive/master.tar.gz) { +(import (fetchTarball "https://github.com/edolstra/flake-compat/archive/master.tar.gz") { src = ./.; }).defaultNix diff --git a/src/patchelf.cc b/src/patchelf.cc index 66d0b99a..a030387d 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -1477,8 +1477,13 @@ std::string ElfFile::shrinkRPath(char* rpath, std::vector neededLibFound(neededLibs.size(), false); std::string newRPath = ""; + std::set componentsConsidered; for (auto & dirName : splitColonDelimitedString(rpath)) { + if (componentsConsidered.find(dirName) != componentsConsidered.end()) { + continue; + } + componentsConsidered.insert(dirName); /* Non-absolute entries are allowed (e.g., the special "$ORIGIN" hack). */ @@ -1617,6 +1622,14 @@ void ElfFile::modifyRPath(RPathOp op, break; } case rpSet: { break; } /* new rpath was provied as input to this function */ + case rpShrinkAndAdd: { + auto temp = std::string(rpath ? rpath : ""); + appendRPath(temp, newRPath); + newRPath = temp; + char * newRPathCStr = const_cast(newRPath.c_str()); + newRPath = shrinkRPath(newRPathCStr, neededLibs, allowedRpathPrefixes); + break; + } } if (!forceRPath && dynRPath && !dynRunPath) { /* convert DT_RPATH to DT_RUNPATH */ @@ -2419,7 +2432,9 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con else if (setExecstack) elfFile.modifyExecstack(ElfFile::ExecstackMode::set); - if (shrinkRPath) + if (shrinkRPath && addRPath) + elfFile.modifyRPath(elfFile.rpShrinkAndAdd, allowedRpathPrefixes, newRPath); + else if (shrinkRPath) elfFile.modifyRPath(elfFile.rpShrink, allowedRpathPrefixes, ""); else if (removeRPath) elfFile.modifyRPath(elfFile.rpRemove, {}, ""); @@ -2567,6 +2582,12 @@ static int mainWrapped(int argc, char * * argv) if (++i == argc) error("missing argument"); allowedRpathPrefixes = splitColonDelimitedString(argv[i]); } + else if (arg == "--add-rpath-and-shrink") { + if (++i == argc) error("missing argument"); + addRPath = true; + newRPath = resolveArgument(argv[i]); + shrinkRPath = true; + } else if (arg == "--set-rpath") { if (++i == argc) error("missing argument"); setRPath = true; diff --git a/src/patchelf.h b/src/patchelf.h index 4e229d67..dcc5bbf7 100644 --- a/src/patchelf.h +++ b/src/patchelf.h @@ -149,7 +149,7 @@ class ElfFile void setInterpreter(const std::string & newInterpreter); - typedef enum { rpPrint, rpShrink, rpSet, rpAdd, rpRemove } RPathOp; + typedef enum { rpPrint, rpShrink, rpSet, rpAdd, rpRemove, rpShrinkAndAdd } RPathOp; void modifyRPath(RPathOp op, const std::vector & allowedRpathPrefixes, std::string newRPath); std::string shrinkRPath(char* rpath, std::vector &neededLibs, const std::vector & allowedRpathPrefixes);