41
41
#include < unistd.h>
42
42
43
43
#include " elf.h"
44
+ #include " patchelf.h"
44
45
45
46
#ifndef PACKAGE_STRING
46
47
#define PACKAGE_STRING " patchelf"
@@ -63,11 +64,6 @@ static int forcedPageSize = -1;
63
64
#define EM_LOONGARCH 258
64
65
#endif
65
66
66
- using FileContents = std::shared_ptr<std::vector<unsigned char >>;
67
-
68
- #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 , class Elf_Versym
69
- #define ElfFileParamNames Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym, Elf_Verneed, Elf_Versym
70
-
71
67
72
68
static std::vector<std::string> splitColonDelimitedString (const char * s)
73
69
{
@@ -85,163 +81,6 @@ static bool hasAllowedPrefix(const std::string & s, const std::vector<std::strin
85
81
return std::any_of (allowedPrefixes.begin (), allowedPrefixes.end (), [&](const std::string & i) { return !s.compare (0 , i.size (), i); });
86
82
}
87
83
88
-
89
- template <ElfFileParams>
90
- class ElfFile
91
- {
92
- public:
93
-
94
- const FileContents fileContents;
95
-
96
- private:
97
-
98
- std::vector<Elf_Phdr> phdrs;
99
- std::vector<Elf_Shdr> shdrs;
100
-
101
- bool littleEndian;
102
-
103
- bool changed = false ;
104
-
105
- bool isExecutable = false ;
106
-
107
- using SectionName = std::string;
108
- using ReplacedSections = std::map<SectionName, std::string>;
109
-
110
- ReplacedSections replacedSections;
111
-
112
- std::string sectionNames; /* content of the .shstrtab section */
113
-
114
- /* Align on 4 or 8 bytes boundaries on 32- or 64-bit platforms
115
- respectively. */
116
- size_t sectionAlignment = sizeof (Elf_Off);
117
-
118
- std::vector<SectionName> sectionsByOldIndex;
119
-
120
- public:
121
- explicit ElfFile (FileContents fileContents);
122
-
123
- bool isChanged ()
124
- {
125
- return changed;
126
- }
127
-
128
- private:
129
-
130
- struct CompPhdr
131
- {
132
- ElfFile * elfFile;
133
- bool operator ()(const Elf_Phdr & x, const Elf_Phdr & y)
134
- {
135
- // A PHDR comes before everything else.
136
- if (elfFile->rdi (y.p_type ) == PT_PHDR) return false ;
137
- if (elfFile->rdi (x.p_type ) == PT_PHDR) return true ;
138
-
139
- // Sort non-PHDRs by address.
140
- return elfFile->rdi (x.p_paddr ) < elfFile->rdi (y.p_paddr );
141
- }
142
- };
143
-
144
- friend struct CompPhdr ;
145
-
146
- void sortPhdrs ();
147
-
148
- struct CompShdr
149
- {
150
- ElfFile * elfFile;
151
- bool operator ()(const Elf_Shdr & x, const Elf_Shdr & y)
152
- {
153
- return elfFile->rdi (x.sh_offset ) < elfFile->rdi (y.sh_offset );
154
- }
155
- };
156
-
157
- friend struct CompShdr ;
158
-
159
- unsigned int getPageSize () const ;
160
-
161
- void sortShdrs ();
162
-
163
- void shiftFile (unsigned int extraPages, Elf_Addr startPage);
164
-
165
- std::string getSectionName (const Elf_Shdr & shdr) const ;
166
-
167
- Elf_Shdr & findSection (const SectionName & sectionName);
168
-
169
- std::optional<std::reference_wrapper<Elf_Shdr>> findSection2 (const SectionName & sectionName);
170
-
171
- unsigned int findSection3 (const SectionName & sectionName);
172
-
173
- std::string & replaceSection (const SectionName & sectionName,
174
- unsigned int size);
175
-
176
- bool haveReplacedSection (const SectionName & sectionName) const ;
177
-
178
- void writeReplacedSections (Elf_Off & curOff,
179
- Elf_Addr startAddr, Elf_Off startOffset);
180
-
181
- void rewriteHeaders (Elf_Addr phdrAddress);
182
-
183
- void rewriteSectionsLibrary ();
184
-
185
- void rewriteSectionsExecutable ();
186
-
187
- void normalizeNoteSegments ();
188
-
189
- public:
190
-
191
- void rewriteSections ();
192
-
193
- std::string getInterpreter ();
194
-
195
- typedef enum { printSoname, replaceSoname } sonameMode;
196
-
197
- void modifySoname (sonameMode op, const std::string & newSoname);
198
-
199
- void setInterpreter (const std::string & newInterpreter);
200
-
201
- typedef enum { rpPrint, rpShrink, rpSet, rpAdd, rpRemove } RPathOp;
202
-
203
- void modifyRPath (RPathOp op, const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath);
204
- std::string shrinkRPath (char * rpath, std::vector<std::string> &neededLibs, const std::vector<std::string> & allowedRpathPrefixes);
205
- void removeRPath (Elf_Shdr & shdrDynamic);
206
-
207
- void addNeeded (const std::set<std::string> & libs);
208
-
209
- void removeNeeded (const std::set<std::string> & libs);
210
-
211
- void replaceNeeded (const std::map<std::string, std::string> & libs);
212
-
213
- void printNeededLibs () /* should be const */ ;
214
-
215
- void noDefaultLib ();
216
-
217
- void clearSymbolVersions (const std::set<std::string> & syms);
218
-
219
- private:
220
-
221
- /* Convert an integer in big or little endian representation (as
222
- specified by the ELF header) to this platform's integer
223
- representation. */
224
- template <class I >
225
- I rdi (I i) const ;
226
-
227
- /* Convert back to the ELF representation. */
228
- template <class I >
229
- I wri (I & t, unsigned long long i) const
230
- {
231
- t = rdi ((I) i);
232
- return i;
233
- }
234
-
235
- Elf_Ehdr *hdr () {
236
- return (Elf_Ehdr *)fileContents->data ();
237
- }
238
-
239
- const Elf_Ehdr *hdr () const {
240
- return (const Elf_Ehdr *)fileContents->data ();
241
- }
242
- };
243
-
244
-
245
84
/* !!! G++ creates broken code if this function is inlined, don't know
246
85
why... */
247
86
template <ElfFileParams>
@@ -630,7 +469,7 @@ std::string ElfFile<ElfFileParamNames>::getSectionName(const Elf_Shdr & shdr) co
630
469
631
470
632
471
template <ElfFileParams>
633
- Elf_Shdr & ElfFile<ElfFileParamNames>::findSection (const SectionName & sectionName)
472
+ Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader (const SectionName & sectionName)
634
473
{
635
474
auto shdr = findSection2 (sectionName);
636
475
if (!shdr) {
@@ -654,7 +493,7 @@ std::optional<std::reference_wrapper<Elf_Shdr>> ElfFile<ElfFileParamNames>::find
654
493
655
494
656
495
template <ElfFileParams>
657
- unsigned int ElfFile<ElfFileParamNames>::findSection3 (const SectionName & sectionName)
496
+ unsigned int ElfFile<ElfFileParamNames>::getSectionIndex (const SectionName & sectionName)
658
497
{
659
498
for (unsigned int i = 1 ; i < rdi (hdr ()->e_shnum ); ++i)
660
499
if (getSectionName (shdrs.at (i)) == sectionName) return i;
@@ -677,7 +516,7 @@ std::string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sec
677
516
if (i != replacedSections.end ()) {
678
517
s = std::string (i->second );
679
518
} else {
680
- auto shdr = findSection (sectionName);
519
+ auto shdr = findSectionHeader (sectionName);
681
520
s = std::string ((char *) fileContents->data () + rdi (shdr.sh_offset ), rdi (shdr.sh_size ));
682
521
}
683
522
@@ -697,15 +536,15 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
697
536
clobbering previously written new section contents. */
698
537
for (auto & i : replacedSections) {
699
538
const std::string & sectionName = i.first ;
700
- Elf_Shdr & shdr = findSection (sectionName);
539
+ Elf_Shdr & shdr = findSectionHeader (sectionName);
701
540
if (rdi (shdr.sh_type ) != SHT_NOBITS)
702
541
memset (fileContents->data () + rdi (shdr.sh_offset ), ' X' , rdi (shdr.sh_size ));
703
542
}
704
543
705
544
std::set<unsigned int > noted_phdrs = {};
706
545
for (auto & i : replacedSections) {
707
546
const std::string & sectionName = i.first ;
708
- auto & shdr = findSection (sectionName);
547
+ auto & shdr = findSectionHeader (sectionName);
709
548
Elf_Shdr orig_shdr = shdr;
710
549
debug (" rewriting section '%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\n " ,
711
550
sectionName.c_str (), rdi (shdr.sh_offset ), rdi (shdr.sh_size ), curOff, i.second .size ());
@@ -1024,7 +863,7 @@ void ElfFile<ElfFileParamNames>::normalizeNoteSegments()
1024
863
1025
864
/* We don't need to do anything if no note segments were replaced. */
1026
865
bool replaced_note = std::any_of (replacedSections.begin (), replacedSections.end (),
1027
- [this ](std::pair<const std::string, std::string> & i) { return rdi (findSection (i.first ).sh_type ) == SHT_NOTE; });
866
+ [this ](std::pair<const std::string, std::string> & i) { return rdi (findSectionHeader (i.first ).sh_type ) == SHT_NOTE; });
1028
867
if (!replaced_note) return ;
1029
868
1030
869
std::vector<Elf_Phdr> newPhdrs;
@@ -1134,13 +973,13 @@ void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress)
1134
973
unsigned int d_tag;
1135
974
for (auto dyn = dyn_table; (d_tag = rdi (dyn->d_tag )) != DT_NULL; dyn++)
1136
975
if (d_tag == DT_STRTAB)
1137
- dyn->d_un .d_ptr = findSection (" .dynstr" ).sh_addr ;
976
+ dyn->d_un .d_ptr = findSectionHeader (" .dynstr" ).sh_addr ;
1138
977
else if (d_tag == DT_STRSZ)
1139
- dyn->d_un .d_val = findSection (" .dynstr" ).sh_size ;
978
+ dyn->d_un .d_val = findSectionHeader (" .dynstr" ).sh_size ;
1140
979
else if (d_tag == DT_SYMTAB)
1141
- dyn->d_un .d_ptr = findSection (" .dynsym" ).sh_addr ;
980
+ dyn->d_un .d_ptr = findSectionHeader (" .dynsym" ).sh_addr ;
1142
981
else if (d_tag == DT_HASH)
1143
- dyn->d_un .d_ptr = findSection (" .hash" ).sh_addr ;
982
+ dyn->d_un .d_ptr = findSectionHeader (" .hash" ).sh_addr ;
1144
983
else if (d_tag == DT_GNU_HASH) {
1145
984
auto shdr = findSection2 (" .gnu.hash" );
1146
985
// some binaries might this section stripped
@@ -1172,15 +1011,15 @@ void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress)
1172
1011
dyn->d_un .d_ptr = (*shdr).get ().sh_addr ;
1173
1012
}
1174
1013
else if (d_tag == DT_VERNEED)
1175
- dyn->d_un .d_ptr = findSection (" .gnu.version_r" ).sh_addr ;
1014
+ dyn->d_un .d_ptr = findSectionHeader (" .gnu.version_r" ).sh_addr ;
1176
1015
else if (d_tag == DT_VERSYM)
1177
- dyn->d_un .d_ptr = findSection (" .gnu.version" ).sh_addr ;
1016
+ dyn->d_un .d_ptr = findSectionHeader (" .gnu.version" ).sh_addr ;
1178
1017
else if (d_tag == DT_MIPS_RLD_MAP_REL) {
1179
1018
/* the MIPS_RLD_MAP_REL tag stores the offset to the debug
1180
1019
pointer, relative to the address of the tag */
1181
1020
auto shdr = findSection2 (" .rld_map" );
1182
1021
if (shdr) {
1183
- auto rld_map_addr = findSection (" .rld_map" ).sh_addr ;
1022
+ auto rld_map_addr = findSectionHeader (" .rld_map" ).sh_addr ;
1184
1023
auto dyn_offset = ((char *)dyn) - ((char *)dyn_table);
1185
1024
dyn->d_un .d_ptr = rld_map_addr + dyn_offset - (*shdrDynamic).get ().sh_addr ;
1186
1025
} else {
@@ -1236,7 +1075,7 @@ static void setSubstr(std::string & s, unsigned int pos, const std::string & t)
1236
1075
template <ElfFileParams>
1237
1076
std::string ElfFile<ElfFileParamNames>::getInterpreter()
1238
1077
{
1239
- auto shdr = findSection (" .interp" );
1078
+ auto shdr = findSectionHeader (" .interp" );
1240
1079
return std::string ((char *) fileContents->data () + rdi (shdr.sh_offset ), rdi (shdr.sh_size ) - 1 );
1241
1080
}
1242
1081
@@ -1248,8 +1087,8 @@ void ElfFile<ElfFileParamNames>::modifySoname(sonameMode op, const std::string &
1248
1087
return ;
1249
1088
}
1250
1089
1251
- auto shdrDynamic = findSection (" .dynamic" );
1252
- auto shdrDynStr = findSection (" .dynstr" );
1090
+ auto shdrDynamic = findSectionHeader (" .dynamic" );
1091
+ auto shdrDynStr = findSectionHeader (" .dynstr" );
1253
1092
char * strTab = (char *) fileContents->data () + rdi (shdrDynStr.sh_offset );
1254
1093
1255
1094
/* Walk through the dynamic section, look for the DT_SONAME entry. */
@@ -1401,7 +1240,7 @@ template<ElfFileParams>
1401
1240
void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
1402
1241
const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath)
1403
1242
{
1404
- auto shdrDynamic = findSection (" .dynamic" );
1243
+ auto shdrDynamic = findSectionHeader (" .dynamic" );
1405
1244
1406
1245
if (rdi (shdrDynamic.sh_type ) == SHT_NOBITS) {
1407
1246
debug (" no dynamic section\n " );
@@ -1410,7 +1249,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
1410
1249
1411
1250
/* !!! We assume that the virtual address in the DT_STRTAB entry
1412
1251
of the dynamic section corresponds to the .dynstr section. */
1413
- auto shdrDynStr = findSection (" .dynstr" );
1252
+ auto shdrDynStr = findSectionHeader (" .dynstr" );
1414
1253
char * strTab = (char *) fileContents->data () + rdi (shdrDynStr.sh_offset );
1415
1254
1416
1255
@@ -1549,8 +1388,8 @@ void ElfFile<ElfFileParamNames>::removeNeeded(const std::set<std::string> & libs
1549
1388
{
1550
1389
if (libs.empty ()) return ;
1551
1390
1552
- auto shdrDynamic = findSection (" .dynamic" );
1553
- auto shdrDynStr = findSection (" .dynstr" );
1391
+ auto shdrDynamic = findSectionHeader (" .dynamic" );
1392
+ auto shdrDynStr = findSectionHeader (" .dynstr" );
1554
1393
char * strTab = (char *) fileContents->data () + rdi (shdrDynStr.sh_offset );
1555
1394
1556
1395
auto dyn = (Elf_Dyn *)(fileContents->data () + rdi (shdrDynamic.sh_offset ));
@@ -1577,8 +1416,8 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std::
1577
1416
{
1578
1417
if (libs.empty ()) return ;
1579
1418
1580
- auto shdrDynamic = findSection (" .dynamic" );
1581
- auto shdrDynStr = findSection (" .dynstr" );
1419
+ auto shdrDynamic = findSectionHeader (" .dynamic" );
1420
+ auto shdrDynStr = findSectionHeader (" .dynstr" );
1582
1421
char * strTab = (char *) fileContents->data () + rdi (shdrDynStr.sh_offset );
1583
1422
1584
1423
auto dyn = (Elf_Dyn *)(fileContents->data () + rdi (shdrDynamic.sh_offset ));
@@ -1634,7 +1473,7 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std::
1634
1473
// be replaced.
1635
1474
1636
1475
if (verNeedNum) {
1637
- auto shdrVersionR = findSection (" .gnu.version_r" );
1476
+ auto shdrVersionR = findSectionHeader (" .gnu.version_r" );
1638
1477
// The filename strings in the .gnu.version_r are different from the
1639
1478
// ones in .dynamic: instead of being in .dynstr, they're in some
1640
1479
// arbitrary section and we have to look in ->sh_link to figure out
@@ -1700,8 +1539,8 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
1700
1539
{
1701
1540
if (libs.empty ()) return ;
1702
1541
1703
- auto shdrDynamic = findSection (" .dynamic" );
1704
- auto shdrDynStr = findSection (" .dynstr" );
1542
+ auto shdrDynamic = findSectionHeader (" .dynamic" );
1543
+ auto shdrDynStr = findSectionHeader (" .dynstr" );
1705
1544
1706
1545
unsigned int length = 0 ;
1707
1546
@@ -1748,8 +1587,8 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
1748
1587
template <ElfFileParams>
1749
1588
void ElfFile<ElfFileParamNames>::printNeededLibs() // const
1750
1589
{
1751
- const auto shdrDynamic = findSection (" .dynamic" );
1752
- const auto shdrDynStr = findSection (" .dynstr" );
1590
+ const auto shdrDynamic = findSectionHeader (" .dynamic" );
1591
+ const auto shdrDynStr = findSectionHeader (" .dynstr" );
1753
1592
const char *strTab = (char *)fileContents->data () + rdi (shdrDynStr.sh_offset );
1754
1593
1755
1594
const Elf_Dyn *dyn = (Elf_Dyn *) (fileContents->data () + rdi (shdrDynamic.sh_offset ));
@@ -1766,7 +1605,7 @@ void ElfFile<ElfFileParamNames>::printNeededLibs() // const
1766
1605
template <ElfFileParams>
1767
1606
void ElfFile<ElfFileParamNames>::noDefaultLib()
1768
1607
{
1769
- auto shdrDynamic = findSection (" .dynamic" );
1608
+ auto shdrDynamic = findSectionHeader (" .dynamic" );
1770
1609
1771
1610
auto dyn = (Elf_Dyn *)(fileContents->data () + rdi (shdrDynamic.sh_offset ));
1772
1611
auto dynFlags1 = (Elf_Dyn *)nullptr ;
@@ -1807,9 +1646,9 @@ void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string>
1807
1646
{
1808
1647
if (syms.empty ()) return ;
1809
1648
1810
- auto shdrDynStr = findSection (" .dynstr" );
1811
- auto shdrDynsym = findSection (" .dynsym" );
1812
- auto shdrVersym = findSection (" .gnu.version" );
1649
+ auto shdrDynStr = findSectionHeader (" .dynstr" );
1650
+ auto shdrDynsym = findSectionHeader (" .dynsym" );
1651
+ auto shdrVersym = findSectionHeader (" .gnu.version" );
1813
1652
1814
1653
auto strTab = (char *)fileContents->data () + rdi (shdrDynStr.sh_offset );
1815
1654
auto dynsyms = (Elf_Sym *)(fileContents->data () + rdi (shdrDynsym.sh_offset ));
0 commit comments