0003-Add-option-to-make-the-rpath-relative-under-a-specif.patch 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. From 618220bfb55c875d6a4d197cb24fe632ac93ec85 Mon Sep 17 00:00:00 2001
  2. From: Wolfgang Grandegger <wg@grandegger.com>
  3. Date: Mon, 20 Feb 2017 16:29:24 +0100
  4. Subject: [PATCH] Add option to make the rpath relative under a specified root
  5. directory
  6. Running "patchelf" with the option "--make-rpath-relative ROOTDIR" will
  7. modify or delete the RPATHDIRs according the following rules
  8. similar to Martin's patches [1] making the Buildroot toolchaing/SDK
  9. relocatable.
  10. RPATHDIR starts with "$ORIGIN":
  11. The original build-system already took care of setting a relative
  12. RPATH, resolve it and test if it's valid (does exist)
  13. RPATHDIR starts with ROOTDIR:
  14. The original build-system added some absolute RPATH (absolute on
  15. the build machine). Test if it's valid (does exist).
  16. ROOTDIR/RPATHDIR exists:
  17. The original build-system already took care of setting an absolute
  18. RPATH (absolute in the final rootfs), resolve it and test if it's
  19. valid (does exist).
  20. RPATHDIR points somewhere else:
  21. (can be anywhere: build trees, staging tree, host location,
  22. non-existing location, etc.). Just discard such a path.
  23. The option "--no-standard-libs" will discard RPATHDIRs ROOTDIR/lib and
  24. ROOTDIR/usr/lib. Like "--shrink-rpath", RPATHDIRs are also discarded
  25. if the directories do not contain a library referenced by the
  26. DT_NEEDED fields.
  27. If the option "--relative-to-file" is given, the rpath will start
  28. with "$ORIGIN" making it relative to the ELF file, otherwise an
  29. absolute path relative to ROOTDIR will be used.
  30. A pull request for a similar patch [2] for mainline inclusion is
  31. pending.
  32. [1] http://lists.busybox.net/pipermail/buildroot/2016-April/159422.html
  33. [2] https://github.com/NixOS/patchelf/pull/118
  34. Signed-off-by: Wolfgang Grandegger <wg@grandegger.com>
  35. ---
  36. src/patchelf.cc | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++------
  37. 1 file changed, 175 insertions(+), 21 deletions(-)
  38. diff --git a/src/patchelf.cc b/src/patchelf.cc
  39. index 1d9a772..35b4a33 100644
  40. --- a/src/patchelf.cc
  41. +++ b/src/patchelf.cc
  42. @@ -46,6 +46,10 @@ static bool debugMode = false;
  43. static bool forceRPath = false;
  44. +static bool noStandardLibDirs = false;
  45. +
  46. +static bool relativeToFile = false;
  47. +
  48. static string fileName;
  49. static int pageSize = PAGESIZE;
  50. @@ -77,6 +81,49 @@ static unsigned int getPageSize(){
  51. return pageSize;
  52. }
  53. +static bool absolutePathExists(const string & path, string & canonicalPath)
  54. +{
  55. + char *cpath = realpath(path.c_str(), NULL);
  56. + if (cpath) {
  57. + canonicalPath = cpath;
  58. + free(cpath);
  59. + return true;
  60. + } else {
  61. + return false;
  62. + }
  63. +}
  64. +
  65. +static string makePathRelative(const string & path,
  66. + const string & refPath)
  67. +{
  68. + string relPath = "$ORIGIN";
  69. + string p = path, refP = refPath;
  70. + size_t pos;
  71. +
  72. + /* Strip the common part of path and refPath */
  73. + while (true) {
  74. + pos = p.find_first_of('/', 1);
  75. + if (refP.find_first_of('/', 1) != pos)
  76. + break;
  77. + if (p.substr(0, pos) != refP.substr(0, pos))
  78. + break;
  79. + if (pos == string::npos)
  80. + break;
  81. + p = p.substr(pos);
  82. + refP = refP.substr(pos);
  83. + }
  84. + /* Check if both pathes are equal */
  85. + if (p != refP) {
  86. + pos = 0;
  87. + while (pos != string::npos) {
  88. + pos =refP.find_first_of('/', pos + 1);
  89. + relPath.append("/..");
  90. + }
  91. + relPath.append(p);
  92. + }
  93. +
  94. + return relPath;
  95. +}
  96. template<ElfFileParams>
  97. class ElfFile
  98. @@ -183,9 +230,13 @@ public:
  99. void setInterpreter(const string & newInterpreter);
  100. - typedef enum { rpPrint, rpShrink, rpSet, rpRemove } RPathOp;
  101. + typedef enum { rpPrint, rpShrink, rpMakeRelative, rpSet, rpRemove} RPathOp;
  102. +
  103. + bool libFoundInRPath(const string & dirName,
  104. + const vector<string> neededLibs,
  105. + vector<bool> & neededLibFound);
  106. - void modifyRPath(RPathOp op, string newRPath);
  107. + void modifyRPath(RPathOp op, string rootDir, string newRPath);
  108. void addNeeded(set<string> libs);
  109. @@ -1041,7 +1092,27 @@ static void concatToRPath(string & rpath, const string & path)
  110. template<ElfFileParams>
  111. -void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
  112. +bool ElfFile<ElfFileParamNames>::libFoundInRPath(const string & dirName,
  113. + const vector<string> neededLibs, vector<bool> & neededLibFound)
  114. +{
  115. + /* For each library that we haven't found yet, see if it
  116. + exists in this directory. */
  117. + bool libFound = false;
  118. + for (unsigned int j = 0; j < neededLibs.size(); ++j)
  119. + if (!neededLibFound[j]) {
  120. + string libName = dirName + "/" + neededLibs[j];
  121. + struct stat st;
  122. + if (stat(libName.c_str(), &st) == 0) {
  123. + neededLibFound[j] = true;
  124. + libFound = true;
  125. + }
  126. + }
  127. + return libFound;
  128. +}
  129. +
  130. +
  131. +template<ElfFileParams>
  132. +void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string rootDir, string newRPath)
  133. {
  134. Elf_Shdr & shdrDynamic = findSection(".dynamic");
  135. @@ -1096,6 +1167,11 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
  136. return;
  137. }
  138. + if (op == rpMakeRelative && !rpath) {
  139. + debug("no RPATH to make relative\n");
  140. + return;
  141. + }
  142. +
  143. if (op == rpShrink && !rpath) {
  144. debug("no RPATH to shrink\n");
  145. return;
  146. @@ -1120,26 +1196,80 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
  147. continue;
  148. }
  149. - /* For each library that we haven't found yet, see if it
  150. - exists in this directory. */
  151. - bool libFound = false;
  152. - for (unsigned int j = 0; j < neededLibs.size(); ++j)
  153. - if (!neededLibFound[j]) {
  154. - string libName = dirName + "/" + neededLibs[j];
  155. - struct stat st;
  156. - if (stat(libName.c_str(), &st) == 0) {
  157. - neededLibFound[j] = true;
  158. - libFound = true;
  159. - }
  160. - }
  161. -
  162. - if (!libFound)
  163. + if (!libFoundInRPath(dirName, neededLibs, neededLibFound))
  164. debug("removing directory `%s' from RPATH\n", dirName.c_str());
  165. else
  166. concatToRPath(newRPath, dirName);
  167. }
  168. }
  169. + /* Make the the RPATH relative to the specified path */
  170. + if (op == rpMakeRelative) {
  171. + vector<bool> neededLibFound(neededLibs.size(), false);
  172. + string fileDir = fileName.substr(0, fileName.find_last_of("/"));
  173. +
  174. + newRPath = "";
  175. +
  176. + vector<string> rpathDirs = splitColonDelimitedString(rpath);
  177. + for (vector<string>::iterator it = rpathDirs.begin(); it != rpathDirs.end(); ++it) {
  178. + const string & dirName = *it;
  179. +
  180. + string canonicalPath;
  181. +
  182. + /* Figure out if we should keep or discard the path. There are several
  183. + cases to be handled:
  184. + "dirName" starts with "$ORIGIN":
  185. + The original build-system already took care of setting a relative
  186. + RPATH. Resolve it and test if it's valid (does exist).
  187. + "dirName" start with "rootDir":
  188. + The original build-system added some absolute RPATH (absolute on
  189. + the build machine). Test if it's valid (does exist).
  190. + "rootDir"/"dirName" exists:
  191. + The original build-system already took care of setting an absolute
  192. + RPATH (absolute in the final rootfs). Resolve it and test if it's
  193. + valid (does exist).
  194. + "dirName" points somewhere else:
  195. + (can be anywhere: build trees, staging tree, host location,
  196. + non-existing location, etc.). Just discard such a path. */
  197. + if (!dirName.compare(0, 7, "$ORIGIN")) {
  198. + string path = fileDir + dirName.substr(7);
  199. + if (!absolutePathExists(path, canonicalPath)) {
  200. + debug("removing directory '%s' from RPATH because '%s' doesn't exist\n",
  201. + dirName.c_str(), path.c_str());
  202. + continue;
  203. + }
  204. + } else if (!dirName.compare(0, rootDir.length(), rootDir)) {
  205. + if (!absolutePathExists(dirName, canonicalPath)) {
  206. + debug("removing directory '%s' from RPATH because it doesn't exist\n", dirName.c_str());
  207. + continue;
  208. + }
  209. + } else {
  210. + string path = rootDir + dirName;
  211. + if (!absolutePathExists(path, canonicalPath)) {
  212. + debug("removing directory '%s' from RPATH because it's not in rootdir\n",
  213. + dirName.c_str());
  214. + continue;
  215. + }
  216. + }
  217. +
  218. + if (noStandardLibDirs) {
  219. + if (!canonicalPath.compare(rootDir + "/lib") ||
  220. + !canonicalPath.compare(rootDir + "/usr/lib")) {
  221. + debug("removing directory '%s' from RPATH because it's a standard library directory\n",
  222. + dirName.c_str());
  223. + continue;
  224. + }
  225. + }
  226. +
  227. + /* Finally make "canonicalPath" relative to "filedir" in "rootDir" */
  228. + if (relativeToFile)
  229. + concatToRPath(newRPath, makePathRelative(canonicalPath, fileDir));
  230. + else
  231. + concatToRPath(newRPath, canonicalPath.substr(rootDir.length()));
  232. + debug("keeping relative path of %s\n", canonicalPath.c_str());
  233. + }
  234. + }
  235. +
  236. if (op == rpRemove) {
  237. if (!rpath) {
  238. debug("no RPATH to delete\n");
  239. @@ -1413,7 +1543,9 @@ static bool shrinkRPath = false;
  240. static bool removeRPath = false;
  241. static bool setRPath = false;
  242. static bool printRPath = false;
  243. +static bool makeRPathRelative = false;
  244. static string newRPath;
  245. +static string rootDir;
  246. static set<string> neededLibsToRemove;
  247. static map<string, string> neededLibsToReplace;
  248. static set<string> neededLibsToAdd;
  249. @@ -1438,14 +1570,16 @@ static void patchElf2(ElfFile & elfFile)
  250. elfFile.setInterpreter(newInterpreter);
  251. if (printRPath)
  252. - elfFile.modifyRPath(elfFile.rpPrint, "");
  253. + elfFile.modifyRPath(elfFile.rpPrint, "", "");
  254. if (shrinkRPath)
  255. - elfFile.modifyRPath(elfFile.rpShrink, "");
  256. + elfFile.modifyRPath(elfFile.rpShrink, "", "");
  257. else if (removeRPath)
  258. - elfFile.modifyRPath(elfFile.rpRemove, "");
  259. + elfFile.modifyRPath(elfFile.rpRemove, "", "");
  260. else if (setRPath)
  261. - elfFile.modifyRPath(elfFile.rpSet, newRPath);
  262. + elfFile.modifyRPath(elfFile.rpSet, "", newRPath);
  263. + else if (makeRPathRelative)
  264. + elfFile.modifyRPath(elfFile.rpMakeRelative, rootDir, "");
  265. if (printNeeded) elfFile.printNeededLibs();
  266. @@ -1508,6 +1642,9 @@ void showHelp(const string & progName)
  267. [--set-rpath RPATH]\n\
  268. [--remove-rpath]\n\
  269. [--shrink-rpath]\n\
  270. + [--make-rpath-relative ROOTDIR]\n\
  271. + [--no-standard-lib-dirs]\n\
  272. + [--relative-to-file]\n\
  273. [--print-rpath]\n\
  274. [--force-rpath]\n\
  275. [--add-needed LIBRARY]\n\
  276. @@ -1564,6 +1701,17 @@ int main(int argc, char * * argv)
  277. setRPath = true;
  278. newRPath = argv[i];
  279. }
  280. + else if (arg == "--make-rpath-relative") {
  281. + if (++i == argc) error("missing argument to --make-rpath-relative");
  282. + makeRPathRelative = true;
  283. + rootDir = argv[i];
  284. + }
  285. + else if (arg == "--no-standard-lib-dirs") {
  286. + noStandardLibDirs = true;
  287. + }
  288. + else if (arg == "--relative-to-file") {
  289. + relativeToFile = true;
  290. + }
  291. else if (arg == "--print-rpath") {
  292. printRPath = true;
  293. }
  294. --
  295. 1.9.1