Skip to content

Commit 05e8f67

Browse files
committed
Added patchelf.h
Added a header file to make things easier to navigate. Renamed findSection3 -> getSectionIndex since thats more sensible to read. Renamed findSection -> findSectionHeader to better distinguish sections from headers.
1 parent b73dbc1 commit 05e8f67

File tree

2 files changed

+212
-193
lines changed

2 files changed

+212
-193
lines changed

src/patchelf.cc

Lines changed: 32 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <unistd.h>
4242

4343
#include "elf.h"
44+
#include "patchelf.h"
4445

4546
#ifndef PACKAGE_STRING
4647
#define PACKAGE_STRING "patchelf"
@@ -63,11 +64,6 @@ static int forcedPageSize = -1;
6364
#define EM_LOONGARCH 258
6465
#endif
6566

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-
7167

7268
static std::vector<std::string> splitColonDelimitedString(const char * s)
7369
{
@@ -85,163 +81,6 @@ static bool hasAllowedPrefix(const std::string & s, const std::vector<std::strin
8581
return std::any_of(allowedPrefixes.begin(), allowedPrefixes.end(), [&](const std::string & i) { return !s.compare(0, i.size(), i); });
8682
}
8783

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-
24584
/* !!! G++ creates broken code if this function is inlined, don't know
24685
why... */
24786
template<ElfFileParams>
@@ -630,7 +469,7 @@ std::string ElfFile<ElfFileParamNames>::getSectionName(const Elf_Shdr & shdr) co
630469

631470

632471
template<ElfFileParams>
633-
Elf_Shdr & ElfFile<ElfFileParamNames>::findSection(const SectionName & sectionName)
472+
Elf_Shdr & ElfFile<ElfFileParamNames>::findSectionHeader(const SectionName & sectionName)
634473
{
635474
auto shdr = findSection2(sectionName);
636475
if (!shdr) {
@@ -654,7 +493,7 @@ std::optional<std::reference_wrapper<Elf_Shdr>> ElfFile<ElfFileParamNames>::find
654493

655494

656495
template<ElfFileParams>
657-
unsigned int ElfFile<ElfFileParamNames>::findSection3(const SectionName & sectionName)
496+
unsigned int ElfFile<ElfFileParamNames>::getSectionIndex(const SectionName & sectionName)
658497
{
659498
for (unsigned int i = 1; i < rdi(hdr()->e_shnum); ++i)
660499
if (getSectionName(shdrs.at(i)) == sectionName) return i;
@@ -677,7 +516,7 @@ std::string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sec
677516
if (i != replacedSections.end()) {
678517
s = std::string(i->second);
679518
} else {
680-
auto shdr = findSection(sectionName);
519+
auto shdr = findSectionHeader(sectionName);
681520
s = std::string((char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size));
682521
}
683522

@@ -697,15 +536,15 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
697536
clobbering previously written new section contents. */
698537
for (auto & i : replacedSections) {
699538
const std::string & sectionName = i.first;
700-
Elf_Shdr & shdr = findSection(sectionName);
539+
Elf_Shdr & shdr = findSectionHeader(sectionName);
701540
if (rdi(shdr.sh_type) != SHT_NOBITS)
702541
memset(fileContents->data() + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size));
703542
}
704543

705544
std::set<unsigned int> noted_phdrs = {};
706545
for (auto & i : replacedSections) {
707546
const std::string & sectionName = i.first;
708-
auto & shdr = findSection(sectionName);
547+
auto & shdr = findSectionHeader(sectionName);
709548
Elf_Shdr orig_shdr = shdr;
710549
debug("rewriting section '%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\n",
711550
sectionName.c_str(), rdi(shdr.sh_offset), rdi(shdr.sh_size), curOff, i.second.size());
@@ -1024,7 +863,7 @@ void ElfFile<ElfFileParamNames>::normalizeNoteSegments()
1024863

1025864
/* We don't need to do anything if no note segments were replaced. */
1026865
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; });
1028867
if (!replaced_note) return;
1029868

1030869
std::vector<Elf_Phdr> newPhdrs;
@@ -1134,13 +973,13 @@ void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress)
1134973
unsigned int d_tag;
1135974
for (auto dyn = dyn_table; (d_tag = rdi(dyn->d_tag)) != DT_NULL; dyn++)
1136975
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;
1138977
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;
1140979
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;
1142981
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;
1144983
else if (d_tag == DT_GNU_HASH) {
1145984
auto shdr = findSection2(".gnu.hash");
1146985
// some binaries might this section stripped
@@ -1172,15 +1011,15 @@ void ElfFile<ElfFileParamNames>::rewriteHeaders(Elf_Addr phdrAddress)
11721011
dyn->d_un.d_ptr = (*shdr).get().sh_addr;
11731012
}
11741013
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;
11761015
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;
11781017
else if (d_tag == DT_MIPS_RLD_MAP_REL) {
11791018
/* the MIPS_RLD_MAP_REL tag stores the offset to the debug
11801019
pointer, relative to the address of the tag */
11811020
auto shdr = findSection2(".rld_map");
11821021
if (shdr) {
1183-
auto rld_map_addr = findSection(".rld_map").sh_addr;
1022+
auto rld_map_addr = findSectionHeader(".rld_map").sh_addr;
11841023
auto dyn_offset = ((char*)dyn) - ((char*)dyn_table);
11851024
dyn->d_un.d_ptr = rld_map_addr + dyn_offset - (*shdrDynamic).get().sh_addr;
11861025
} else {
@@ -1236,7 +1075,7 @@ static void setSubstr(std::string & s, unsigned int pos, const std::string & t)
12361075
template<ElfFileParams>
12371076
std::string ElfFile<ElfFileParamNames>::getInterpreter()
12381077
{
1239-
auto shdr = findSection(".interp");
1078+
auto shdr = findSectionHeader(".interp");
12401079
return std::string((char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size) - 1);
12411080
}
12421081

@@ -1248,8 +1087,8 @@ void ElfFile<ElfFileParamNames>::modifySoname(sonameMode op, const std::string &
12481087
return;
12491088
}
12501089

1251-
auto shdrDynamic = findSection(".dynamic");
1252-
auto shdrDynStr = findSection(".dynstr");
1090+
auto shdrDynamic = findSectionHeader(".dynamic");
1091+
auto shdrDynStr = findSectionHeader(".dynstr");
12531092
char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset);
12541093

12551094
/* Walk through the dynamic section, look for the DT_SONAME entry. */
@@ -1401,7 +1240,7 @@ template<ElfFileParams>
14011240
void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
14021241
const std::vector<std::string> & allowedRpathPrefixes, std::string newRPath)
14031242
{
1404-
auto shdrDynamic = findSection(".dynamic");
1243+
auto shdrDynamic = findSectionHeader(".dynamic");
14051244

14061245
if (rdi(shdrDynamic.sh_type) == SHT_NOBITS) {
14071246
debug("no dynamic section\n");
@@ -1410,7 +1249,7 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op,
14101249

14111250
/* !!! We assume that the virtual address in the DT_STRTAB entry
14121251
of the dynamic section corresponds to the .dynstr section. */
1413-
auto shdrDynStr = findSection(".dynstr");
1252+
auto shdrDynStr = findSectionHeader(".dynstr");
14141253
char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset);
14151254

14161255

@@ -1549,8 +1388,8 @@ void ElfFile<ElfFileParamNames>::removeNeeded(const std::set<std::string> & libs
15491388
{
15501389
if (libs.empty()) return;
15511390

1552-
auto shdrDynamic = findSection(".dynamic");
1553-
auto shdrDynStr = findSection(".dynstr");
1391+
auto shdrDynamic = findSectionHeader(".dynamic");
1392+
auto shdrDynStr = findSectionHeader(".dynstr");
15541393
char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset);
15551394

15561395
auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset));
@@ -1577,8 +1416,8 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std::
15771416
{
15781417
if (libs.empty()) return;
15791418

1580-
auto shdrDynamic = findSection(".dynamic");
1581-
auto shdrDynStr = findSection(".dynstr");
1419+
auto shdrDynamic = findSectionHeader(".dynamic");
1420+
auto shdrDynStr = findSectionHeader(".dynstr");
15821421
char * strTab = (char *) fileContents->data() + rdi(shdrDynStr.sh_offset);
15831422

15841423
auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset));
@@ -1634,7 +1473,7 @@ void ElfFile<ElfFileParamNames>::replaceNeeded(const std::map<std::string, std::
16341473
// be replaced.
16351474

16361475
if (verNeedNum) {
1637-
auto shdrVersionR = findSection(".gnu.version_r");
1476+
auto shdrVersionR = findSectionHeader(".gnu.version_r");
16381477
// The filename strings in the .gnu.version_r are different from the
16391478
// ones in .dynamic: instead of being in .dynstr, they're in some
16401479
// 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)
17001539
{
17011540
if (libs.empty()) return;
17021541

1703-
auto shdrDynamic = findSection(".dynamic");
1704-
auto shdrDynStr = findSection(".dynstr");
1542+
auto shdrDynamic = findSectionHeader(".dynamic");
1543+
auto shdrDynStr = findSectionHeader(".dynstr");
17051544

17061545
unsigned int length = 0;
17071546

@@ -1748,8 +1587,8 @@ void ElfFile<ElfFileParamNames>::addNeeded(const std::set<std::string> & libs)
17481587
template<ElfFileParams>
17491588
void ElfFile<ElfFileParamNames>::printNeededLibs() // const
17501589
{
1751-
const auto shdrDynamic = findSection(".dynamic");
1752-
const auto shdrDynStr = findSection(".dynstr");
1590+
const auto shdrDynamic = findSectionHeader(".dynamic");
1591+
const auto shdrDynStr = findSectionHeader(".dynstr");
17531592
const char *strTab = (char *)fileContents->data() + rdi(shdrDynStr.sh_offset);
17541593

17551594
const Elf_Dyn *dyn = (Elf_Dyn *) (fileContents->data() + rdi(shdrDynamic.sh_offset));
@@ -1766,7 +1605,7 @@ void ElfFile<ElfFileParamNames>::printNeededLibs() // const
17661605
template<ElfFileParams>
17671606
void ElfFile<ElfFileParamNames>::noDefaultLib()
17681607
{
1769-
auto shdrDynamic = findSection(".dynamic");
1608+
auto shdrDynamic = findSectionHeader(".dynamic");
17701609

17711610
auto dyn = (Elf_Dyn *)(fileContents->data() + rdi(shdrDynamic.sh_offset));
17721611
auto dynFlags1 = (Elf_Dyn *)nullptr;
@@ -1807,9 +1646,9 @@ void ElfFile<ElfFileParamNames>::clearSymbolVersions(const std::set<std::string>
18071646
{
18081647
if (syms.empty()) return;
18091648

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");
18131652

18141653
auto strTab = (char *)fileContents->data() + rdi(shdrDynStr.sh_offset);
18151654
auto dynsyms = (Elf_Sym *)(fileContents->data() + rdi(shdrDynsym.sh_offset));

0 commit comments

Comments
 (0)