@@ -44,12 +44,15 @@ static bool debugMode = false;
4444
4545static bool forceRPath = false ;
4646
47+ static bool noStandardLibDirs = false ;
48+
49+ static bool relativeToFile = false ;
50+
4751static std::string fileName;
4852static int pageSize = PAGESIZE;
4953
5054typedef std::shared_ptr<std::vector<unsigned char >> FileContents;
5155
52-
5356#define ElfFileParams class Elf_Ehdr , class Elf_Phdr , class Elf_Shdr , class Elf_Addr , class Elf_Off , class Elf_Dyn , class Elf_Sym , class Elf_Verneed
5457#define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym, Elf_Verneed
5558
@@ -83,6 +86,49 @@ static unsigned int getPageSize()
8386 return pageSize;
8487}
8588
89+ static bool absolutePathExists (const std::string & path, std::string & canonicalPath)
90+ {
91+ char *cpath = realpath (path.c_str (), NULL );
92+ if (cpath) {
93+ canonicalPath = cpath;
94+ free (cpath);
95+ return true ;
96+ } else {
97+ return false ;
98+ }
99+ }
100+
101+ static std::string makePathRelative (const std::string & path,
102+ const std::string & refPath)
103+ {
104+ std::string relPath = " $ORIGIN" ;
105+ std::string p = path, refP = refPath;
106+ std::size_t pos;
107+
108+ /* Strip the common part of path and refPath */
109+ while (true ) {
110+ pos = p.find_first_of (' /' , 1 );
111+ if (refP.find_first_of (' /' , 1 ) != pos)
112+ break ;
113+ if (p.substr (0 , pos) != refP.substr (0 , pos))
114+ break ;
115+ if (pos == std::string::npos)
116+ break ;
117+ p = p.substr (pos);
118+ refP = refP.substr (pos);
119+ }
120+ /* Check if both pathes are equal */
121+ if (p != refP) {
122+ pos = 0 ;
123+ while (pos != std::string::npos) {
124+ pos =refP.find_first_of (' /' , pos + 1 );
125+ relPath.append (" /.." );
126+ }
127+ relPath.append (p);
128+ }
129+
130+ return relPath;
131+ }
86132
87133template <ElfFileParams>
88134class ElfFile
@@ -191,9 +237,15 @@ class ElfFile
191237
192238 void setInterpreter (const std::string & newInterpreter);
193239
194- typedef enum { rpPrint, rpShrink, rpSet, rpRemove } RPathOp;
240+ typedef enum { rpPrint, rpShrink, rpMakeRelative, rpSet, rpRemove} RPathOp;
241+
242+ bool libFoundInRPath (const std::string & dirName,
243+ const std::vector<std::string> neededLibs,
244+ std::vector<bool > & neededLibFound);
195245
196- void modifyRPath (RPathOp op, const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath);
246+ void modifyRPath (RPathOp op,
247+ const std::vector<std::string> & allowedRpathPrefixes,
248+ std::string rootDir, std::string newRPath);
197249
198250 void addNeeded (const std::set<std::string> & libs);
199251
@@ -1099,10 +1151,33 @@ static void concatToRPath(std::string & rpath, const std::string & path)
10991151 rpath += path;
11001152}
11011153
1154+ template <ElfFileParams>
1155+ bool ElfFile<ElfFileParamNames>::libFoundInRPath(const std::string & dirName,
1156+ const std::vector<std::string> neededLibs, std::vector<bool > & neededLibFound)
1157+ {
1158+ /* For each library that we haven't found yet, see if it
1159+ exists in this directory. */
1160+ bool libFound = false ;
1161+ for (unsigned int j = 0 ; j < neededLibs.size (); ++j)
1162+ if (!neededLibFound[j]) {
1163+ std::string libName = dirName + " /" + neededLibs[j];
1164+ try {
1165+ if (getElfType (readFile (libName, sizeof (Elf32_Ehdr))).machine == rdi (hdr->e_machine )) {
1166+ neededLibFound[j] = true ;
1167+ libFound = true ;
1168+ } else
1169+ debug (" ignoring library '%s' because its machine type differs\n " , libName.c_str ());
1170+ } catch (SysError & e) {
1171+ if (e.errNo != ENOENT) throw ;
1172+ }
1173+ }
1174+ return libFound;
1175+ }
11021176
11031177template <ElfFileParams>
11041178void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
1105- const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath)
1179+ const std::vector<std::string> & allowedRpathPrefixes,
1180+ std::string rootDir, std::string newRPath)
11061181{
11071182 Elf_Shdr & shdrDynamic = findSection (" .dynamic" );
11081183
@@ -1153,6 +1228,10 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
11531228 return ;
11541229 }
11551230
1231+ if (op == rpMakeRelative && !rpath) {
1232+ debug (" no RPATH to make relative\n " );
1233+ return ;
1234+ }
11561235
11571236 /* For each directory in the RPATH, check if it contains any
11581237 needed library. */
@@ -1177,27 +1256,79 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
11771256 continue ;
11781257 }
11791258
1180- /* For each library that we haven't found yet, see if it
1181- exists in this directory. */
1182- bool libFound = false ;
1183- for (unsigned int j = 0 ; j < neededLibs.size (); ++j)
1184- if (!neededLibFound[j]) {
1185- std::string libName = dirName + " /" + neededLibs[j];
1186- try {
1187- if (getElfType (readFile (libName, sizeof (Elf32_Ehdr))).machine == rdi (hdr->e_machine )) {
1188- neededLibFound[j] = true ;
1189- libFound = true ;
1190- } else
1191- debug (" ignoring library '%s' because its machine type differs\n " , libName.c_str ());
1192- } catch (SysError & e) {
1193- if (e.errNo != ENOENT) throw ;
1194- }
1259+ if (!libFoundInRPath (dirName, neededLibs, neededLibFound))
1260+ debug (" removing directory '%s' from RPATH\n " , dirName.c_str ());
1261+ else
1262+ concatToRPath (newRPath, dirName);
1263+ }
1264+ }
1265+
1266+ /* Make the the RPATH relative to the specified path */
1267+ if (op == rpMakeRelative) {
1268+ std::vector<bool > neededLibFound (neededLibs.size (), false );
1269+ std::string fileDir = fileName.substr (0 , fileName.find_last_of (" /" ));
1270+ newRPath = " " ;
1271+
1272+ for (auto & dirName : splitColonDelimitedString (rpath)) {
1273+ std::string canonicalPath;
1274+ std::string path;
1275+
1276+ /* Figure out if we should keep or discard the path; there are several
1277+ cases to handled:
1278+ "dirName" starts with "$ORIGIN":
1279+ The original build-system already took care of setting a relative
1280+ RPATH, resolve it and test if it is worthwhile to keep it.
1281+ "dirName" start with "rootDir":
1282+ The original build-system added some absolute RPATH (absolute on
1283+ the build machine). While this is wrong, it can still be fixed; so
1284+ test if it is worthwhile to keep it.
1285+ "rootDir"/"dirName" exists:
1286+ The original build-system already took care of setting an absolute
1287+ RPATH (absolute in the final rootfs), resolve it and test if it is
1288+ worthwhile to keep it;
1289+ "dirName" points somewhere else:
1290+ (can be anywhere: build trees, staging tree, host location,
1291+ non-existing location, etc.). Just discard such a path. */
1292+ if (!dirName.compare (0 , 7 , " $ORIGIN" )) {
1293+ path = fileDir + dirName.substr (7 );
1294+ if (!absolutePathExists (path, canonicalPath)) {
1295+ debug (" removing directory '%s' from RPATH because it doesn't exist\n " , dirName.c_str ());
1296+ continue ;
1297+ }
1298+ } else if (!dirName.compare (0 , rootDir.length (), rootDir)) {
1299+ if (!absolutePathExists (dirName, canonicalPath)) {
1300+ debug (" removing directory '%s' from RPATH because it doesn't exist\n " , dirName.c_str ());
1301+ continue ;
1302+ }
1303+ } else {
1304+ path = rootDir + dirName;
1305+ if (!absolutePathExists (path, canonicalPath)) {
1306+ debug (" removing directory '%s' from RPATH because it's not under the root directory\n " ,
1307+ dirName.c_str ());
1308+ continue ;
11951309 }
1310+ }
1311+
1312+ if (noStandardLibDirs) {
1313+ if (!canonicalPath.compare (rootDir + " /lib" ) ||
1314+ !canonicalPath.compare (rootDir + " /usr/lib" )) {
1315+ debug (" removing directory '%s' from RPATH because it's a standard library directory\n " ,
1316+ dirName.c_str ());
1317+ continue ;
1318+ }
1319+ }
11961320
1197- if (!libFound)
1321+ if (!libFoundInRPath (canonicalPath, neededLibs, neededLibFound)) {
11981322 debug (" removing directory '%s' from RPATH\n " , dirName.c_str ());
1323+ continue ;
1324+ }
1325+
1326+ /* Finally make "canonicalPath" relative to "filedir" in "rootDir" */
1327+ if (relativeToFile)
1328+ concatToRPath (newRPath, makePathRelative (canonicalPath, fileDir));
11991329 else
1200- concatToRPath (newRPath, dirName);
1330+ concatToRPath (newRPath, canonicalPath.substr (rootDir.length ()));
1331+ debug (" keeping relative path of %s\n " , canonicalPath.c_str ());
12011332 }
12021333 }
12031334
@@ -1528,7 +1659,9 @@ static std::vector<std::string> allowedRpathPrefixes;
15281659static bool removeRPath = false ;
15291660static bool setRPath = false ;
15301661static bool printRPath = false ;
1662+ static bool makeRPathRelative = false ;
15311663static std::string newRPath;
1664+ static std::string rootDir;
15321665static std::set<std::string> neededLibsToRemove;
15331666static std::map<std::string, std::string> neededLibsToReplace;
15341667static std::set<std::string> neededLibsToAdd;
@@ -1551,14 +1684,16 @@ static void patchElf2(ElfFile && elfFile)
15511684 elfFile.setInterpreter (newInterpreter);
15521685
15531686 if (printRPath)
1554- elfFile.modifyRPath (elfFile.rpPrint , {}, " " );
1687+ elfFile.modifyRPath (elfFile.rpPrint , {}, {}, " " );
15551688
15561689 if (shrinkRPath)
1557- elfFile.modifyRPath (elfFile.rpShrink , allowedRpathPrefixes, " " );
1690+ elfFile.modifyRPath (elfFile.rpShrink , allowedRpathPrefixes, " " , " " );
15581691 else if (removeRPath)
1559- elfFile.modifyRPath (elfFile.rpRemove , {}, " " );
1692+ elfFile.modifyRPath (elfFile.rpRemove , {}, " " , " " );
15601693 else if (setRPath)
1561- elfFile.modifyRPath (elfFile.rpSet , {}, newRPath);
1694+ elfFile.modifyRPath (elfFile.rpSet , {}, " " , newRPath);
1695+ else if (makeRPathRelative)
1696+ elfFile.modifyRPath (elfFile.rpMakeRelative , {}, rootDir, " " );
15621697
15631698 if (printNeeded) elfFile.printNeededLibs ();
15641699
@@ -1604,6 +1739,9 @@ void showHelp(const std::string & progName)
16041739 [--remove-rpath]\n \
16051740 [--shrink-rpath]\n \
16061741 [--allowed-rpath-prefixes PREFIXES]\t\t With '--shrink-rpath', reject rpath entries not starting with the allowed prefix\n \
1742+ [--make-rpath-relative ROOTDIR]\n \
1743+ [--no-standard-lib-dirs]\n \
1744+ [--relative-to-file]\n \
16071745 [--print-rpath]\n \
16081746 [--force-rpath]\n \
16091747 [--add-needed LIBRARY]\n \
@@ -1664,6 +1802,17 @@ int mainWrapped(int argc, char * * argv)
16641802 setRPath = true ;
16651803 newRPath = argv[i];
16661804 }
1805+ else if (arg == " --make-rpath-relative" ) {
1806+ if (++i == argc) error (" missing argument to --make-rpath-relative" );
1807+ makeRPathRelative = true ;
1808+ rootDir = argv[i];
1809+ }
1810+ else if (arg == " --no-standard-lib-dirs" ) {
1811+ noStandardLibDirs = true ;
1812+ }
1813+ else if (arg == " --relative-to-file" ) {
1814+ relativeToFile = true ;
1815+ }
16671816 else if (arg == " --print-rpath" ) {
16681817 printRPath = true ;
16691818 }
0 commit comments