@@ -49,6 +49,8 @@ static int pageSize = PAGESIZE;
4949
5050typedef std::shared_ptr<std::vector<unsigned char >> FileContents;
5151
52+ #define MODIFY_FLAG_NO_STD_LIB_DIRS 0x1
53+ static int modifyFlags;
5254
5355#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
5456#define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym, Elf_Verneed
@@ -83,6 +85,36 @@ static unsigned int getPageSize()
8385 return pageSize;
8486}
8587
88+ static bool absolutePathExists (const std::string & path, std::string & canonicalPath)
89+ {
90+ char *cpath = realpath (path.c_str (), NULL );
91+ if (cpath) {
92+ canonicalPath = cpath;
93+ free (cpath);
94+ return true ;
95+ } else {
96+ return false ;
97+ }
98+ }
99+
100+ static std::string makePathRelative (const std::string & path,
101+ const std::string & refPath, const std::string & rootDir)
102+ {
103+ std::string relPath = " $ORIGIN" ;
104+
105+ /* Strip root path first */
106+ std::string p = path.substr (rootDir.length ());
107+ std::string refP = refPath.substr (rootDir.length ());
108+
109+ std::size_t pos = refP.find_first_of (' /' );
110+ while (pos != std::string::npos) {
111+ pos =refP.find_first_of (' /' , pos + 1 );
112+ relPath.append (" /.." );
113+ }
114+ relPath.append (p);
115+
116+ return relPath;
117+ }
86118
87119template <ElfFileParams>
88120class ElfFile
@@ -191,9 +223,14 @@ class ElfFile
191223
192224 void setInterpreter (const std::string & newInterpreter);
193225
194- typedef enum { rpPrint, rpShrink, rpSet, rpRemove } RPathOp;
226+ typedef enum { rpPrint, rpShrink, rpMakeRelative, rpSet, rpRemove} RPathOp;
195227
196- void modifyRPath (RPathOp op, const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath);
228+ bool libFoundInRPath (const std::string & dirName,
229+ const std::vector<std::string> neededLibs);
230+
231+ void modifyRPath (RPathOp op,
232+ const std::vector<std::string> & allowedRpathPrefixes,
233+ std::string rootDir, int flags, std::string newRPath);
197234
198235 void addNeeded (const std::set<std::string> & libs);
199236
@@ -1099,10 +1136,35 @@ static void concatToRPath(std::string & rpath, const std::string & path)
10991136 rpath += path;
11001137}
11011138
1139+ template <ElfFileParams>
1140+ bool ElfFile<ElfFileParamNames>::libFoundInRPath(const std::string & dirName,
1141+ const std::vector<std::string> neededLibs)
1142+ {
1143+ std::vector<bool > neededLibFound (neededLibs.size (), false );
1144+
1145+ /* For each library that we haven't found yet, see if it
1146+ exists in this directory. */
1147+ bool libFound = false ;
1148+ for (unsigned int j = 0 ; j < neededLibs.size (); ++j)
1149+ if (!neededLibFound[j]) {
1150+ std::string libName = dirName + " /" + neededLibs[j];
1151+ try {
1152+ if (getElfType (readFile (libName, sizeof (Elf32_Ehdr))).machine == rdi (hdr->e_machine )) {
1153+ neededLibFound[j] = true ;
1154+ libFound = true ;
1155+ } else
1156+ debug (" ignoring library '%s' because its machine type differs\n " , libName.c_str ());
1157+ } catch (SysError & e) {
1158+ if (e.errNo != ENOENT) throw ;
1159+ }
1160+ }
1161+ return libFound;
1162+ }
11021163
11031164template <ElfFileParams>
11041165void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
1105- const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath)
1166+ const std::vector<std::string> & allowedRpathPrefixes,
1167+ std::string rootDir, int flags, std::string newRPath)
11061168{
11071169 Elf_Shdr & shdrDynamic = findSection (" .dynamic" );
11081170
@@ -1153,11 +1215,14 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
11531215 return ;
11541216 }
11551217
1218+ if (op == rpMakeRelative && !rpath) {
1219+ debug (" no RPATH to make relative\n " );
1220+ return ;
1221+ }
11561222
11571223 /* For each directory in the RPATH, check if it contains any
11581224 needed library. */
11591225 if (op == rpShrink) {
1160- std::vector<bool > neededLibFound (neededLibs.size (), false );
11611226
11621227 newRPath = " " ;
11631228
@@ -1177,30 +1242,78 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
11771242 continue ;
11781243 }
11791244
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- }
1195- }
1196-
1197- if (!libFound)
1245+ if (!libFoundInRPath (dirName, neededLibs))
11981246 debug (" removing directory '%s' from RPATH\n " , dirName.c_str ());
11991247 else
12001248 concatToRPath (newRPath, dirName);
12011249 }
12021250 }
12031251
1252+ /* Make the the RPATH relative to the specified path */
1253+ if (op == rpMakeRelative) {
1254+ std::string fileDir = fileName.substr (0 , fileName.find_last_of (" /" ));
1255+ newRPath = " " ;
1256+
1257+ for (auto & dirName : splitColonDelimitedString (rpath)) {
1258+ std::string canonicalPath;
1259+ std::string path;
1260+
1261+ /* Figure out if we should keep or discard the path; there are several
1262+ cases to handled:
1263+ "dirName" starts with "$ORIGIN":
1264+ The original build-system already took care of setting a relative
1265+ RPATH, resolve it and test if it is worthwhile to keep it.
1266+ "dirName" start with "rootDir":
1267+ The original build-system added some absolute RPATH (absolute on
1268+ the build machine). While this is wrong, it can still be fixed; so
1269+ test if it is worthwhile to keep it.
1270+ "rootDir"/"dirName" exists:
1271+ The original build-system already took care of setting an absolute
1272+ RPATH (absolute in the final rootfs), resolve it and test if it is
1273+ worthwhile to keep it;
1274+ "dirName" points somewhere else:
1275+ (can be anywhere: build trees, staging tree, host location,
1276+ non-existing location, etc.). Just discard such a path. */
1277+ if (!dirName.compare (0 , 7 , " $ORIGIN" )) {
1278+ path = fileDir + dirName.substr (7 );
1279+ if (!absolutePathExists (path, canonicalPath)) {
1280+ debug (" removing directory '%s' from RPATH because it doesn't exist\n " , dirName.c_str ());
1281+ continue ;
1282+ }
1283+ } else if (!dirName.compare (0 , rootDir.length (), rootDir)) {
1284+ if (!absolutePathExists (dirName, canonicalPath)) {
1285+ debug (" removing directory '%s' from RPATH because it doesn't exist\n " , dirName.c_str ());
1286+ continue ;
1287+ }
1288+ } else {
1289+ path = rootDir + dirName;
1290+ if (!absolutePathExists (path, canonicalPath)) {
1291+ debug (" removing directory '%s' from RPATH because it's not under the root directory\n " ,
1292+ dirName.c_str ());
1293+ continue ;
1294+ }
1295+ }
1296+
1297+ if (flags & MODIFY_FLAG_NO_STD_LIB_DIRS) {
1298+ if (!canonicalPath.compare (rootDir + " /lib" ) ||
1299+ !canonicalPath.compare (rootDir + " /usr/lib" )) {
1300+ debug (" removing directory '%s' from RPATH because it's a standard library directory\n " ,
1301+ dirName.c_str ());
1302+ continue ;
1303+ }
1304+ }
1305+
1306+ if (!libFoundInRPath (canonicalPath, neededLibs)) {
1307+ debug (" removing directory '%s' from RPATH\n " , dirName.c_str ());
1308+ continue ;
1309+ }
1310+
1311+ /* Finally make "canonicalPath" relative to "filedir" in "rootDir" */
1312+ concatToRPath (newRPath, makePathRelative (canonicalPath, fileDir, rootDir));
1313+ debug (" keeping relative path of %s\n " , canonicalPath.c_str ());
1314+ }
1315+ }
1316+
12041317 if (op == rpRemove) {
12051318 if (!rpath) {
12061319 debug (" no RPATH to delete\n " );
@@ -1528,7 +1641,9 @@ static std::vector<std::string> allowedRpathPrefixes;
15281641static bool removeRPath = false ;
15291642static bool setRPath = false ;
15301643static bool printRPath = false ;
1644+ static bool makeRPathRelative = false ;
15311645static std::string newRPath;
1646+ static std::string rootDir;
15321647static std::set<std::string> neededLibsToRemove;
15331648static std::map<std::string, std::string> neededLibsToReplace;
15341649static std::set<std::string> neededLibsToAdd;
@@ -1551,14 +1666,16 @@ static void patchElf2(ElfFile && elfFile)
15511666 elfFile.setInterpreter (newInterpreter);
15521667
15531668 if (printRPath)
1554- elfFile.modifyRPath (elfFile.rpPrint , {}, " " );
1669+ elfFile.modifyRPath (elfFile.rpPrint , {}, {}, modifyFlags, " " );
15551670
15561671 if (shrinkRPath)
1557- elfFile.modifyRPath (elfFile.rpShrink , allowedRpathPrefixes, " " );
1672+ elfFile.modifyRPath (elfFile.rpShrink , allowedRpathPrefixes, " " , modifyFlags, " " );
15581673 else if (removeRPath)
1559- elfFile.modifyRPath (elfFile.rpRemove , {}, " " );
1674+ elfFile.modifyRPath (elfFile.rpRemove , {}, " " , modifyFlags, " " );
15601675 else if (setRPath)
1561- elfFile.modifyRPath (elfFile.rpSet , {}, newRPath);
1676+ elfFile.modifyRPath (elfFile.rpSet , {}, " " , modifyFlags, newRPath);
1677+ else if (makeRPathRelative)
1678+ elfFile.modifyRPath (elfFile.rpMakeRelative , {}, rootDir, modifyFlags, " " );
15621679
15631680 if (printNeeded) elfFile.printNeededLibs ();
15641681
@@ -1604,6 +1721,8 @@ void showHelp(const std::string & progName)
16041721 [--remove-rpath]\n \
16051722 [--shrink-rpath]\n \
16061723 [--allowed-rpath-prefixes PREFIXES]\t\t With '--shrink-rpath', reject rpath entries not starting with the allowed prefix\n \
1724+ [--make-rpath-relative ROOTDIR]\n \
1725+ [--no-standard-lib-dirs]\n \
16071726 [--print-rpath]\n \
16081727 [--force-rpath]\n \
16091728 [--add-needed LIBRARY]\n \
@@ -1664,6 +1783,14 @@ int mainWrapped(int argc, char * * argv)
16641783 setRPath = true ;
16651784 newRPath = argv[i];
16661785 }
1786+ else if (arg == " --make-rpath-relative" ) {
1787+ if (++i == argc) error (" missing argument to --make-rpath-relative" );
1788+ makeRPathRelative = true ;
1789+ rootDir = argv[i];
1790+ }
1791+ else if (arg == " --no-standard-lib-dirs" ) {
1792+ modifyFlags |= MODIFY_FLAG_NO_STD_LIB_DIRS;
1793+ }
16671794 else if (arg == " --print-rpath" ) {
16681795 printRPath = true ;
16691796 }
0 commit comments