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