diff options
Diffstat (limited to 'src/patchelf.cc')
-rw-r--r-- | src/patchelf.cc | 58 |
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); |