* gnu/packages/patches/patchelf-rework-for-arm.patch: New file. * gnu-system.am: Add it. * gnu/packages/elf.scm: Apply patch when the target is ARM.
		
			
				
	
	
		
			473 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			473 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| Rework the growing algorithm in patchelf to support ARM systems.
 | ||
| See <https://github.com/NixOS/patchelf/issues/8>.
 | ||
| This patch copied from:
 | ||
| <https://github.com/sriemer/patchelf/commit/0a96239cea6b97b9a0fff80da576e58ca2dfb2a2>
 | ||
| 
 | ||
| From 0a96239cea6b97b9a0fff80da576e58ca2dfb2a2 Mon Sep 17 00:00:00 2001
 | ||
| From: Sebastian Parschauer <s.parschauer@gmx.de>
 | ||
| Date: Sat, 28 Jun 2014 01:24:57 +0200
 | ||
| Subject: [PATCH] Rework the growing algorithm
 | ||
| 
 | ||
| On ARM systems there is no space in virtual memory for another LOAD
 | ||
| area in front of the code LOAD area. So insert data to its end
 | ||
| instead. At this location there should be enough space in virtual
 | ||
| memory due to alignment. We can extend it until the end of the
 | ||
| alignment but the file shift may be greater as it must be aligned
 | ||
| to the page size. Do the same for the data LOAD area.
 | ||
| ---
 | ||
|  src/patchelf.cc | 357 ++++++++++++++++++++++----------------------------------
 | ||
|  1 file changed, 142 insertions(+), 215 deletions(-)
 | ||
| 
 | ||
| diff --git a/src/patchelf.cc b/src/patchelf.cc
 | ||
| index dcbfd38..4fce9e6 100644
 | ||
| --- a/src/patchelf.cc
 | ||
| +++ b/src/patchelf.cc
 | ||
| @@ -116,7 +116,11 @@ private:
 | ||
|  
 | ||
|      void sortShdrs();
 | ||
|  
 | ||
| -    void shiftFile(unsigned int extraPages, Elf_Addr startPage);
 | ||
| +    void shiftFileSingle(size_t fileShift, Elf_Off insertOff);
 | ||
| +
 | ||
| +    void shiftFile(size_t neededCode, size_t neededData,
 | ||
| +                   Elf_Off codeOff[], Elf_Off dataOff[],
 | ||
| +                   Elf_Addr *codePage, Elf_Addr *dataPage);
 | ||
|  
 | ||
|      string getSectionName(const Elf_Shdr & shdr);
 | ||
|  
 | ||
| @@ -130,13 +134,11 @@ private:
 | ||
|          unsigned int size);
 | ||
|  
 | ||
|      void writeReplacedSections(Elf_Off & curOff,
 | ||
| -        Elf_Addr startAddr, Elf_Off startOffset);
 | ||
| +        Elf_Addr startAddr, Elf_Off startOffset, bool isData);
 | ||
|  
 | ||
|      void rewriteHeaders(Elf_Addr phdrAddress);
 | ||
|  
 | ||
| -    void rewriteSectionsLibrary();
 | ||
| -
 | ||
| -    void rewriteSectionsExecutable();
 | ||
| +    void rewriteSectionsBinary();
 | ||
|  
 | ||
|  public:
 | ||
|  
 | ||
| @@ -391,46 +393,119 @@ static unsigned int roundUp(unsigned int n, unsigned int m)
 | ||
|  
 | ||
|  
 | ||
|  template<ElfFileParams>
 | ||
| -void ElfFile<ElfFileParamNames>::shiftFile(unsigned int extraPages, Elf_Addr startPage)
 | ||
| +void ElfFile<ElfFileParamNames>::shiftFileSingle(size_t fileShift,
 | ||
| +        Elf_Off insertOff)
 | ||
|  {
 | ||
| -    /* Move the entire contents of the file `extraPages' pages
 | ||
| -       further. */
 | ||
|      unsigned int oldSize = fileSize;
 | ||
| -    unsigned int shift = extraPages * pageSize;
 | ||
| -    growFile(fileSize + extraPages * pageSize);
 | ||
| -    memmove(contents + extraPages * pageSize, contents, oldSize);
 | ||
| -    memset(contents + sizeof(Elf_Ehdr), 0, shift - sizeof(Elf_Ehdr));
 | ||
| +
 | ||
| +    /* Grow at the end */
 | ||
| +    growFile(fileSize + fileShift);
 | ||
| +
 | ||
| +    /* move the data from the insertion point
 | ||
| +       to the end and zero inserted space */
 | ||
| +    memmove(contents + insertOff + fileShift,
 | ||
| +            contents + insertOff, oldSize - insertOff);
 | ||
| +    memset(contents + insertOff, 0, fileShift);
 | ||
|  
 | ||
|      /* Adjust the ELF header. */
 | ||
|      wri(hdr->e_phoff, sizeof(Elf_Ehdr));
 | ||
| -    wri(hdr->e_shoff, rdi(hdr->e_shoff) + shift);
 | ||
| +    if (rdi(hdr->e_shoff) >= insertOff)
 | ||
| +        wri(hdr->e_shoff, rdi(hdr->e_shoff) + fileShift);
 | ||
|  
 | ||
|      /* Update the offsets in the section headers. */
 | ||
| -    for (int i = 1; i < rdi(hdr->e_shnum); ++i)
 | ||
| -        wri(shdrs[i].sh_offset, rdi(shdrs[i].sh_offset) + shift);
 | ||
| +    for (int i = 1; i < rdi(hdr->e_shnum); ++i) {
 | ||
| +        if (rdi(shdrs[i].sh_offset) >= insertOff)
 | ||
| +            wri(shdrs[i].sh_offset, rdi(shdrs[i].sh_offset) + fileShift);
 | ||
| +    }
 | ||
|  
 | ||
|      /* Update the offsets in the program headers. */
 | ||
|      for (int i = 0; i < rdi(hdr->e_phnum); ++i) {
 | ||
| -        wri(phdrs[i].p_offset, rdi(phdrs[i].p_offset) + shift);
 | ||
| -        if (rdi(phdrs[i].p_align) != 0 &&
 | ||
| -            (rdi(phdrs[i].p_vaddr) - rdi(phdrs[i].p_offset)) % rdi(phdrs[i].p_align) != 0) {
 | ||
| -            debug("changing alignment of program header %d from %d to %d\n", i,
 | ||
| -                rdi(phdrs[i].p_align), pageSize);
 | ||
| -            wri(phdrs[i].p_align, pageSize);
 | ||
| +        if (rdi(phdrs[i].p_offset) >= insertOff)
 | ||
| +            wri(phdrs[i].p_offset, rdi(phdrs[i].p_offset) + fileShift);
 | ||
| +        /* Check for ELF load command alignment issue the same
 | ||
| +           way as glibc/elf/dl-load.c does. This gives us the
 | ||
| +           chance to run an interpreter explicitly. */
 | ||
| +        if (rdi(phdrs[i].p_type) == PT_LOAD && ((rdi(phdrs[i].p_vaddr) -
 | ||
| +          rdi(phdrs[i].p_offset)) & (rdi(phdrs[i].p_align) - 1)) != 0) {
 | ||
| +             debug("changing alignment of program header %d from %d to %d\n",
 | ||
| +                   i, rdi(phdrs[i].p_align), pageSize);
 | ||
| +             wri(phdrs[i].p_align, pageSize);
 | ||
|          }
 | ||
|      }
 | ||
| +}
 | ||
| +
 | ||
| +template<ElfFileParams>
 | ||
| +void ElfFile<ElfFileParamNames>::shiftFile(size_t neededCode,
 | ||
| +        size_t neededData, Elf_Off codeOff[], Elf_Off dataOff[],
 | ||
| +        Elf_Addr *codePage, Elf_Addr *dataPage)
 | ||
| +{
 | ||
| +    /* Move some contents of the file further. The binary has one LOAD area
 | ||
| +     * for code and one for data. There is virtual memory space between
 | ||
| +     * these which we can use due to alignment.
 | ||
| +     */
 | ||
| +    unsigned int memShift = neededCode;
 | ||
| +    unsigned int fileShift = roundUp(neededCode, pageSize);
 | ||
| +    unsigned int maxMemShift = 0;
 | ||
| +
 | ||
| +    if (neededCode > 0) {
 | ||
| +        /* find the LOAD program header for code and extend it */
 | ||
| +        for (int i = 0; i < rdi(hdr->e_phnum); ++i) {
 | ||
| +            if (rdi(phdrs[i].p_type) == PT_LOAD &&
 | ||
| +              rdi(phdrs[i].p_flags) & PF_X) {
 | ||
| +                codeOff[1] = rdi(phdrs[i].p_filesz);
 | ||
| +                codeOff[0] = codeOff[1] + rdi(phdrs[i].p_offset);
 | ||
| +                maxMemShift = rdi(phdrs[i].p_memsz) % rdi(phdrs[i].p_align);
 | ||
| +                if (maxMemShift == 0)
 | ||
| +                    continue;
 | ||
| +                maxMemShift = rdi(phdrs[i].p_align) - maxMemShift;
 | ||
| +                if (maxMemShift == 0 || memShift > maxMemShift)
 | ||
| +                    continue;
 | ||
| +                *codePage = rdi(phdrs[i].p_vaddr);
 | ||
| +                wri(phdrs[i].p_filesz, rdi(phdrs[i].p_filesz) + memShift);
 | ||
| +                wri(phdrs[i].p_memsz, rdi(phdrs[i].p_memsz) + memShift);
 | ||
| +                break;
 | ||
| +            }
 | ||
| +        }
 | ||
| +        debug("codeOff: %#lx, memShift: %d, maxMemShift: %d, fileShift: %d\n",
 | ||
| +              codeOff[1], memShift, maxMemShift, fileShift);
 | ||
| +        if (codeOff[1] == 0 || maxMemShift == 0)
 | ||
| +            goto out;
 | ||
| +
 | ||
| +        shiftFileSingle(fileShift, codeOff[0]);
 | ||
| +    }
 | ||
| +
 | ||
| +    /* +++ Do the same for the data LOAD area  +++ */
 | ||
| +    memShift = neededData;
 | ||
| +    fileShift = roundUp(neededData, pageSize);
 | ||
| +    maxMemShift = 0;
 | ||
| +    if (neededData > 0) {
 | ||
| +        /* find the LOAD program header for data and extend it */
 | ||
| +        for (int i = 0; i < rdi(hdr->e_phnum); ++i) {
 | ||
| +            if (rdi(phdrs[i].p_type) == PT_LOAD &&
 | ||
| +              rdi(phdrs[i].p_flags) & PF_W) {
 | ||
| +                dataOff[1] = rdi(phdrs[i].p_filesz);
 | ||
| +                dataOff[0] = dataOff[1] + rdi(phdrs[i].p_offset);
 | ||
| +                maxMemShift = rdi(phdrs[i].p_memsz) % rdi(phdrs[i].p_align);
 | ||
| +                if (maxMemShift == 0)
 | ||
| +                    continue;
 | ||
| +                maxMemShift = rdi(phdrs[i].p_align) - maxMemShift;
 | ||
| +                if (maxMemShift == 0 || memShift > maxMemShift)
 | ||
| +                    continue;
 | ||
| +                *dataPage = rdi(phdrs[i].p_vaddr);
 | ||
| +                wri(phdrs[i].p_filesz, rdi(phdrs[i].p_filesz) + memShift);
 | ||
| +                wri(phdrs[i].p_memsz, rdi(phdrs[i].p_memsz) + memShift);
 | ||
| +                break;
 | ||
| +            }
 | ||
| +        }
 | ||
| +        debug("dataOff: %#lx, memShift: %d, maxMemShift: %d, fileShift: %d\n",
 | ||
| +              dataOff[1], memShift, maxMemShift, fileShift);
 | ||
| +        if (dataOff[1] == 0 || maxMemShift == 0)
 | ||
| +            goto out;
 | ||
|  
 | ||
| -    /* Add a segment that maps the new program/section headers and
 | ||
| -       PT_INTERP segment into memory.  Otherwise glibc will choke. */
 | ||
| -    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, 0);
 | ||
| -    wri(phdr.p_vaddr, wri(phdr.p_paddr, startPage));
 | ||
| -    wri(phdr.p_filesz, wri(phdr.p_memsz, shift));
 | ||
| -    wri(phdr.p_flags, PF_R | PF_W);
 | ||
| -    wri(phdr.p_align, pageSize);
 | ||
| +        shiftFileSingle(fileShift, dataOff[0]);
 | ||
| +    }
 | ||
| +out:
 | ||
| +    return;
 | ||
|  }
 | ||
|  
 | ||
|  
 | ||
| @@ -491,7 +566,7 @@ string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sectionN
 | ||
|  
 | ||
|  template<ElfFileParams>
 | ||
|  void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
 | ||
| -    Elf_Addr startAddr, Elf_Off startOffset)
 | ||
| +    Elf_Addr startAddr, Elf_Off startOffset, bool isData = false)
 | ||
|  {
 | ||
|      /* Overwrite the old section contents with 'X's.  Do this
 | ||
|         *before* writing the new section contents (below) to prevent
 | ||
| @@ -501,6 +576,9 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
 | ||
|      {
 | ||
|          string sectionName = i->first;
 | ||
|          Elf_Shdr & shdr = findSection(sectionName);
 | ||
| +        if ((!isData && rdi(shdr.sh_flags) & SHF_WRITE) ||
 | ||
| +         (isData && ~(rdi(shdr.sh_flags)) & SHF_WRITE))
 | ||
| +            continue;
 | ||
|          memset(contents + rdi(shdr.sh_offset), 'X', rdi(shdr.sh_size));
 | ||
|      }
 | ||
|  
 | ||
| @@ -509,6 +587,9 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
 | ||
|      {
 | ||
|          string sectionName = i->first;
 | ||
|          Elf_Shdr & shdr = findSection(sectionName);
 | ||
| +        if ((!isData && rdi(shdr.sh_flags) & SHF_WRITE) ||
 | ||
| +         (isData && ~(rdi(shdr.sh_flags)) & SHF_WRITE))
 | ||
| +            continue;
 | ||
|          debug("rewriting section `%s' from offset 0x%x (size %d) to offset 0x%x (size %d)\n",
 | ||
|              sectionName.c_str(), rdi(shdr.sh_offset), rdi(shdr.sh_size), curOff, i->second.size());
 | ||
|  
 | ||
| @@ -546,201 +627,47 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
 | ||
|          curOff += roundUp(i->second.size(), sectionAlignment);
 | ||
|      }
 | ||
|  
 | ||
| -    replacedSections.clear();
 | ||
| +    if (isData)
 | ||
| +        replacedSections.clear();
 | ||
|  }
 | ||
|  
 | ||
|  
 | ||
|  template<ElfFileParams>
 | ||
| -void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
 | ||
| +void ElfFile<ElfFileParamNames>::rewriteSectionsBinary()
 | ||
|  {
 | ||
| -    /* 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 startPage = 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 > startPage) startPage = thisPage;
 | ||
| -    }
 | ||
| -
 | ||
| -    debug("last page is 0x%llx\n", (unsigned long long) startPage);
 | ||
| +    Elf_Off codeOff[2] = {0}, dataOff[2] = {0};
 | ||
| +    Elf_Addr codePage = 0, dataPage = 0;
 | ||
| +    size_t neededCode = 0, neededData = 0, oldCode = 0, oldData = 0;
 | ||
| +    Elf_Shdr shdr = findSection(".text");
 | ||
| +    Elf_Addr firstPage = rdi(shdr.sh_addr) - rdi(shdr.sh_offset);
 | ||
|  
 | ||
| +    debug("first page is 0x%llx\n", (unsigned long long) firstPage);
 | ||
|  
 | ||
| -    /* Compute the total space needed for the replaced sections and
 | ||
| -       the program headers. */
 | ||
| -    off_t neededSpace = (phdrs.size() + 1) * sizeof(Elf_Phdr);
 | ||
| +    /* Compute the total space needed for the replaced sections */
 | ||
|      for (ReplacedSections::iterator i = replacedSections.begin();
 | ||
| -         i != replacedSections.end(); ++i)
 | ||
| -        neededSpace += roundUp(i->second.size(), sectionAlignment);
 | ||
| -    debug("needed space is %d\n", neededSpace);
 | ||
| -
 | ||
| -
 | ||
| -    size_t startOffset = roundUp(fileSize, pageSize);
 | ||
| -
 | ||
| -    growFile(startOffset + neededSpace);
 | ||
| -
 | ||
| -
 | ||
| -    /* Even though this file is of type ET_DYN, it could actually be
 | ||
| -       an executable.  For instance, Gold produces executables marked
 | ||
| -       ET_DYN.  In that case we can still hit the kernel bug that
 | ||
| -       necessitated rewriteSectionsExecutable().  However, such
 | ||
| -       executables also tend to start at virtual address 0, so
 | ||
| -       rewriteSectionsExecutable() won't work because it doesn't have
 | ||
| -       any virtual address space to grow downwards into.  As a
 | ||
| -       workaround, make sure that the virtual address of our new
 | ||
| -       PT_LOAD segment relative to the first PT_LOAD segment is equal
 | ||
| -       to its offset; otherwise we hit the kernel bug.  This may
 | ||
| -       require creating a hole in the executable.  The bigger the size
 | ||
| -       of the uninitialised data segment, the bigger the hole. */
 | ||
| -    if (isExecutable) {
 | ||
| -        if (startOffset >= startPage) {
 | ||
| -            debug("shifting new PT_LOAD segment by %d bytes to work around a Linux kernel bug\n", startOffset - startPage);
 | ||
| -        } else {
 | ||
| -            size_t hole = startPage - startOffset;
 | ||
| -            /* Print a warning, because the hole could be very big. */
 | ||
| -            fprintf(stderr, "warning: working around a Linux kernel bug by creating a hole of %zu bytes in ‘%s’\n", hole, fileName.c_str());
 | ||
| -            assert(hole % pageSize == 0);
 | ||
| -            /* !!! We could create an actual hole in the file here,
 | ||
| -               but it's probably not worth the effort. */
 | ||
| -            growFile(fileSize + hole);
 | ||
| -            startOffset += hole;
 | ||
| -        }
 | ||
| -        startPage = startOffset;
 | ||
| -    }
 | ||
| -
 | ||
| -
 | ||
| -    /* 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, startPage));
 | ||
| -    wri(phdr.p_filesz, wri(phdr.p_memsz, neededSpace));
 | ||
| -    wri(phdr.p_flags, PF_R | PF_W);
 | ||
| -    wri(phdr.p_align, pageSize);
 | ||
| -
 | ||
| -
 | ||
| -    /* Write out the replaced sections. */
 | ||
| -    Elf_Off curOff = startOffset + phdrs.size() * sizeof(Elf_Phdr);
 | ||
| -    writeReplacedSections(curOff, startPage, startOffset);
 | ||
| -    assert((off_t) curOff == startOffset + neededSpace);
 | ||
| -
 | ||
| -
 | ||
| -    /* Move the program header to the start of the new area. */
 | ||
| -    wri(hdr->e_phoff, startOffset);
 | ||
| -
 | ||
| -    rewriteHeaders(startPage);
 | ||
| -}
 | ||
| -
 | ||
| -
 | ||
| -template<ElfFileParams>
 | ||
| -void ElfFile<ElfFileParamNames>::rewriteSectionsExecutable()
 | ||
| -{
 | ||
| -    /* 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;
 | ||
| -    for (unsigned int i = 1; i < rdi(hdr->e_shnum); ++i) {
 | ||
| -        string sectionName = getSectionName(shdrs[i]);
 | ||
| -        if (replacedSections.find(sectionName) != replacedSections.end()) {
 | ||
| -            debug("using replaced section `%s'\n", sectionName.c_str());
 | ||
| -            lastReplaced = i;
 | ||
| -        }
 | ||
| -    }
 | ||
| -
 | ||
| -    assert(lastReplaced != 0);
 | ||
| -
 | ||
| -    debug("last replaced is %d\n", lastReplaced);
 | ||
| -
 | ||
| -    /* Try to replace all sections before that, as far as possible.
 | ||
| -       Stop when we reach an irreplacable section (such as one of type
 | ||
| -       SHT_PROGBITS).  These cannot be moved in virtual address space
 | ||
| -       since that would invalidate absolute references to them. */
 | ||
| -    assert(lastReplaced + 1 < shdrs.size()); /* !!! I'm lazy. */
 | ||
| -    size_t startOffset = rdi(shdrs[lastReplaced + 1].sh_offset);
 | ||
| -    Elf_Addr startAddr = rdi(shdrs[lastReplaced + 1].sh_addr);
 | ||
| -    string prevSection;
 | ||
| -    for (unsigned int i = 1; i <= lastReplaced; ++i) {
 | ||
| -        Elf_Shdr & shdr(shdrs[i]);
 | ||
| -        string sectionName = getSectionName(shdr);
 | ||
| -        debug("looking at section `%s'\n", sectionName.c_str());
 | ||
| -        /* !!! Why do we stop after a .dynstr section? I can't
 | ||
| -           remember! */
 | ||
| -        if ((rdi(shdr.sh_type) == SHT_PROGBITS && sectionName != ".interp")
 | ||
| -            || prevSection == ".dynstr")
 | ||
| -        {
 | ||
| -            startOffset = rdi(shdr.sh_offset);
 | ||
| -            startAddr = rdi(shdr.sh_addr);
 | ||
| -            lastReplaced = i - 1;
 | ||
| -            break;
 | ||
| +         i != replacedSections.end(); ++i) {
 | ||
| +        shdr = findSection(i->first);
 | ||
| +        if (rdi(shdr.sh_flags) & SHF_WRITE) {
 | ||
| +            oldData += rdi(shdr.sh_size);
 | ||
| +            neededData += roundUp(i->second.size(), sectionAlignment);
 | ||
|          } else {
 | ||
| -            if (replacedSections.find(sectionName) == replacedSections.end()) {
 | ||
| -                debug("replacing section `%s' which is in the way\n", sectionName.c_str());
 | ||
| -                replaceSection(sectionName, rdi(shdr.sh_size));
 | ||
| -            }
 | ||
| +            oldCode += rdi(shdr.sh_size);
 | ||
| +            neededCode += roundUp(i->second.size(), sectionAlignment);
 | ||
|          }
 | ||
| -        prevSection = sectionName;
 | ||
|      }
 | ||
|  
 | ||
| -    debug("first reserved offset/addr is 0x%x/0x%llx\n",
 | ||
| -        startOffset, (unsigned long long) startAddr);
 | ||
| -
 | ||
| -    assert(startAddr % pageSize == startOffset % pageSize);
 | ||
| -    Elf_Addr firstPage = startAddr - startOffset;
 | ||
| -    debug("first page is 0x%llx\n", (unsigned long long) firstPage);
 | ||
| -
 | ||
| -    /* Right now we assume that the section headers are somewhere near
 | ||
| -       the end, which appears to be the case most of the time.
 | ||
| -       Therefore they're not accidentally overwritten by the replaced
 | ||
| -       sections. !!!  Fix this. */
 | ||
| -    assert((off_t) rdi(hdr->e_shoff) >= startOffset);
 | ||
| -
 | ||
| -
 | ||
| -    /* Compute the total space needed for the replaced sections, the
 | ||
| -       ELF header, and the program headers. */
 | ||
| -    size_t neededSpace = sizeof(Elf_Ehdr) + phdrs.size() * 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);
 | ||
| -
 | ||
| -    /* If we need more space at the start of the file, then grow the
 | ||
| -       file by the minimum number of pages and adjust internal
 | ||
| -       offsets. */
 | ||
| -    if (neededSpace > startOffset) {
 | ||
| -
 | ||
| -        /* We also need an additional program header, so adjust for that. */
 | ||
| -        neededSpace += sizeof(Elf_Phdr);
 | ||
| -        debug("needed space is %d\n", neededSpace);
 | ||
| -
 | ||
| -        unsigned int neededPages = roundUp(neededSpace - startOffset, pageSize) / pageSize;
 | ||
| -        debug("needed pages is %d\n", neededPages);
 | ||
| -        if (neededPages * pageSize > firstPage)
 | ||
| -            error("virtual address space underrun!");
 | ||
| -
 | ||
| -        firstPage -= neededPages * pageSize;
 | ||
| -        startOffset += neededPages * pageSize;
 | ||
| -
 | ||
| -        shiftFile(neededPages, firstPage);
 | ||
| -    }
 | ||
| -
 | ||
| -
 | ||
| -    /* Clear out the free space. */
 | ||
| -    Elf_Off curOff = sizeof(Elf_Ehdr) + phdrs.size() * sizeof(Elf_Phdr);
 | ||
| -    debug("clearing first %d bytes\n", startOffset - curOff);
 | ||
| -    memset(contents + curOff, 0, startOffset - curOff);
 | ||
| +    debug("needed space is C: %d, D: %d\n", neededCode, neededData);
 | ||
|  
 | ||
| +    /* If we need more space within the file, then grow the
 | ||
| +       file and adjust internal offsets. */
 | ||
| +    shiftFile(neededCode, neededData, codeOff, dataOff, &codePage,
 | ||
| +              &dataPage);
 | ||
| +    assert(codeOff[0] > 0);
 | ||
|  
 | ||
|      /* Write out the replaced sections. */
 | ||
| -    writeReplacedSections(curOff, firstPage, 0);
 | ||
| -    assert((off_t) curOff == neededSpace);
 | ||
| -
 | ||
| +    debug("codePage: %#lx, dataPage: %#lx\n", codePage, dataPage);
 | ||
| +    writeReplacedSections(codeOff[0], codePage + codeOff[1], codeOff[0]);
 | ||
| +    writeReplacedSections(dataOff[0], dataPage + dataOff[1], dataOff[0], true);
 | ||
|  
 | ||
|      rewriteHeaders(firstPage + rdi(hdr->e_phoff));
 | ||
|  }
 | ||
| @@ -758,10 +685,10 @@ void ElfFile<ElfFileParamNames>::rewriteSections()
 | ||
|  
 | ||
|      if (rdi(hdr->e_type) == ET_DYN) {
 | ||
|          debug("this is a dynamic library\n");
 | ||
| -        rewriteSectionsLibrary();
 | ||
| +        rewriteSectionsBinary();
 | ||
|      } else if (rdi(hdr->e_type) == ET_EXEC) {
 | ||
|          debug("this is an executable\n");
 | ||
| -        rewriteSectionsExecutable();
 | ||
| +        rewriteSectionsBinary();
 | ||
|      } else error("unknown ELF type");
 | ||
|  }
 | ||
|  
 | ||
| -- 
 | ||
| 2.1.2
 | ||
| 
 |