diff options
Diffstat (limited to 'gnu/packages/patches/patchelf-rework-for-arm.patch')
-rw-r--r-- | gnu/packages/patches/patchelf-rework-for-arm.patch | 473 |
1 files changed, 0 insertions, 473 deletions
diff --git a/gnu/packages/patches/patchelf-rework-for-arm.patch b/gnu/packages/patches/patchelf-rework-for-arm.patch deleted file mode 100644 index 6f4eb8f72b..0000000000 --- a/gnu/packages/patches/patchelf-rework-for-arm.patch +++ /dev/null @@ -1,473 +0,0 @@ -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 - |