0001-Add-option-to-make-the-rpath-relative-under-a-specif.patch 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. From 6e8915572db65cf63b7a82f9b24af6f9cad92ba7 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. [Fabrice: update for 0.13]
  36. Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
  37. [Dario: make the patch to be applied with fuzz factor 0]
  38. Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
  39. ---
  40. src/patchelf.cc | 199 +++++++++++++++++++++++++++++++++++++++++-------
  41. 1 file changed, 171 insertions(+), 28 deletions(-)
  42. diff --git a/src/patchelf.cc b/src/patchelf.cc
  43. index fd1e7b7b61c3..f3b7ba8867bf 100644
  44. --- a/src/patchelf.cc
  45. +++ b/src/patchelf.cc
  46. @@ -45,6 +45,10 @@ static bool debugMode = false;
  47. static bool forceRPath = false;
  48. +static bool noStandardLibDirs = false;
  49. +
  50. +static bool relativeToFile = false;
  51. +
  52. static std::vector<std::string> fileNames;
  53. static std::string outputFileName;
  54. static bool alwaysWrite = false;
  55. @@ -81,6 +85,49 @@ static bool hasAllowedPrefix(const std::string & s, const std::vector<std::strin
  56. return std::any_of(allowedPrefixes.begin(), allowedPrefixes.end(), [&](const std::string & i) { return !s.compare(0, i.size(), i); });
  57. }
  58. +static bool absolutePathExists(const std::string & path, std::string & canonicalPath)
  59. +{
  60. + char *cpath = realpath(path.c_str(), NULL);
  61. + if (cpath) {
  62. + canonicalPath = cpath;
  63. + free(cpath);
  64. + return true;
  65. + } else {
  66. + return false;
  67. + }
  68. +}
  69. +
  70. +static std::string makePathRelative(const std::string & path,
  71. + const std::string & refPath)
  72. +{
  73. + std::string relPath = "$ORIGIN";
  74. + std::string p = path, refP = refPath;
  75. + size_t pos;
  76. +
  77. + /* Strip the common part of path and refPath */
  78. + while (true) {
  79. + pos = p.find_first_of('/', 1);
  80. + if (refP.find_first_of('/', 1) != pos)
  81. + break;
  82. + if (p.substr(0, pos) != refP.substr(0, pos))
  83. + break;
  84. + if (pos == std::string::npos)
  85. + break;
  86. + p = p.substr(pos);
  87. + refP = refP.substr(pos);
  88. + }
  89. + /* Check if both pathes are equal */
  90. + if (p != refP) {
  91. + pos = 0;
  92. + while (pos != std::string::npos) {
  93. + pos =refP.find_first_of('/', pos + 1);
  94. + relPath.append("/..");
  95. + }
  96. + relPath.append(p);
  97. + }
  98. +
  99. + return relPath;
  100. +}
  101. template<ElfFileParams>
  102. class ElfFile
  103. @@ -197,9 +244,13 @@ public:
  104. void setInterpreter(const std::string & newInterpreter);
  105. - typedef enum { rpPrint, rpShrink, rpSet, rpAdd, rpRemove } RPathOp;
  106. + typedef enum { rpPrint, rpShrink, rpMakeRelative, rpSet, rpAdd, rpRemove} RPathOp;
  107. - void modifyRPath(RPathOp op, const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath);
  108. + bool libFoundInRPath(const std::string & dirName,
  109. + const std::vector<std::string> neededLibs,
  110. + std::vector<bool> & neededLibFound);
  111. +
  112. + void modifyRPath(RPathOp op, std::string rootDir, const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath, const std::string & fileName);
  113. void addNeeded(const std::set<std::string> & libs);
  114. @@ -1267,8 +1318,28 @@ static void concatToRPath(std::string & rpath, const std::string & path)
  115. template<ElfFileParams>
  116. -void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
  117. - const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath)
  118. +bool ElfFile<ElfFileParamNames>::libFoundInRPath(const std::string & dirName,
  119. + const std::vector<std::string> neededLibs, std::vector<bool> & neededLibFound)
  120. +{
  121. + /* For each library that we haven't found yet, see if it
  122. + exists in this directory. */
  123. + bool libFound = false;
  124. + for (unsigned int j = 0; j < neededLibs.size(); ++j)
  125. + if (!neededLibFound[j]) {
  126. + std::string libName = dirName + "/" + neededLibs[j];
  127. + struct stat st;
  128. + if (stat(libName.c_str(), &st) == 0) {
  129. + neededLibFound[j] = true;
  130. + libFound = true;
  131. + }
  132. + }
  133. + return libFound;
  134. +}
  135. +
  136. +
  137. +template<ElfFileParams>
  138. +void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, std::string rootDir,
  139. + const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath, const std::string & fileName)
  140. {
  141. auto shdrDynamic = findSection(".dynamic");
  142. @@ -1314,6 +1385,11 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
  143. return;
  144. }
  145. + if (op == rpMakeRelative && !rpath) {
  146. + debug("no RPATH to make relative\n");
  147. + return;
  148. + }
  149. +
  150. if (op == rpShrink && !rpath) {
  151. debug("no RPATH to shrink\n");
  152. return;
  153. @@ -1343,31 +1419,80 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
  154. continue;
  155. }
  156. - /* For each library that we haven't found yet, see if it
  157. - exists in this directory. */
  158. - bool libFound = false;
  159. - for (unsigned int j = 0; j < neededLibs.size(); ++j)
  160. - if (!neededLibFound[j]) {
  161. - std::string libName = dirName + "/" + neededLibs[j];
  162. - try {
  163. - Elf32_Half library_e_machine = getElfType(readFile(libName, sizeof(Elf32_Ehdr))).machine;
  164. - if (rdi(library_e_machine) == rdi(hdr->e_machine)) {
  165. - neededLibFound[j] = true;
  166. - libFound = true;
  167. - } else
  168. - debug("ignoring library '%s' because its machine type differs\n", libName.c_str());
  169. - } catch (SysError & e) {
  170. - if (e.errNo != ENOENT) throw;
  171. - }
  172. - }
  173. -
  174. - if (!libFound)
  175. + if (!libFoundInRPath(dirName, neededLibs, neededLibFound))
  176. debug("removing directory '%s' from RPATH\n", dirName.c_str());
  177. else
  178. concatToRPath(newRPath, dirName);
  179. }
  180. }
  181. + /* Make the the RPATH relative to the specified path */
  182. + if (op == rpMakeRelative) {
  183. + std::vector<bool> neededLibFound(neededLibs.size(), false);
  184. + std::string fileDir = fileName.substr(0, fileName.find_last_of("/"));
  185. +
  186. + newRPath = "";
  187. +
  188. + std::vector<std::string> rpathDirs = splitColonDelimitedString(rpath);
  189. + for (std::vector<std::string>::iterator it = rpathDirs.begin(); it != rpathDirs.end(); ++it) {
  190. + const std::string & dirName = *it;
  191. +
  192. + std::string canonicalPath;
  193. +
  194. + /* Figure out if we should keep or discard the path. There are several
  195. + cases to be handled:
  196. + "dirName" starts with "$ORIGIN":
  197. + The original build-system already took care of setting a relative
  198. + RPATH. Resolve it and test if it's valid (does exist).
  199. + "dirName" start with "rootDir":
  200. + The original build-system added some absolute RPATH (absolute on
  201. + the build machine). Test if it's valid (does exist).
  202. + "rootDir"/"dirName" exists:
  203. + The original build-system already took care of setting an absolute
  204. + RPATH (absolute in the final rootfs). Resolve it and test if it's
  205. + valid (does exist).
  206. + "dirName" points somewhere else:
  207. + (can be anywhere: build trees, staging tree, host location,
  208. + non-existing location, etc.). Just discard such a path. */
  209. + if (!dirName.compare(0, 7, "$ORIGIN")) {
  210. + std::string path = fileDir + dirName.substr(7);
  211. + if (!absolutePathExists(path, canonicalPath)) {
  212. + debug("removing directory '%s' from RPATH because '%s' doesn't exist\n",
  213. + dirName.c_str(), path.c_str());
  214. + continue;
  215. + }
  216. + } else if (!dirName.compare(0, rootDir.length(), rootDir)) {
  217. + if (!absolutePathExists(dirName, canonicalPath)) {
  218. + debug("removing directory '%s' from RPATH because it doesn't exist\n", dirName.c_str());
  219. + continue;
  220. + }
  221. + } else {
  222. + std::string path = rootDir + dirName;
  223. + if (!absolutePathExists(path, canonicalPath)) {
  224. + debug("removing directory '%s' from RPATH because it's not in rootdir\n",
  225. + dirName.c_str());
  226. + continue;
  227. + }
  228. + }
  229. +
  230. + if (noStandardLibDirs) {
  231. + if (!canonicalPath.compare(rootDir + "/lib") ||
  232. + !canonicalPath.compare(rootDir + "/usr/lib")) {
  233. + debug("removing directory '%s' from RPATH because it's a standard library directory\n",
  234. + dirName.c_str());
  235. + continue;
  236. + }
  237. + }
  238. +
  239. + /* Finally make "canonicalPath" relative to "filedir" in "rootDir" */
  240. + if (relativeToFile)
  241. + concatToRPath(newRPath, makePathRelative(canonicalPath, fileDir));
  242. + else
  243. + concatToRPath(newRPath, canonicalPath.substr(rootDir.length()));
  244. + debug("keeping relative path of %s\n", canonicalPath.c_str());
  245. + }
  246. + }
  247. +
  248. if (op == rpRemove) {
  249. if (!rpath) {
  250. debug("no RPATH to delete\n");
  251. @@ -1736,7 +1861,9 @@ static bool removeRPath = false;
  252. static bool setRPath = false;
  253. static bool addRPath = false;
  254. static bool printRPath = false;
  255. +static bool makeRPathRelative = false;
  256. static std::string newRPath;
  257. +static std::string rootDir;
  258. static std::set<std::string> neededLibsToRemove;
  259. static std::map<std::string, std::string> neededLibsToReplace;
  260. static std::set<std::string> neededLibsToAdd;
  261. @@ -1760,16 +1887,18 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
  262. elfFile.setInterpreter(newInterpreter);
  263. if (printRPath)
  264. - elfFile.modifyRPath(elfFile.rpPrint, {}, "");
  265. + elfFile.modifyRPath(elfFile.rpPrint, "", {}, "", fileName);
  266. if (shrinkRPath)
  267. - elfFile.modifyRPath(elfFile.rpShrink, allowedRpathPrefixes, "");
  268. + elfFile.modifyRPath(elfFile.rpShrink, "", allowedRpathPrefixes, "", fileName);
  269. else if (removeRPath)
  270. - elfFile.modifyRPath(elfFile.rpRemove, {}, "");
  271. + elfFile.modifyRPath(elfFile.rpRemove, "", {}, "", fileName);
  272. else if (setRPath)
  273. - elfFile.modifyRPath(elfFile.rpSet, {}, newRPath);
  274. + elfFile.modifyRPath(elfFile.rpSet, "", {}, newRPath, fileName);
  275. else if (addRPath)
  276. - elfFile.modifyRPath(elfFile.rpAdd, {}, newRPath);
  277. + elfFile.modifyRPath(elfFile.rpAdd, "", {}, newRPath, fileName);
  278. + else if (makeRPathRelative)
  279. + elfFile.modifyRPath(elfFile.rpMakeRelative, rootDir, {}, "", fileName);
  280. if (printNeeded) elfFile.printNeededLibs();
  281. @@ -1821,6 +1950,9 @@ void showHelp(const std::string & progName)
  282. [--remove-rpath]\n\
  283. [--shrink-rpath]\n\
  284. [--allowed-rpath-prefixes PREFIXES]\t\tWith '--shrink-rpath', reject rpath entries not starting with the allowed prefix\n\
  285. + [--make-rpath-relative ROOTDIR]\n\
  286. + [--no-standard-lib-dirs]\n\
  287. + [--relative-to-file]\n\
  288. [--print-rpath]\n\
  289. [--force-rpath]\n\
  290. [--add-needed LIBRARY]\n\
  291. @@ -1889,6 +2021,17 @@ int mainWrapped(int argc, char * * argv)
  292. addRPath = true;
  293. newRPath = argv[i];
  294. }
  295. + else if (arg == "--make-rpath-relative") {
  296. + if (++i == argc) error("missing argument to --make-rpath-relative");
  297. + makeRPathRelative = true;
  298. + rootDir = argv[i];
  299. + }
  300. + else if (arg == "--no-standard-lib-dirs") {
  301. + noStandardLibDirs = true;
  302. + }
  303. + else if (arg == "--relative-to-file") {
  304. + relativeToFile = true;
  305. + }
  306. else if (arg == "--print-rpath") {
  307. printRPath = true;
  308. }
  309. --
  310. 2.43.0