36
36
#include < cstring>
37
37
38
38
#include < fcntl.h>
39
+ #include < dlfcn.h>
39
40
#include < sys/stat.h>
40
41
#include < sys/types.h>
41
42
#include < unistd.h>
43
+ #include < regex>
44
+ #include < array>
42
45
43
46
#include " elf.h"
44
47
@@ -93,6 +96,8 @@ class ElfFile
93
96
94
97
const FileContents fileContents;
95
98
99
+ const std::string fileName;
100
+
96
101
private:
97
102
98
103
std::vector<Elf_Phdr> phdrs;
@@ -118,7 +123,7 @@ class ElfFile
118
123
std::vector<SectionName> sectionsByOldIndex;
119
124
120
125
public:
121
- explicit ElfFile (FileContents fileContents);
126
+ explicit ElfFile (FileContents fileContents, std::string fileName );
122
127
123
128
bool isChanged ()
124
129
{
@@ -210,6 +215,10 @@ class ElfFile
210
215
211
216
void replaceNeeded (const std::map<std::string, std::string> & libs);
212
217
218
+ void shrinkWrap (std::map<std::string, std::string> & neededLibsToReplace, std::set<std::string> & neededLibsToAdd);
219
+
220
+ std::vector<std::string> getNeededLibs ();
221
+
213
222
void printNeededLibs () /* should be const */ ;
214
223
215
224
void noDefaultLib ();
@@ -382,8 +391,8 @@ static void checkPointer(const FileContents & contents, void * p, unsigned int s
382
391
383
392
384
393
template <ElfFileParams>
385
- ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents )
386
- : fileContents(fContents )
394
+ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents , std::string fileName )
395
+ : fileContents(fContents ), fileName(fileName)
387
396
{
388
397
/* Check the ELF header for basic validity. */
389
398
if (fileContents->size () < (off_t ) sizeof (Elf_Ehdr)) error (" missing ELF header" );
@@ -1237,7 +1246,7 @@ template<ElfFileParams>
1237
1246
std::string ElfFile<ElfFileParamNames>::getInterpreter()
1238
1247
{
1239
1248
auto shdr = findSection (" .interp" );
1240
- return std::string ((char *) fileContents->data () + rdi (shdr.sh_offset ), rdi (shdr.sh_size ));
1249
+ return std::string ((char *) fileContents->data () + rdi (shdr.sh_offset ), rdi (shdr.sh_size ) - 1 );
1241
1250
}
1242
1251
1243
1252
template <ElfFileParams>
@@ -1745,21 +1754,81 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
1745
1754
changed = true ;
1746
1755
}
1747
1756
1757
+ // https://stackoverflow.com/a/478960/143733
1758
+ std::string exec (const char * cmd) {
1759
+ std::array<char , 128 > buffer;
1760
+ std::string result;
1761
+ std::unique_ptr<FILE, decltype (&pclose )> pipe (popen (cmd, " r" ), pclose );
1762
+ if (!pipe ) {
1763
+ throw std::runtime_error (" popen() failed!" );
1764
+ }
1765
+ while (fgets (buffer.data (), buffer.size (), pipe .get ()) != nullptr ) {
1766
+ result += buffer.data ();
1767
+ }
1768
+ return result;
1769
+ }
1770
+
1748
1771
template <ElfFileParams>
1749
- void ElfFile<ElfFileParamNames>::printNeededLibs() // const
1772
+ void ElfFile<ElfFileParamNames>::shrinkWrap(std::map<std::string, std::string> & neededLibsToReplace, std::set<std::string> & neededLibsToAdd)
1773
+ {
1774
+ const std::string interpreter = getInterpreter ();
1775
+ const std::vector<std::string> needed = getNeededLibs ();
1776
+ std::stringstream ss;
1777
+ ss << interpreter << " --list " << this ->fileName ;
1778
+ const std::string cmd = ss.str ();
1779
+ const std::string lddOut = exec (cmd.c_str ());
1780
+
1781
+ std::istringstream iss (lddOut);
1782
+ std::string line;
1783
+ while (std::getline (iss, line)) {
1784
+ std::regex r (" \\ s*([^ ]+) => ([^ ]+)" );
1785
+ std::smatch matches;
1786
+ if (!std::regex_search (line, matches, r)) {
1787
+ continue ;
1788
+ }
1789
+
1790
+ std::string soname = matches.str (1 );
1791
+ std::string location = matches.str (2 );
1792
+ debug (" Found %s => %s\n " , soname.c_str (), location.c_str ());
1793
+
1794
+ // if the ELF file has this soname, then merely replace it
1795
+ if (std::find (needed.begin (), needed.end (), soname) != needed.end ()) {
1796
+ neededLibsToReplace.insert ({soname, location});
1797
+ } else {
1798
+ neededLibsToAdd.insert (location);
1799
+ }
1800
+ }
1801
+ }
1802
+
1803
+ template <ElfFileParams>
1804
+ std::vector<std::string> ElfFile<ElfFileParamNames>::getNeededLibs() // const
1750
1805
{
1751
1806
const auto shdrDynamic = findSection (" .dynamic" );
1752
1807
const auto shdrDynStr = findSection (" .dynstr" );
1753
1808
const char *strTab = (char *)fileContents->data () + rdi (shdrDynStr.sh_offset );
1754
1809
1755
1810
const Elf_Dyn *dyn = (Elf_Dyn *) (fileContents->data () + rdi (shdrDynamic.sh_offset ));
1756
1811
1812
+ std::vector<std::string> results;
1813
+
1757
1814
for (; rdi (dyn->d_tag ) != DT_NULL; dyn++) {
1758
1815
if (rdi (dyn->d_tag ) == DT_NEEDED) {
1759
1816
const char *name = strTab + rdi (dyn->d_un .d_val );
1760
- printf ( " %s \n " , name);
1817
+ results. push_back ( std::string ( name) );
1761
1818
}
1762
1819
}
1820
+
1821
+ return results;
1822
+ }
1823
+
1824
+
1825
+ template <ElfFileParams>
1826
+ void ElfFile<ElfFileParamNames>::printNeededLibs() // const
1827
+ {
1828
+ const std::vector<std::string> needed = getNeededLibs ();
1829
+ for (std::string soname : needed) {
1830
+ printf (" %s\n " , soname.c_str ());
1831
+ }
1763
1832
}
1764
1833
1765
1834
@@ -1832,6 +1901,7 @@ void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string>
1832
1901
1833
1902
static bool printInterpreter = false ;
1834
1903
static bool printSoname = false ;
1904
+ static bool shrinkWrap = false ;
1835
1905
static bool setSoname = false ;
1836
1906
static std::string newSoname;
1837
1907
static std::string newInterpreter;
@@ -1855,6 +1925,9 @@ static void patchElf2(ElfFile && elfFile, const FileContents & fileContents, con
1855
1925
if (printInterpreter)
1856
1926
printf (" %s\n " , elfFile.getInterpreter ().c_str ());
1857
1927
1928
+ if (shrinkWrap)
1929
+ elfFile.shrinkWrap (neededLibsToReplace, neededLibsToAdd);
1930
+
1858
1931
if (printSoname)
1859
1932
elfFile.modifySoname (elfFile.printSoname , " " );
1860
1933
@@ -1906,9 +1979,9 @@ static void patchElf()
1906
1979
const std::string & outputFileName2 = outputFileName.empty () ? fileName : outputFileName;
1907
1980
1908
1981
if (getElfType (fileContents).is32Bit )
1909
- patchElf2 (ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed, Elf32_Versym>(fileContents), fileContents, outputFileName2);
1982
+ patchElf2 (ElfFile<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Addr, Elf32_Off, Elf32_Dyn, Elf32_Sym, Elf32_Verneed, Elf32_Versym>(fileContents, fileName ), fileContents, outputFileName2);
1910
1983
else
1911
- patchElf2 (ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, Elf64_Versym>(fileContents), fileContents, outputFileName2);
1984
+ patchElf2 (ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Addr, Elf64_Off, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, Elf64_Versym>(fileContents, fileName ), fileContents, outputFileName2);
1912
1985
}
1913
1986
}
1914
1987
@@ -1927,6 +2000,7 @@ void showHelp(const std::string & progName)
1927
2000
fprintf (stderr, " syntax: %s\n \
1928
2001
[--set-interpreter FILENAME]\n \
1929
2002
[--page-size SIZE]\n \
2003
+ [--shrink-wrap]\n \
1930
2004
[--print-interpreter]\n \
1931
2005
[--print-soname]\t\t Prints 'DT_SONAME' entry of .dynamic section. Raises an error if DT_SONAME doesn't exist\n \
1932
2006
[--set-soname SONAME]\t\t Sets 'DT_SONAME' entry to SONAME.\n \
@@ -1978,6 +2052,9 @@ int mainWrapped(int argc, char * * argv)
1978
2052
else if (arg == " --print-soname" ) {
1979
2053
printSoname = true ;
1980
2054
}
2055
+ else if (arg == " --shrink-wrap" ) {
2056
+ shrinkWrap = true ;
2057
+ }
1981
2058
else if (arg == " --set-soname" ) {
1982
2059
if (++i == argc) error (" missing argument" );
1983
2060
setSoname = true ;
0 commit comments