aboutsummaryrefslogtreecommitdiff
path: root/package/patchelf/0005-Avoid-inflating-file-sizes-needlessly-and-allow-bina.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/patchelf/0005-Avoid-inflating-file-sizes-needlessly-and-allow-bina.patch')
-rw-r--r--package/patchelf/0005-Avoid-inflating-file-sizes-needlessly-and-allow-bina.patch176
1 files changed, 176 insertions, 0 deletions
diff --git a/package/patchelf/0005-Avoid-inflating-file-sizes-needlessly-and-allow-bina.patch b/package/patchelf/0005-Avoid-inflating-file-sizes-needlessly-and-allow-bina.patch
new file mode 100644
index 0000000000..0d7931cd52
--- /dev/null
+++ b/package/patchelf/0005-Avoid-inflating-file-sizes-needlessly-and-allow-bina.patch
@@ -0,0 +1,176 @@
+From 79c093226e609b99fa889f6e37480b92b399610d Mon Sep 17 00:00:00 2001
+From: Richard Purdie <richard.purdie@linuxfoundation.org>
+Date: Tue, 7 Mar 2017 21:08:34 +0000
+Subject: [PATCH] Avoid inflating file sizes needlessly and allow binaries to
+ be stripped
+
+The current approach to changing sections in ET_DYN executables is to move
+the INTERP section to the end of the file. +This means changing PT_PHDR to
+add an extra PT_LOAD section so that the new section is mmaped into memory
+by the elf loader in the kernel. In order to extend PHDR, this means moving
+it to the end of the file.
+
+Its documented in BUGS there is a kernel 'bug' which means that if you have holes
+in memory between the base load address and the PT_LOAD segment that contains PHDR,
+it will pass an incorrect PHDR address to ld.so and fail to load the binary, segfaulting.
+
+To avoid this, the code currently inserts space into the binary to ensure that when
+loaded into memory there are no holes between the PT_LOAD sections. This inflates the
+binaries by many MBs in some cases. Whilst we could make them sparse, there is a second
+issue which is that strip can fail to process these binaries:
+
+$ strip fixincl
+Not enough room for program headers, try linking with -N
+[.note.ABI-tag]: Bad value
+
+This turns out to be due to libbfd not liking the relocated PHDR section either
+(https://github.com/NixOS/patchelf/issues/10).
+
+Instead this patch implements a different approach, leaving PHDR where it is but extending
+it in place to allow addition of a new PT_LOAD section. This overwrites sections in the
+binary but those get moved to the end of the file in the new PT_LOAD section.
+
+This is based on patches linked from the above github issue, however whilst the idea
+was good, the implementation wasn't correct and they've been rewritten here.
+
+Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
+
+Fetch from: https://github.com/NixOS/patchelf/commit/c4deb5e9e1ce9c98a48e0d5bb37d87739b8cfee4
+
+Backported to v0.9
+
+Signed-off-by: Conrad Ratschan <conrad.ratschan@rockwellcollins.com>
+---
+ src/patchelf.cc | 71 ++++++++++++++++++++++++++++---------------------
+ 1 file changed, 40 insertions(+), 31 deletions(-)
+
+diff --git a/src/patchelf.cc b/src/patchelf.cc
+index 1d58061..c2147af 100644
+--- a/src/patchelf.cc
++++ b/src/patchelf.cc
+@@ -209,6 +209,8 @@ private:
+ string & replaceSection(const SectionName & sectionName,
+ unsigned int size);
+
++ bool haveReplacedSection(const SectionName & sectionName);
++
+ void writeReplacedSections(Elf_Off & curOff,
+ Elf_Addr startAddr, Elf_Off startOffset);
+
+@@ -632,6 +634,15 @@ void ElfFile<ElfFileParamNames>::writeReplacedSections(Elf_Off & curOff,
+ replacedSections.clear();
+ }
+
++template<ElfFileParams>
++bool ElfFile<ElfFileParamNames>::haveReplacedSection(const SectionName & sectionName)
++{
++ ReplacedSections::iterator i = replacedSections.find(sectionName);
++
++ if (i != replacedSections.end())
++ return true;
++ return false;
++}
+
+ template<ElfFileParams>
+ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
+@@ -648,52 +659,53 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
+
+ debug("last page is 0x%llx\n", (unsigned long long) startPage);
+
++ /* Because we're adding a new section header, we're necessarily increasing
++ the size of the program header table. This can cause the first section
++ to overlap the program header table in memory; we need to shift the first
++ few segments to someplace else. */
++ /* Some sections may already be replaced so account for that */
++ unsigned int i = 1;
++ Elf_Addr pht_size = sizeof(Elf_Ehdr) + (phdrs.size() + 1)*sizeof(Elf_Phdr);
++ while( shdrs[i].sh_addr <= pht_size && i < rdi(hdr->e_shnum) ) {
++ if (not haveReplacedSection(getSectionName(shdrs[i])))
++ replaceSection(getSectionName(shdrs[i]), shdrs[i].sh_size);
++ i++;
++ }
+
+- /* 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 */
++ off_t neededSpace = 0;
+ 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, getPageSize());
+
+ 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
++ ET_DYN as does LD when linking with pie. If we move PT_PHDR, it
++ has to stay in the first PT_LOAD segment or any subsequent ones
++ if they're continuous in memory due to linux kernel constraints
++ (see BUGS). Since the end of the file would be after bss, we can't
++ move PHDR there, we therefore choose to leave PT_PHDR where it is but
++ move enough following sections such that we can add the extra PT_LOAD
++ section to it. This PT_LOAD segment ensures the sections at the end of
++ the file are mapped into memory for ld.so to process.
++ We can't use the approach in rewriteSectionsExecutable()
++ since DYN executables 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. */
++ any virtual address space to grow downwards into. */
+ 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 % getPageSize() == 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. */
++ /* 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[rdi(hdr->e_phnum) - 1];
+@@ -706,15 +718,12 @@ void ElfFile<ElfFileParamNames>::rewriteSectionsLibrary()
+
+
+ /* Write out the replaced sections. */
+- Elf_Off curOff = startOffset + phdrs.size() * sizeof(Elf_Phdr);
++ Elf_Off curOff = startOffset;
+ writeReplacedSections(curOff, startPage, startOffset);
+ assert(curOff == startOffset + neededSpace);
+
+-
+- /* Move the program header to the start of the new area. */
+- wri(hdr->e_phoff, startOffset);
+-
+- rewriteHeaders(startPage);
++ /* Write out the updated program and section headers */
++ rewriteHeaders(hdr->e_phoff);
+ }
+
+
+--
+2.17.1
+