@@ -60,6 +60,10 @@ static bool debugMode = false;
60
60
static bool forceRPath = false ;
61
61
static bool clobberOldSections = true ;
62
62
63
+ static bool noStandardLibDirs = false ;
64
+
65
+ static bool relativeToFile = false ;
66
+
63
67
static std::vector<std::string> fileNames;
64
68
static std::string outputFileName;
65
69
static bool alwaysWrite = false ;
@@ -264,6 +268,49 @@ static std::string extractString(const FileContents & contents, size_t offset, s
264
268
return { reinterpret_cast <const char *>(contents->data ()) + offset, size };
265
269
}
266
270
271
+ static bool absolutePathExists (const std::string & path, std::string & canonicalPath)
272
+ {
273
+ char *cpath = realpath (path.c_str (), NULL );
274
+ if (cpath) {
275
+ canonicalPath = cpath;
276
+ free (cpath);
277
+ return true ;
278
+ } else {
279
+ return false ;
280
+ }
281
+ }
282
+
283
+ static std::string makePathRelative (const std::string & path,
284
+ const std::string & refPath)
285
+ {
286
+ std::string relPath = " $ORIGIN" ;
287
+ std::string p = path, refP = refPath;
288
+ std::size_t pos;
289
+
290
+ /* Strip the common part of path and refPath */
291
+ while (true ) {
292
+ pos = p.find_first_of (' /' , 1 );
293
+ if (refP.find_first_of (' /' , 1 ) != pos)
294
+ break ;
295
+ if (p.substr (0 , pos) != refP.substr (0 , pos))
296
+ break ;
297
+ if (pos == std::string::npos)
298
+ break ;
299
+ p = p.substr (pos);
300
+ refP = refP.substr (pos);
301
+ }
302
+ /* Check if both pathes are equal */
303
+ if (p != refP) {
304
+ pos = 0 ;
305
+ while (pos != std::string::npos) {
306
+ pos =refP.find_first_of (' /' , pos + 1 );
307
+ relPath.append (" /.." );
308
+ }
309
+ relPath.append (p);
310
+ }
311
+
312
+ return relPath;
313
+ }
267
314
268
315
template <ElfFileParams>
269
316
ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents )
@@ -1524,6 +1571,30 @@ static void appendRPath(std::string & rpath, const std::string & path)
1524
1571
rpath += path;
1525
1572
}
1526
1573
1574
+ template <ElfFileParams>
1575
+ bool ElfFile<ElfFileParamNames>::libFoundInRPath(const std::string & dirName,
1576
+ const std::vector<std::string> neededLibs, std::vector<bool > & neededLibFound)
1577
+ {
1578
+ /* For each library that we haven't found yet, see if it
1579
+ exists in this directory. */
1580
+ bool libFound = false ;
1581
+ for (unsigned int j = 0 ; j < neededLibs.size (); ++j)
1582
+ if (!neededLibFound.at (j)) {
1583
+ std::string libName = dirName + " /" + neededLibs.at (j);
1584
+ try {
1585
+ Elf32_Half library_e_machine = getElfType (readFile (libName, sizeof (Elf32_Ehdr))).machine ;
1586
+ if (rdi (library_e_machine) == rdi (hdr ()->e_machine )) {
1587
+ neededLibFound.at (j) = true ;
1588
+ libFound = true ;
1589
+ } else
1590
+ debug (" ignoring library '%s' because its machine type differs\n " , libName.c_str ());
1591
+ } catch (SysError & e) {
1592
+ if (e.errNo != ENOENT) throw ;
1593
+ }
1594
+ }
1595
+ return libFound;
1596
+ }
1597
+
1527
1598
/* For each directory in the RPATH, check if it contains any
1528
1599
needed library. */
1529
1600
template <ElfFileParams>
@@ -1548,25 +1619,7 @@ std::string ElfFile<ElfFileParamNames>::shrinkRPath(char* rpath, std::vector<std
1548
1619
continue ;
1549
1620
}
1550
1621
1551
- /* For each library that we haven't found yet, see if it
1552
- exists in this directory. */
1553
- bool libFound = false ;
1554
- for (unsigned int j = 0 ; j < neededLibs.size (); ++j)
1555
- if (!neededLibFound.at (j)) {
1556
- std::string libName = dirName + " /" + neededLibs.at (j);
1557
- try {
1558
- Elf32_Half library_e_machine = getElfType (readFile (libName, sizeof (Elf32_Ehdr))).machine ;
1559
- if (rdi (library_e_machine) == rdi (hdr ()->e_machine )) {
1560
- neededLibFound.at (j) = true ;
1561
- libFound = true ;
1562
- } else
1563
- debug (" ignoring library '%s' because its machine type differs\n " , libName.c_str ());
1564
- } catch (SysError & e) {
1565
- if (e.errNo != ENOENT) throw ;
1566
- }
1567
- }
1568
-
1569
- if (!libFound)
1622
+ if (!libFoundInRPath (dirName, neededLibs, neededLibFound))
1570
1623
debug (" removing directory '%s' from RPATH\n " , dirName.c_str ());
1571
1624
else
1572
1625
appendRPath (newRPath, dirName);
@@ -1575,6 +1628,86 @@ std::string ElfFile<ElfFileParamNames>::shrinkRPath(char* rpath, std::vector<std
1575
1628
return newRPath;
1576
1629
}
1577
1630
1631
+ /* Make the the RPATH relative to the specified path */
1632
+ template <ElfFileParams>
1633
+ std::string ElfFile<ElfFileParamNames>::makeRelativeRPath(char * rpath, std::vector<std::string> &neededLibs, const std::string & rootDir, const std::string & fileName) {
1634
+ std::vector<bool > neededLibFound (neededLibs.size (), false );
1635
+ std::string fileDir = fileName.substr (0 , fileName.find_last_of (" /" ));
1636
+ std::string newRPath = " " ;
1637
+
1638
+ debug (" makeRelativeRPath: fileName = '%s'\n " , fileName.c_str ());
1639
+
1640
+ for (auto & dirName : splitColonDelimitedString (rpath)) {
1641
+ std::string canonicalPath;
1642
+ std::string path;
1643
+
1644
+ debug (" makeRelativeRPath: dirName = '%s'\n " , dirName.c_str ());
1645
+
1646
+ /* Figure out if we should keep or discard the path; there are several
1647
+ cases to handle:
1648
+ "dirName" starts with "$ORIGIN":
1649
+ The original build-system already took care of setting a relative
1650
+ RPATH, resolve it and test if it is worthwhile to keep it.
1651
+ "dirName" start with "rootDir":
1652
+ The original build-system added some absolute RPATH (absolute on
1653
+ the build machine). While this is wrong, it can still be fixed; so
1654
+ test if it is worthwhile to keep it.
1655
+ "rootDir"/"dirName" exists:
1656
+ The original build-system already took care of setting an absolute
1657
+ RPATH (absolute in the final rootfs), resolve it and test if it is
1658
+ worthwhile to keep it;
1659
+ "dirName" points somewhere else:
1660
+ (can be anywhere: build trees, staging tree, host location,
1661
+ non-existing location, etc.). Just discard such a path. */
1662
+ if (!dirName.compare (0 , 7 , " $ORIGIN" )) {
1663
+ path = fileDir + dirName.substr (7 );
1664
+ if (!absolutePathExists (path, canonicalPath)) {
1665
+ debug (" removing directory '%s' from RPATH because it doesn't exist\n " , dirName.c_str ());
1666
+ continue ;
1667
+ }
1668
+ } else if (!dirName.compare (0 , rootDir.length (), rootDir)) {
1669
+ if (!absolutePathExists (dirName, canonicalPath)) {
1670
+ debug (" removing directory '%s' from RPATH because it doesn't exist\n " , dirName.c_str ());
1671
+ continue ;
1672
+ }
1673
+ } else {
1674
+ path = rootDir + dirName;
1675
+ if (!absolutePathExists (path, canonicalPath)) {
1676
+ debug (" removing directory '%s' from RPATH because it's not under the root directory\n " ,
1677
+ dirName.c_str ());
1678
+ continue ;
1679
+ }
1680
+ }
1681
+
1682
+ if (noStandardLibDirs) {
1683
+ if (!canonicalPath.compare (rootDir + " /lib" ) ||
1684
+ !canonicalPath.compare (rootDir + " /usr/lib" )) {
1685
+ debug (" removing directory '%s' from RPATH because it's a standard library directory\n " ,
1686
+ dirName.c_str ());
1687
+ continue ;
1688
+ }
1689
+ }
1690
+
1691
+ if (!libFoundInRPath (canonicalPath, neededLibs, neededLibFound)) {
1692
+ debug (" removing directory '%s' from RPATH\n " , dirName.c_str ());
1693
+ continue ;
1694
+ }
1695
+
1696
+ /* Finally make "canonicalPath" relative to "filedir" in "rootDir" */
1697
+ if (relativeToFile) {
1698
+ debug (" making RPATH relative to FILE\n " );
1699
+ appendRPath (newRPath, makePathRelative (canonicalPath, fileDir));
1700
+ }
1701
+ else {
1702
+ debug (" not making RPATH relative to FILE\n " );
1703
+ appendRPath (newRPath, canonicalPath.substr (rootDir.length ()));
1704
+ }
1705
+ debug (" keeping relative path of %s\n " , canonicalPath.c_str ());
1706
+ }
1707
+
1708
+ return newRPath;
1709
+ }
1710
+
1578
1711
template <ElfFileParams>
1579
1712
void ElfFile<ElfFileParamNames>::removeRPath(Elf_Shdr & shdrDynamic) {
1580
1713
auto dyn = (Elf_Dyn *)(fileContents->data () + rdi (shdrDynamic.sh_offset ));
@@ -1596,7 +1729,7 @@ void ElfFile<ElfFileParamNames>::removeRPath(Elf_Shdr & shdrDynamic) {
1596
1729
1597
1730
template <ElfFileParams>
1598
1731
void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
1599
- const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath)
1732
+ const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath, const std::string & rootDir, const std::string & fileName )
1600
1733
{
1601
1734
auto shdrDynamic = findSectionHeader (" .dynamic" );
1602
1735
@@ -1643,6 +1776,8 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
1643
1776
neededLibs.push_back (std::string (strTab + rdi (dyn->d_un .d_val )));
1644
1777
}
1645
1778
1779
+ printf (" modifyRPath: op = %d\n " , op);
1780
+
1646
1781
switch (op) {
1647
1782
case rpPrint: {
1648
1783
printf (" %s\n " , rpath ? rpath : " " );
@@ -1671,6 +1806,15 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
1671
1806
break ;
1672
1807
}
1673
1808
case rpSet: { break ; } /* new rpath was provied as input to this function */
1809
+ case rpMakeRelative: {
1810
+ if (!rpath) {
1811
+ debug (" no RPATH to make relative\n " );
1812
+ return ;
1813
+ }
1814
+ debug (" making RPATH relative\n " );
1815
+ newRPath = makeRelativeRPath (rpath, neededLibs, rootDir, fileName);
1816
+ break ;
1817
+ }
1674
1818
}
1675
1819
1676
1820
if (!forceRPath && dynRPath && !dynRunPath) { /* convert DT_RPATH to DT_RUNPATH */
@@ -2429,7 +2573,9 @@ static bool addRPath = false;
2429
2573
static bool addDebugTag = false ;
2430
2574
static bool renameDynamicSymbols = false ;
2431
2575
static bool printRPath = false ;
2576
+ static bool makeRPathRelative = false ;
2432
2577
static std::string newRPath;
2578
+ static std::string rootDir;
2433
2579
static std::set<std::string> neededLibsToRemove;
2434
2580
static std::map<std::string, std::string> neededLibsToReplace;
2435
2581
static std::set<std::string> neededLibsToAdd;
@@ -2464,23 +2610,31 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
2464
2610
elfFile.setInterpreter (newInterpreter);
2465
2611
2466
2612
if (printRPath)
2467
- elfFile.modifyRPath (elfFile.rpPrint , {}, " " );
2613
+ elfFile.modifyRPath (elfFile.rpPrint , {}, " " , rootDir, fileName );
2468
2614
2469
2615
if (printExecstack)
2470
2616
elfFile.modifyExecstack (ElfFile::ExecstackMode::print);
2471
2617
else if (clearExecstack)
2472
2618
elfFile.modifyExecstack (ElfFile::ExecstackMode::clear);
2473
2619
else if (setExecstack)
2474
2620
elfFile.modifyExecstack (ElfFile::ExecstackMode::set);
2621
+ else
2622
+ printf (" patchElf2: nothing done 1\n " );
2623
+
2624
+ printf (" patchElf2: makeRPathRelativeop = %d\n " , makeRPathRelative);
2475
2625
2476
2626
if (shrinkRPath)
2477
- elfFile.modifyRPath (elfFile.rpShrink , allowedRpathPrefixes, " " );
2627
+ elfFile.modifyRPath (elfFile.rpShrink , allowedRpathPrefixes, " " , rootDir, fileName );
2478
2628
else if (removeRPath)
2479
- elfFile.modifyRPath (elfFile.rpRemove , {}, " " );
2629
+ elfFile.modifyRPath (elfFile.rpRemove , {}, " " , rootDir, fileName );
2480
2630
else if (setRPath)
2481
- elfFile.modifyRPath (elfFile.rpSet , {}, newRPath);
2631
+ elfFile.modifyRPath (elfFile.rpSet , {}, newRPath, rootDir, fileName );
2482
2632
else if (addRPath)
2483
- elfFile.modifyRPath (elfFile.rpAdd , {}, newRPath);
2633
+ elfFile.modifyRPath (elfFile.rpAdd , {}, newRPath, rootDir, fileName);
2634
+ else if (makeRPathRelative)
2635
+ elfFile.modifyRPath (elfFile.rpMakeRelative , {}, " " , rootDir, fileName);
2636
+ else
2637
+ printf (" patchElf2: nothing done 2\n " );
2484
2638
2485
2639
if (printNeeded) elfFile.printNeededLibs ();
2486
2640
@@ -2548,6 +2702,9 @@ static void showHelp(const std::string & progName)
2548
2702
[--remove-rpath]\n \
2549
2703
[--shrink-rpath]\n \
2550
2704
[--allowed-rpath-prefixes PREFIXES]\t\t With '--shrink-rpath', reject rpath entries not starting with the allowed prefix\n \
2705
+ [--make-rpath-relative ROOTDIR]\n \
2706
+ [--no-standard-lib-dirs]\n \
2707
+ [--relative-to-file]\n \
2551
2708
[--print-rpath]\n \
2552
2709
[--force-rpath]\n \
2553
2710
[--add-needed LIBRARY]\n \
@@ -2583,6 +2740,7 @@ static int mainWrapped(int argc, char * * argv)
2583
2740
int i;
2584
2741
for (i = 1 ; i < argc; ++i) {
2585
2742
std::string arg (argv[i]);
2743
+ debug (" mainWrapped: arg = '%s'\n " , argv[i]);
2586
2744
if (arg == " --set-interpreter" || arg == " --interpreter" ) {
2587
2745
if (++i == argc) error (" missing argument" );
2588
2746
newInterpreter = resolveArgument (argv[i]);
@@ -2631,6 +2789,19 @@ static int mainWrapped(int argc, char * * argv)
2631
2789
addRPath = true ;
2632
2790
newRPath = resolveArgument (argv[i]);
2633
2791
}
2792
+ else if (arg == " --make-rpath-relative" ) {
2793
+ if (++i == argc) error (" missing argument to --make-rpath-relative" );
2794
+ debug (" mainWrapped: makeRPathRelative = true\n " );
2795
+ makeRPathRelative = true ;
2796
+ rootDir = argv[i];
2797
+ }
2798
+ else if (arg == " --no-standard-lib-dirs" ) {
2799
+ noStandardLibDirs = true ;
2800
+ }
2801
+ else if (arg == " --relative-to-file" ) {
2802
+ debug (" mainWrapped: relativeToFile = true\n " );
2803
+ relativeToFile = true ;
2804
+ }
2634
2805
else if (arg == " --print-rpath" ) {
2635
2806
printRPath = true ;
2636
2807
}
0 commit comments