summaryrefslogtreecommitdiffstats
path: root/src/patchelf.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/patchelf.cc')
-rw-r--r--src/patchelf.cc173
1 files changed, 170 insertions, 3 deletions
diff --git a/src/patchelf.cc b/src/patchelf.cc
index d8187bb..27e220d 100644
--- a/src/patchelf.cc
+++ b/src/patchelf.cc
@@ -459,10 +459,175 @@ void ElfFile<ElfFileParamNames>::rewriteSections()
unsigned int sectionAlignment = sizeof(Elf_Off);
+ if (!findSection2(".interp")) {
+ debug("no .interp section; this is a dynamic library\n");
+
+
+ /* For dynamic libraries, we just place the replacement
+ sections at the end of the file. They're mapped into
+ memory by a PT_LOAD segment located directly after the last
+ virtual address page of other segments. */
+ Elf_Addr lastPage = 0;
+ for (unsigned int i = 0; i < phdrs.size(); ++i) {
+ Elf_Addr thisPage = roundUp(rdi(phdrs[i].p_vaddr) + rdi(phdrs[i].p_memsz), pageSize);
+ if (thisPage > lastPage) lastPage = thisPage;
+ }
+
+ debug("last page is 0x%llx\n", (unsigned long long) lastPage);
+
+
+ /* Compute the total space needed for the replaced sections
+ and the program headers. */
+ off_t neededSpace = (phdrs.size() + 1) * sizeof(Elf_Phdr);
+ for (ReplacedSections::iterator i = replacedSections.begin();
+ i != replacedSections.end(); ++i)
+ neededSpace += roundUp(i->second.size(), sectionAlignment);
+ debug("needed space is %d\n", neededSpace);
+
+
+ off_t startOffset = roundUp(fileSize, pageSize);
+
+ growFile(startOffset + neededSpace);
+
+
+ /* Add a segment that maps the replaced sections and program
+ headers into memory.. */
+ phdrs.resize(rdi(hdr->e_phnum) + 1);
+ wri(hdr->e_phnum, rdi(hdr->e_phnum) + 1);
+ Elf_Phdr & phdr = phdrs[rdi(hdr->e_phnum) - 1];
+ wri(phdr.p_type, PT_LOAD);
+ wri(phdr.p_offset, startOffset);
+ wri(phdr.p_vaddr, wri(phdr.p_paddr, lastPage));
+ wri(phdr.p_filesz, wri(phdr.p_memsz, neededSpace));
+ wri(phdr.p_flags, PF_R | PF_W);
+ wri(phdr.p_align, 4096);
+
+
+ /* Write out the replaced sections. */
+ off_t curOff = startOffset + phdrs.size() * sizeof(Elf_Phdr);
+ for (ReplacedSections::iterator i = replacedSections.begin();
+ i != replacedSections.end(); )
+ {
+ string sectionName = i->first;
+ Elf_Shdr & shdr = findSection(sectionName);
+ debug("rewriting section `%s' from offset %d to offset %d\n",
+ sectionName.c_str(), rdi(shdr.sh_offset), curOff);
+
+ memset(contents + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size));
+ memcpy(contents + curOff, (unsigned char *) i->second.c_str(),
+ i->second.size());
+
+ /* Update the section header for this section. */
+ wri(shdr.sh_offset, curOff);
+ wri(shdr.sh_addr, lastPage + (curOff - startOffset));
+ wri(shdr.sh_size, i->second.size());
+ wri(shdr.sh_addralign, sectionAlignment);
+
+ /* If this is the .interp section, then the PT_INTERP segment
+ must be sync'ed with it. */
+ if (sectionName == ".interp") {
+ for (unsigned int j = 0; j < phdrs.size(); ++j)
+ if (rdi(phdrs[j].p_type) == PT_INTERP) {
+ phdrs[j].p_offset = shdr.sh_offset;
+ phdrs[j].p_vaddr = phdrs[j].p_paddr = shdr.sh_addr;
+ phdrs[j].p_filesz = phdrs[j].p_memsz = shdr.sh_size;
+ }
+ }
+
+ /* If this is the .dynamic section, then the PT_DYNAMIC segment
+ must be sync'ed with it. */
+ if (sectionName == ".dynamic") {
+ for (unsigned int j = 0; j < phdrs.size(); ++j)
+ if (rdi(phdrs[j].p_type) == PT_DYNAMIC) {
+ phdrs[j].p_offset = shdr.sh_offset;
+ phdrs[j].p_vaddr = phdrs[j].p_paddr = shdr.sh_addr;
+ phdrs[j].p_filesz = phdrs[j].p_memsz = shdr.sh_size;
+ }
+ }
+
+ curOff += roundUp(i->second.size(), sectionAlignment);
+
+ ++i;
+ replacedSections.erase(sectionName);
+ }
+
+ assert(replacedSections.empty());
+ assert((off_t) curOff == startOffset + neededSpace);
+
+
+ /* !!! cut&paste */
+
+ /* Rewrite the program header table. */
+ wri(hdr->e_phoff, startOffset);
+
+ /* If there is a segment for the program header table, update
+ it. (According to the ELF spec, it must be the first
+ entry.) */
+ if (rdi(phdrs[0].p_type) == PT_PHDR) {
+ phdrs[0].p_offset = hdr->e_phoff;
+ abort();
+ // !!! wri(phdrs[0].p_vaddr, wri(phdrs[0].p_paddr, firstPage + rdi(hdr->e_phoff)));
+ wri(phdrs[0].p_filesz, wri(phdrs[0].p_memsz, phdrs.size() * sizeof(Elf_Phdr)));
+ }
+
+ sortPhdrs();
+
+ for (unsigned int i = 0; i < phdrs.size(); ++i)
+ * ((Elf_Phdr *) (contents + rdi(hdr->e_phoff)) + i) = phdrs[i];
+
+
+ /* Rewrite the section header table. For neatness, keep the
+ sections sorted. */
+ assert(rdi(hdr->e_shnum) == shdrs.size());
+ //sortShdrs(); !!! breaks the library
+ for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)
+ * ((Elf_Shdr *) (contents + rdi(hdr->e_shoff)) + i) = shdrs[i];
+
+
+ /* Update all those nasty virtual addresses in the .dynamic
+ section. */
+ Elf_Shdr & shdrDynamic = findSection(".dynamic");
+ Elf_Dyn * dyn = (Elf_Dyn *) (contents + rdi(shdrDynamic.sh_offset));
+ unsigned int d_tag;
+ for ( ; (d_tag = rdi(dyn->d_tag)) != DT_NULL; dyn++)
+ if (d_tag == DT_STRTAB)
+ dyn->d_un.d_ptr = findSection(".dynstr").sh_addr;
+ else if (d_tag == DT_STRSZ)
+ dyn->d_un.d_val = findSection(".dynstr").sh_size;
+ else if (d_tag == DT_SYMTAB)
+ dyn->d_un.d_ptr = findSection(".dynsym").sh_addr;
+ else if (d_tag == DT_HASH)
+ dyn->d_un.d_ptr = findSection(".hash").sh_addr;
+ else if (d_tag == DT_JMPREL) {
+ Elf_Shdr * shdr = findSection2(".rel.plt");
+ if (!shdr) shdr = findSection2(".rela.plt"); /* 64-bit Linux, x86-64 */
+ if (!shdr) shdr = findSection2(".rela.IA_64.pltoff"); /* 64-bit Linux, IA-64 */
+ if (!shdr) error("cannot find section corresponding to DT_JMPREL");
+ dyn->d_un.d_ptr = shdr->sh_addr;
+ }
+ else if (d_tag == DT_REL) { /* !!! hack! */
+ Elf_Shdr * shdr = findSection2(".rel.dyn");
+ /* no idea if this makes sense, but it was needed for some
+ program */
+ if (!shdr) shdr = findSection2(".rel.got");
+ if (!shdr) error("cannot find .rel.dyn or .rel.got");
+ dyn->d_un.d_ptr = shdr->sh_addr;
+ }
+ /* should probably update DT_RELA */
+ else if (d_tag == DT_VERNEED)
+ dyn->d_un.d_ptr = findSection(".gnu.version_r").sh_addr;
+ else if (d_tag == DT_VERSYM)
+ dyn->d_un.d_ptr = findSection(".gnu.version").sh_addr;
+
+
+ return;
+ }
+
+
/* Sort the sections by offset, otherwise we won't correctly find
all the sections before the last replaced section. */
sortShdrs();
-
+
/* What is the index of the last replaced section? */
unsigned int lastReplaced = 0;
@@ -622,6 +787,7 @@ void ElfFile<ElfFileParamNames>::rewriteSections()
for (unsigned int i = 0; i < phdrs.size(); ++i)
* ((Elf_Phdr *) (contents + rdi(hdr->e_phoff)) + i) = phdrs[i];
+
/* Rewrite the section header table. For neatness, keep the
sections sorted. */
assert(rdi(hdr->e_shnum) == shdrs.size());
@@ -629,6 +795,7 @@ void ElfFile<ElfFileParamNames>::rewriteSections()
for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i)
* ((Elf_Shdr *) (contents + rdi(hdr->e_shoff)) + i) = shdrs[i];
+
/* Update all those nasty virtual addresses in the .dynamic
section. */
Elf_Shdr & shdrDynamic = findSection(".dynamic");
@@ -808,8 +975,8 @@ void ElfFile<ElfFileParamNames>::modifyRPath(RPathOp op, string newRPath)
changed = true;
- /* Zero out the previous rpath to prevent retained
- dependencies in Nix. */
+ /* Zero out the previous rpath to prevent retained dependencies in
+ Nix. */
unsigned int rpathSize = 0;
if (rpath) {
rpathSize = strlen(rpath);