@@ -49,6 +49,8 @@ static int pageSize = PAGESIZE;
49
49
50
50
typedef std::shared_ptr<std::vector<unsigned char >> FileContents;
51
51
52
+ #define MODIFY_FLAG_NO_STD_LIB_DIRS 0x1
53
+ static int modifyFlags;
52
54
53
55
#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
54
56
#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()
83
85
return pageSize;
84
86
}
85
87
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
+ }
86
118
87
119
template <ElfFileParams>
88
120
class ElfFile
@@ -191,9 +223,14 @@ class ElfFile
191
223
192
224
void setInterpreter (const std::string & newInterpreter);
193
225
194
- typedef enum { rpPrint, rpShrink, rpSet, rpRemove } RPathOp;
226
+ typedef enum { rpPrint, rpShrink, rpMakeRelative, rpSet, rpRemove} RPathOp;
195
227
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);
197
234
198
235
void addNeeded (const std::set<std::string> & libs);
199
236
@@ -1099,10 +1136,35 @@ static void concatToRPath(std::string & rpath, const std::string & path)
1099
1136
rpath += path;
1100
1137
}
1101
1138
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
+ }
1102
1163
1103
1164
template <ElfFileParams>
1104
1165
void 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)
1106
1168
{
1107
1169
Elf_Shdr & shdrDynamic = findSection (" .dynamic" );
1108
1170
@@ -1153,11 +1215,14 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
1153
1215
return ;
1154
1216
}
1155
1217
1218
+ if (op == rpMakeRelative && !rpath) {
1219
+ debug (" no RPATH to make relative\n " );
1220
+ return ;
1221
+ }
1156
1222
1157
1223
/* For each directory in the RPATH, check if it contains any
1158
1224
needed library. */
1159
1225
if (op == rpShrink) {
1160
- std::vector<bool > neededLibFound (neededLibs.size (), false );
1161
1226
1162
1227
newRPath = " " ;
1163
1228
@@ -1177,30 +1242,78 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
1177
1242
continue ;
1178
1243
}
1179
1244
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))
1198
1246
debug (" removing directory '%s' from RPATH\n " , dirName.c_str ());
1199
1247
else
1200
1248
concatToRPath (newRPath, dirName);
1201
1249
}
1202
1250
}
1203
1251
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
+
1204
1317
if (op == rpRemove) {
1205
1318
if (!rpath) {
1206
1319
debug (" no RPATH to delete\n " );
@@ -1528,7 +1641,9 @@ static std::vector<std::string> allowedRpathPrefixes;
1528
1641
static bool removeRPath = false ;
1529
1642
static bool setRPath = false ;
1530
1643
static bool printRPath = false ;
1644
+ static bool makeRPathRelative = false ;
1531
1645
static std::string newRPath;
1646
+ static std::string rootDir;
1532
1647
static std::set<std::string> neededLibsToRemove;
1533
1648
static std::map<std::string, std::string> neededLibsToReplace;
1534
1649
static std::set<std::string> neededLibsToAdd;
@@ -1551,14 +1666,16 @@ static void patchElf2(ElfFile && elfFile)
1551
1666
elfFile.setInterpreter (newInterpreter);
1552
1667
1553
1668
if (printRPath)
1554
- elfFile.modifyRPath (elfFile.rpPrint , {}, " " );
1669
+ elfFile.modifyRPath (elfFile.rpPrint , {}, {}, modifyFlags, " " );
1555
1670
1556
1671
if (shrinkRPath)
1557
- elfFile.modifyRPath (elfFile.rpShrink , allowedRpathPrefixes, " " );
1672
+ elfFile.modifyRPath (elfFile.rpShrink , allowedRpathPrefixes, " " , modifyFlags, " " );
1558
1673
else if (removeRPath)
1559
- elfFile.modifyRPath (elfFile.rpRemove , {}, " " );
1674
+ elfFile.modifyRPath (elfFile.rpRemove , {}, " " , modifyFlags, " " );
1560
1675
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, " " );
1562
1679
1563
1680
if (printNeeded) elfFile.printNeededLibs ();
1564
1681
@@ -1604,6 +1721,8 @@ void showHelp(const std::string & progName)
1604
1721
[--remove-rpath]\n \
1605
1722
[--shrink-rpath]\n \
1606
1723
[--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 \
1607
1726
[--print-rpath]\n \
1608
1727
[--force-rpath]\n \
1609
1728
[--add-needed LIBRARY]\n \
@@ -1664,6 +1783,14 @@ int mainWrapped(int argc, char * * argv)
1664
1783
setRPath = true ;
1665
1784
newRPath = argv[i];
1666
1785
}
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
+ }
1667
1794
else if (arg == " --print-rpath" ) {
1668
1795
printRPath = true ;
1669
1796
}
0 commit comments