123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- From 618220bfb55c875d6a4d197cb24fe632ac93ec85 Mon Sep 17 00:00:00 2001
- From: Wolfgang Grandegger <wg@grandegger.com>
- Date: Mon, 20 Feb 2017 16:29:24 +0100
- Subject: [PATCH] Add option to make the rpath relative under a specified root
- directory
- Running "patchelf" with the option "--make-rpath-relative ROOTDIR" will
- modify or delete the RPATHDIRs according the following rules
- similar to Martin's patches [1] making the Buildroot toolchaing/SDK
- relocatable.
- RPATHDIR starts with "$ORIGIN":
- The original build-system already took care of setting a relative
- RPATH, resolve it and test if it's valid (does exist)
- RPATHDIR starts with ROOTDIR:
- The original build-system added some absolute RPATH (absolute on
- the build machine). Test if it's valid (does exist).
- ROOTDIR/RPATHDIR exists:
- The original build-system already took care of setting an absolute
- RPATH (absolute in the final rootfs), resolve it and test if it's
- valid (does exist).
- RPATHDIR points somewhere else:
- (can be anywhere: build trees, staging tree, host location,
- non-existing location, etc.). Just discard such a path.
- The option "--no-standard-libs" will discard RPATHDIRs ROOTDIR/lib and
- ROOTDIR/usr/lib. Like "--shrink-rpath", RPATHDIRs are also discarded
- if the directories do not contain a library referenced by the
- DT_NEEDED fields.
- If the option "--relative-to-file" is given, the rpath will start
- with "$ORIGIN" making it relative to the ELF file, otherwise an
- absolute path relative to ROOTDIR will be used.
- A pull request for a similar patch [2] for mainline inclusion is
- pending.
- [1] http://lists.busybox.net/pipermail/buildroot/2016-April/159422.html
- [2] https://github.com/NixOS/patchelf/pull/118
- Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
- ---
- src/patchelf.cc | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++------
- 1 file changed, 175 insertions(+), 21 deletions(-)
- diff --git a/src/patchelf.cc b/src/patchelf.cc
- index 1d9a772..35b4a33 100644
- --- a/src/patchelf.cc
- +++ b/src/patchelf.cc
- @@ -46,6 +46,10 @@ static bool debugMode = false;
-
- static bool forceRPath = false;
-
- +static bool noStandardLibDirs = false;
- +
- +static bool relativeToFile = false;
- +
- static string fileName;
- static int pageSize = PAGESIZE;
-
- @@ -77,6 +81,49 @@ static unsigned int getPageSize(){
- return pageSize;
- }
-
- +static bool absolutePathExists(const string & path, string & canonicalPath)
- +{
- + char *cpath = realpath(path.c_str(), NULL);
- + if (cpath) {
- + canonicalPath = cpath;
- + free(cpath);
- + return true;
- + } else {
- + return false;
- + }
- +}
- +
- +static string makePathRelative(const string & path,
- + const string & refPath)
- +{
- + string relPath = "$ORIGIN";
- + string p = path, refP = refPath;
- + size_t pos;
- +
- + /* Strip the common part of path and refPath */
- + while (true) {
- + pos = p.find_first_of('/', 1);
- + if (refP.find_first_of('/', 1) != pos)
- + break;
- + if (p.substr(0, pos) != refP.substr(0, pos))
- + break;
- + if (pos == string::npos)
- + break;
- + p = p.substr(pos);
- + refP = refP.substr(pos);
- + }
- + /* Check if both pathes are equal */
- + if (p != refP) {
- + pos = 0;
- + while (pos != string::npos) {
- + pos =refP.find_first_of('/', pos + 1);
- + relPath.append("/..");
- + }
- + relPath.append(p);
- + }
- +
- + return relPath;
- +}
-
- template<ElfFileParams>
- class ElfFile
- @@ -183,9 +230,13 @@ public:
-
- void setInterpreter(const string & newInterpreter);
-
- - typedef enum { rpPrint, rpShrink, rpSet, rpRemove } RPathOp;
- + typedef enum { rpPrint, rpShrink, rpMakeRelative, rpSet, rpRemove} RPathOp;
- +
- + bool libFoundInRPath(const string & dirName,
- + const vector<string> neededLibs,
- + vector<bool> & neededLibFound);
-
- - void modifyRPath(RPathOp op, string newRPath);
- + void modifyRPath(RPathOp op, string rootDir, string newRPath);
-
- void addNeeded(set<string> libs);
-
- @@ -1041,7 +1092,27 @@ static void concatToRPath(string & rpath, const string & path)
-
-
- template<ElfFileParams>
- -void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
- +bool ElfFile<ElfFileParamNames>::libFoundInRPath(const string & dirName,
- + const vector<string> neededLibs, vector<bool> & neededLibFound)
- +{
- + /* For each library that we haven't found yet, see if it
- + exists in this directory. */
- + bool libFound = false;
- + for (unsigned int j = 0; j < neededLibs.size(); ++j)
- + if (!neededLibFound[j]) {
- + string libName = dirName + "/" + neededLibs[j];
- + struct stat st;
- + if (stat(libName.c_str(), &st) == 0) {
- + neededLibFound[j] = true;
- + libFound = true;
- + }
- + }
- + return libFound;
- +}
- +
- +
- +template<ElfFileParams>
- +void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string rootDir, string newRPath)
- {
- Elf_Shdr & shdrDynamic = findSection(".dynamic");
-
- @@ -1096,6 +1167,11 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
- return;
- }
-
- + if (op == rpMakeRelative && !rpath) {
- + debug("no RPATH to make relative\n");
- + return;
- + }
- +
- if (op == rpShrink && !rpath) {
- debug("no RPATH to shrink\n");
- return;
- @@ -1120,26 +1196,80 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
- continue;
- }
-
- - /* For each library that we haven't found yet, see if it
- - exists in this directory. */
- - bool libFound = false;
- - for (unsigned int j = 0; j < neededLibs.size(); ++j)
- - if (!neededLibFound[j]) {
- - string libName = dirName + "/" + neededLibs[j];
- - struct stat st;
- - if (stat(libName.c_str(), &st) == 0) {
- - neededLibFound[j] = true;
- - libFound = true;
- - }
- - }
- -
- - if (!libFound)
- + if (!libFoundInRPath(dirName, neededLibs, neededLibFound))
- debug("removing directory `%s' from RPATH\n", dirName.c_str());
- else
- concatToRPath(newRPath, dirName);
- }
- }
-
- + /* Make the the RPATH relative to the specified path */
- + if (op == rpMakeRelative) {
- + vector<bool> neededLibFound(neededLibs.size(), false);
- + string fileDir = fileName.substr(0, fileName.find_last_of("/"));
- +
- + newRPath = "";
- +
- + vector<string> rpathDirs = splitColonDelimitedString(rpath);
- + for (vector<string>::iterator it = rpathDirs.begin(); it != rpathDirs.end(); ++it) {
- + const string & dirName = *it;
- +
- + string canonicalPath;
- +
- + /* Figure out if we should keep or discard the path. There are several
- + cases to be handled:
- + "dirName" starts with "$ORIGIN":
- + The original build-system already took care of setting a relative
- + RPATH. Resolve it and test if it's valid (does exist).
- + "dirName" start with "rootDir":
- + The original build-system added some absolute RPATH (absolute on
- + the build machine). Test if it's valid (does exist).
- + "rootDir"/"dirName" exists:
- + The original build-system already took care of setting an absolute
- + RPATH (absolute in the final rootfs). Resolve it and test if it's
- + valid (does exist).
- + "dirName" points somewhere else:
- + (can be anywhere: build trees, staging tree, host location,
- + non-existing location, etc.). Just discard such a path. */
- + if (!dirName.compare(0, 7, "$ORIGIN")) {
- + string path = fileDir + dirName.substr(7);
- + if (!absolutePathExists(path, canonicalPath)) {
- + debug("removing directory '%s' from RPATH because '%s' doesn't exist\n",
- + dirName.c_str(), path.c_str());
- + continue;
- + }
- + } else if (!dirName.compare(0, rootDir.length(), rootDir)) {
- + if (!absolutePathExists(dirName, canonicalPath)) {
- + debug("removing directory '%s' from RPATH because it doesn't exist\n", dirName.c_str());
- + continue;
- + }
- + } else {
- + string path = rootDir + dirName;
- + if (!absolutePathExists(path, canonicalPath)) {
- + debug("removing directory '%s' from RPATH because it's not in rootdir\n",
- + dirName.c_str());
- + continue;
- + }
- + }
- +
- + if (noStandardLibDirs) {
- + if (!canonicalPath.compare(rootDir + "/lib") ||
- + !canonicalPath.compare(rootDir + "/usr/lib")) {
- + debug("removing directory '%s' from RPATH because it's a standard library directory\n",
- + dirName.c_str());
- + continue;
- + }
- + }
- +
- + /* Finally make "canonicalPath" relative to "filedir" in "rootDir" */
- + if (relativeToFile)
- + concatToRPath(newRPath, makePathRelative(canonicalPath, fileDir));
- + else
- + concatToRPath(newRPath, canonicalPath.substr(rootDir.length()));
- + debug("keeping relative path of %s\n", canonicalPath.c_str());
- + }
- + }
- +
- if (op == rpRemove) {
- if (!rpath) {
- debug("no RPATH to delete\n");
- @@ -1413,7 +1543,9 @@ static bool shrinkRPath = false;
- static bool removeRPath = false;
- static bool setRPath = false;
- static bool printRPath = false;
- +static bool makeRPathRelative = false;
- static string newRPath;
- +static string rootDir;
- static set<string> neededLibsToRemove;
- static map<string, string> neededLibsToReplace;
- static set<string> neededLibsToAdd;
- @@ -1438,14 +1570,16 @@ static void patchElf2(ElfFile & elfFile)
- elfFile.setInterpreter(newInterpreter);
-
- if (printRPath)
- - elfFile.modifyRPath(elfFile.rpPrint, "");
- + elfFile.modifyRPath(elfFile.rpPrint, "", "");
-
- if (shrinkRPath)
- - elfFile.modifyRPath(elfFile.rpShrink, "");
- + elfFile.modifyRPath(elfFile.rpShrink, "", "");
- else if (removeRPath)
- - elfFile.modifyRPath(elfFile.rpRemove, "");
- + elfFile.modifyRPath(elfFile.rpRemove, "", "");
- else if (setRPath)
- - elfFile.modifyRPath(elfFile.rpSet, newRPath);
- + elfFile.modifyRPath(elfFile.rpSet, "", newRPath);
- + else if (makeRPathRelative)
- + elfFile.modifyRPath(elfFile.rpMakeRelative, rootDir, "");
-
- if (printNeeded) elfFile.printNeededLibs();
-
- @@ -1508,6 +1642,9 @@ void showHelp(const string & progName)
- [--set-rpath RPATH]\n\
- [--remove-rpath]\n\
- [--shrink-rpath]\n\
- + [--make-rpath-relative ROOTDIR]\n\
- + [--no-standard-lib-dirs]\n\
- + [--relative-to-file]\n\
- [--print-rpath]\n\
- [--force-rpath]\n\
- [--add-needed LIBRARY]\n\
- @@ -1564,6 +1701,17 @@ int main(int argc, char * * argv)
- setRPath = true;
- newRPath = argv[i];
- }
- + else if (arg == "--make-rpath-relative") {
- + if (++i == argc) error("missing argument to --make-rpath-relative");
- + makeRPathRelative = true;
- + rootDir = argv[i];
- + }
- + else if (arg == "--no-standard-lib-dirs") {
- + noStandardLibDirs = true;
- + }
- + else if (arg == "--relative-to-file") {
- + relativeToFile = true;
- + }
- else if (arg == "--print-rpath") {
- printRPath = true;
- }
- --
- 1.9.1
|