summaryrefslogtreecommitdiff
path: root/src/patchelf.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/patchelf.cc')
-rw-r--r--src/patchelf.cc58
1 files changed, 46 insertions, 12 deletions
diff --git a/src/patchelf.cc b/src/patchelf.cc
index b78210c..1a90edb 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -800,12 +800,17 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
page of other segments. */
Elf_Addr startPage = 0;
Elf_Addr firstPage = 0;
+ unsigned alignStartPage = getPageSize();
for (auto & phdr : phdrs) {
- Elf_Addr thisPage = roundUp(rdi(phdr.p_vaddr) + rdi(phdr.p_memsz), getPageSize());
+ Elf_Addr thisPage = rdi(phdr.p_vaddr) + rdi(phdr.p_memsz);
if (thisPage > startPage) startPage = thisPage;
if (rdi(phdr.p_type) == PT_PHDR) firstPage = rdi(phdr.p_vaddr) - rdi(phdr.p_offset);
+ unsigned thisAlign = rdi(phdr.p_align);
+ alignStartPage = std::max(alignStartPage, thisAlign);
}
+ startPage = roundUp(startPage, alignStartPage);
+
debug("last page is 0x%llx\n", (unsigned long long) startPage);
debug("first page is 0x%llx\n", (unsigned long long) firstPage);
@@ -826,11 +831,16 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
replaceSection(getSectionName(shdrs.at(i)), rdi(shdrs.at(i).sh_size));
i++;
}
+ bool moveHeaderTableToTheEnd = rdi(hdr()->e_shoff) < pht_size;
/* Compute the total space needed for the replaced sections */
off_t neededSpace = 0;
for (auto & s : replacedSections)
neededSpace += roundUp(s.second.size(), sectionAlignment);
+
+ off_t headerTableSpace = roundUp(rdi(hdr()->e_shnum) * rdi(hdr()->e_shentsize), sectionAlignment);
+ if (moveHeaderTableToTheEnd)
+ neededSpace += headerTableSpace;
debug("needed space is %d\n", neededSpace);
Elf_Off startOffset = roundUp(fileContents->size(), getPageSize());
@@ -860,24 +870,48 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
startPage = startOffset;
}
- /* Add a segment that maps the replaced sections into memory. */
wri(hdr()->e_phoff, sizeof(Elf_Ehdr));
- phdrs.resize(rdi(hdr()->e_phnum) + 1);
- wri(hdr()->e_phnum, rdi(hdr()->e_phnum) + 1);
- Elf_Phdr & phdr = phdrs.at(rdi(hdr()->e_phnum) - 1);
- wri(phdr.p_type, PT_LOAD);
- wri(phdr.p_offset, startOffset);
- wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage));
- wri(phdr.p_filesz, wri(phdr.p_memsz, neededSpace));
- wri(phdr.p_flags, PF_R | PF_W);
- wri(phdr.p_align, getPageSize());
+ bool needNewSegment = true;
+ auto& lastSeg = phdrs.back();
+ /* Try to extend the last segment to include replaced sections */
+ if (!phdrs.empty() &&
+ rdi(lastSeg.p_type) == PT_LOAD &&
+ rdi(lastSeg.p_flags) == (PF_R | PF_W) &&
+ rdi(lastSeg.p_align) == alignStartPage) {
+ auto segEnd = roundUp(rdi(lastSeg.p_offset) + rdi(lastSeg.p_memsz), getPageSize());
+ if (segEnd == startOffset) {
+ auto newSz = startOffset + neededSpace - rdi(lastSeg.p_offset);
+ wri(lastSeg.p_filesz, wri(lastSeg.p_memsz, newSz));
+ needNewSegment = false;
+ }
+ }
+
+ if (needNewSegment) {
+ /* Add a segment that maps the replaced sections into memory. */
+ phdrs.resize(rdi(hdr()->e_phnum) + 1);
+ wri(hdr()->e_phnum, rdi(hdr()->e_phnum) + 1);
+ Elf_Phdr & phdr = phdrs.at(rdi(hdr()->e_phnum) - 1);
+ wri(phdr.p_type, PT_LOAD);
+ wri(phdr.p_offset, startOffset);
+ wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage));
+ wri(phdr.p_filesz, wri(phdr.p_memsz, neededSpace));
+ wri(phdr.p_flags, PF_R | PF_W);
+ wri(phdr.p_align, alignStartPage);
+ }
normalizeNoteSegments();
/* Write out the replaced sections. */
Elf_Off curOff = startOffset;
+
+ if (moveHeaderTableToTheEnd) {
+ debug("Moving the shtable to offset %d\n", curOff);
+ wri(hdr()->e_shoff, curOff);
+ curOff += headerTableSpace;
+ }
+
writeReplacedSections(curOff, startPage, startOffset);
assert(curOff == startOffset + neededSpace);
@@ -2136,7 +2170,7 @@ void ElfFile<ElfFileParamNames>::renameDynamicSymbols(const std::unordered_map<s
}
}
- if (changed)
+ if (!extraStrings.empty())
{
auto newStrTabSize = strTab.size() + extraStrings.size();
auto& newSec = replaceSection(".dynstr", newStrTabSize);