Skip to content

Commit 6bfcafb

Browse files
committed
Merge branch 'master' of https://github.com/rpurdie/patchelf
2 parents e44c318 + c4deb5e commit 6bfcafb

File tree

1 file changed

+40
-32
lines changed

1 file changed

+40
-32
lines changed

src/patchelf.cc

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ class ElfFile
171171
std::string & replaceSection(const SectionName & sectionName,
172172
unsigned int size);
173173

174+
bool haveReplacedSection(const SectionName & sectionName);
175+
174176
void writeReplacedSections(Elf_Off & curOff,
175177
Elf_Addr startAddr, Elf_Off startOffset);
176178

@@ -579,6 +581,15 @@ unsigned int ElfFile<ElfFileParamNames>::findSection3(const SectionName & sectio
579581
return 0;
580582
}
581583

584+
template<ElfFileParams>
585+
bool ElfFile<ElfFileParamNames>::haveReplacedSection(const SectionName & sectionName)
586+
{
587+
ReplacedSections::iterator i = replacedSections.find(sectionName);
588+
589+
if (i != replacedSections.end())
590+
return true;
591+
return false;
592+
}
582593

583594
template<ElfFileParams>
584595
std::string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sectionName,
@@ -673,51 +684,51 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
673684

674685
debug("last page is 0x%llx\n", (unsigned long long) startPage);
675686

687+
/* Because we're adding a new section header, we're necessarily increasing
688+
the size of the program header table. This can cause the first section
689+
to overlap the program header table in memory; we need to shift the first
690+
few segments to someplace else. */
691+
/* Some sections may already be replaced so account for that */
692+
unsigned int i = 1;
693+
Elf_Addr pht_size = sizeof(Elf_Ehdr) + (phdrs.size() + 1)*sizeof(Elf_Phdr);
694+
while( shdrs[i].sh_addr <= pht_size && i < rdi(hdr->e_shnum) ) {
695+
if (not haveReplacedSection(getSectionName(shdrs[i])))
696+
replaceSection(getSectionName(shdrs[i]), shdrs[i].sh_size);
697+
i++;
698+
}
676699

677-
/* Compute the total space needed for the replaced sections and
678-
the program headers. */
679-
off_t neededSpace = (phdrs.size() + 1) * sizeof(Elf_Phdr);
700+
/* Compute the total space needed for the replaced sections */
701+
off_t neededSpace = 0;
680702
for (auto & i : replacedSections)
681703
neededSpace += roundUp(i.second.size(), sectionAlignment);
682704
debug("needed space is %d\n", neededSpace);
683705

684-
685706
size_t startOffset = roundUp(fileContents->size(), getPageSize());
686707

687708
growFile(fileContents, startOffset + neededSpace);
688709

689-
690710
/* Even though this file is of type ET_DYN, it could actually be
691711
an executable. For instance, Gold produces executables marked
692-
ET_DYN. In that case we can still hit the kernel bug that
693-
necessitated rewriteSectionsExecutable(). However, such
694-
executables also tend to start at virtual address 0, so
712+
ET_DYN as does LD when linking with pie. If we move PT_PHDR, it
713+
has to stay in the first PT_LOAD segment or any subsequent ones
714+
if they're continuous in memory due to linux kernel constraints
715+
(see BUGS). Since the end of the file would be after bss, we can't
716+
move PHDR there, we therefore choose to leave PT_PHDR where it is but
717+
move enough following sections such that we can add the extra PT_LOAD
718+
section to it. This PT_LOAD segment ensures the sections at the end of
719+
the file are mapped into memory for ld.so to process.
720+
We can't use the approach in rewriteSectionsExecutable()
721+
since DYN executables tend to start at virtual address 0, so
695722
rewriteSectionsExecutable() won't work because it doesn't have
696-
any virtual address space to grow downwards into. As a
697-
workaround, make sure that the virtual address of our new
698-
PT_LOAD segment relative to the first PT_LOAD segment is equal
699-
to its offset; otherwise we hit the kernel bug. This may
700-
require creating a hole in the executable. The bigger the size
701-
of the uninitialised data segment, the bigger the hole. */
723+
any virtual address space to grow downwards into. */
702724
if (isExecutable) {
703725
if (startOffset >= startPage) {
704726
debug("shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n", startOffset - startPage);
705-
} else {
706-
size_t hole = startPage - startOffset;
707-
/* Print a warning, because the hole could be very big. */
708-
fprintf(stderr, "warning: working around a Linux kernel bug by creating a hole of %zu bytes in '%s'\n", hole, fileName.c_str());
709-
assert(hole % getPageSize() == 0);
710-
/* !!! We could create an actual hole in the file here,
711-
but it's probably not worth the effort. */
712-
growFile(fileContents, fileContents->size() + hole);
713-
startOffset += hole;
714727
}
715728
startPage = startOffset;
716729
}
717730

718-
719-
/* Add a segment that maps the replaced sections and program
720-
headers into memory. */
731+
/* Add a segment that maps the replaced sections into memory. */
721732
phdrs.resize(rdi(hdr->e_phnum) + 1);
722733
wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1);
723734
Elf_Phdr & phdr = phdrs[rdi(hdr->e_phnum) - 1];
@@ -730,15 +741,12 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
730741

731742

732743
/* Write out the replaced sections. */
733-
Elf_Off curOff = startOffset + phdrs.size() * sizeof(Elf_Phdr);
744+
Elf_Off curOff = startOffset;
734745
writeReplacedSections(curOff, startPage, startOffset);
735746
assert(curOff == startOffset + neededSpace);
736747

737-
738-
/* Move the program header to the start of the new area. */
739-
wri(hdr->e_phoff, startOffset);
740-
741-
rewriteHeaders(startPage);
748+
/* Write out the updated program and section headers */
749+
rewriteHeaders(hdr->e_phoff);
742750
}
743751

744752

0 commit comments

Comments
 (0)