gnu: patchelf: Update to 0.10.
* gnu/packages/elf.scm (patchelf): Update to 0.10. [source]: Remove patches. [arguments]: Remove patch/rework-for-arm phase. Add phase to modify tests for our modified GCC package. [native-inputs]: Add gcc:lib. * gnu/packages/patches/patchelf-page-size.patch, * gnu/packages/patches/patchelf-rework-for-arm.patch: Remove files. * gnu/local.mk (dist_patch_DATA): Remove them.
This commit is contained in:
parent
4e4f3a6b76
commit
0d01a5a9d4
|
@ -1205,8 +1205,6 @@ dist_patch_DATA = \
|
|||
%D%/packages/patches/p7zip-CVE-2016-9296.patch \
|
||||
%D%/packages/patches/p7zip-CVE-2017-17969.patch \
|
||||
%D%/packages/patches/p7zip-remove-unused-code.patch \
|
||||
%D%/packages/patches/patchelf-page-size.patch \
|
||||
%D%/packages/patches/patchelf-rework-for-arm.patch \
|
||||
%D%/packages/patches/patchutils-test-perms.patch \
|
||||
%D%/packages/patches/patch-hurd-path-max.patch \
|
||||
%D%/packages/patches/pcre2-fix-jit_match-crash.patch \
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2014, 2015 Mark H Weaver <mhw@netris.org>
|
||||
;;; Copyright © 2015 Andreas Enge <andreas@enge.fr>
|
||||
;;; Copyright © 2017, 2018 Efraim Flashner <efraim@flashner.co.il>
|
||||
;;; Copyright © 2017, 2018, 2019 Efraim Flashner <efraim@flashner.co.il>
|
||||
;;; Copyright © 2017 Leo Famulari <leo@famulari.name>
|
||||
;;; Copyright © 2018 Tobias Geerinckx-Rice <me@tobias.gr>
|
||||
;;; Copyright © 2018 Marius Bakke <mbakke@fastmail.com>
|
||||
|
@ -31,6 +31,7 @@ (define-module (gnu packages elf)
|
|||
#:use-module (gnu packages)
|
||||
#:use-module (gnu packages compression)
|
||||
#:use-module (gnu packages documentation)
|
||||
#:use-module (gnu packages gcc)
|
||||
#:use-module (gnu packages m4)
|
||||
#:use-module (gnu packages pkg-config)
|
||||
#:use-module (gnu packages python)
|
||||
|
@ -198,7 +199,7 @@ (define-public libelf
|
|||
(define-public patchelf
|
||||
(package
|
||||
(name "patchelf")
|
||||
(version "0.8")
|
||||
(version "0.10")
|
||||
(source (origin
|
||||
(method url-fetch)
|
||||
(uri (string-append
|
||||
|
@ -207,28 +208,24 @@ (define-public patchelf
|
|||
"/patchelf-" version ".tar.bz2"))
|
||||
(sha256
|
||||
(base32
|
||||
"1rqpg84wrd3fa16wa9vqdvasnc05yz49w207cz1l0wrl4k8q97y9"))
|
||||
(patches (search-patches "patchelf-page-size.patch"))))
|
||||
"1wzwvnlyf853hw9zgqq5522bvf8gqadk8icgqa41a5n7593csw7n"))))
|
||||
(build-system gnu-build-system)
|
||||
|
||||
;; XXX: The upstream 'patchelf' doesn't support ARM. The only available
|
||||
;; patch makes significant changes to the algorithm, possibly
|
||||
;; introducing bugs. So, we apply the patch only on ARM systems.
|
||||
(inputs
|
||||
(if (target-arm32?)
|
||||
`(("patch/rework-for-arm" ,(search-patch
|
||||
"patchelf-rework-for-arm.patch")))
|
||||
'()))
|
||||
(arguments
|
||||
(if (target-arm32?)
|
||||
`(#:phases
|
||||
(modify-phases %standard-phases
|
||||
(add-after 'unpack 'patch/rework-for-arm
|
||||
(lambda* (#:key inputs #:allow-other-keys)
|
||||
(let ((patch-file (assoc-ref inputs "patch/rework-for-arm")))
|
||||
(invoke "patch" "--force" "-p1" "--input" patch-file))))))
|
||||
'()))
|
||||
|
||||
'(#:phases
|
||||
(modify-phases %standard-phases
|
||||
(add-after 'unpack 'fix-tests
|
||||
;; Our GCC code ensures that RUNPATH is never empty, it includes
|
||||
;; at least glibc/lib and gcc:lib/lib.
|
||||
(lambda* (#:key inputs #:allow-other-keys)
|
||||
(substitute* "tests/no-rpath.sh"
|
||||
;; Disable checking for an empty runpath:
|
||||
(("^if test.*") "")
|
||||
;; Find libgcc_s.so, which is necessary for the test:
|
||||
(("/xxxxxxxxxxxxxxx") (string-append (assoc-ref inputs "gcc:lib")
|
||||
"/lib")))
|
||||
#t)))))
|
||||
(native-inputs
|
||||
`(("gcc:lib" ,gcc "lib")))
|
||||
(home-page "https://nixos.org/patchelf.html")
|
||||
(synopsis "Modify the dynamic linker and RPATH of ELF executables")
|
||||
(description
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
Improve the determination of pageSize in patchelf.cc.
|
||||
|
||||
Patch by Mark H Weaver <mhw@netris.org>.
|
||||
|
||||
--- patchelf/src/patchelf.cc.orig 1969-12-31 19:00:01.000000000 -0500
|
||||
+++ patchelf/src/patchelf.cc 2014-02-16 20:15:06.283203125 -0500
|
||||
@@ -21,11 +21,19 @@
|
||||
using namespace std;
|
||||
|
||||
|
||||
-#ifdef MIPSEL
|
||||
-/* The lemote fuloong 2f kernel defconfig sets a page size of 16KB */
|
||||
-const unsigned int pageSize = 4096*4;
|
||||
-#else
|
||||
+/* Note that some platforms support multiple page sizes. Therefore,
|
||||
+ it is not enough to query the current page size. 'pageSize' must
|
||||
+ be the maximum architectural page size for the platform, which is
|
||||
+ typically defined in the corresponding ABI document.
|
||||
+
|
||||
+ XXX FIXME: This won't work when we're cross-compiling. */
|
||||
+
|
||||
+#if defined __MIPSEL__ || defined __MIPSEB__ || defined __aarch64__
|
||||
+const unsigned int pageSize = 65536;
|
||||
+#elif defined __x86_64__ || defined __i386__ || defined __arm__
|
||||
const unsigned int pageSize = 4096;
|
||||
+#else
|
||||
+# error maximum architectural page size unknown for this platform
|
||||
#endif
|
||||
|
||||
|
||||
--- patchelf/tests/no-rpath.sh.orig 2014-01-14 08:17:47.000000000 -0500
|
||||
+++ patchelf/tests/no-rpath.sh 2015-01-06 18:31:53.418172797 -0500
|
||||
@@ -1,23 +1,23 @@
|
||||
#! /bin/sh -e
|
||||
SCRATCH=scratch/$(basename $0 .sh)
|
||||
|
||||
-rm -rf ${SCRATCH}
|
||||
-mkdir -p ${SCRATCH}
|
||||
+if [ "$(uname -m)" = i686 -a "$(uname -s)" = Linux ]; then
|
||||
+ rm -rf ${SCRATCH}
|
||||
+ mkdir -p ${SCRATCH}
|
||||
|
||||
-cp ${srcdir}/no-rpath ${SCRATCH}/
|
||||
+ cp ${srcdir}/no-rpath ${SCRATCH}/
|
||||
|
||||
-oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/no-rpath)
|
||||
-if test -n "$oldRPath"; then exit 1; fi
|
||||
-../src/patchelf \
|
||||
- --set-interpreter "$(../src/patchelf --print-interpreter ../src/patchelf)" \
|
||||
- --set-rpath /foo:/bar:/xxxxxxxxxxxxxxx ${SCRATCH}/no-rpath
|
||||
+ oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/no-rpath)
|
||||
+ if test -n "$oldRPath"; then exit 1; fi
|
||||
+ ../src/patchelf \
|
||||
+ --set-interpreter "$(../src/patchelf --print-interpreter ../src/patchelf)" \
|
||||
+ --set-rpath /foo:/bar:/xxxxxxxxxxxxxxx ${SCRATCH}/no-rpath
|
||||
|
||||
-newRPath=$(../src/patchelf --print-rpath ${SCRATCH}/no-rpath)
|
||||
-if ! echo "$newRPath" | grep -q '/foo:/bar'; then
|
||||
- echo "incomplete RPATH"
|
||||
- exit 1
|
||||
-fi
|
||||
+ newRPath=$(../src/patchelf --print-rpath ${SCRATCH}/no-rpath)
|
||||
+ if ! echo "$newRPath" | grep -q '/foo:/bar'; then
|
||||
+ echo "incomplete RPATH"
|
||||
+ exit 1
|
||||
+ fi
|
||||
|
||||
-if [ "$(uname -m)" = i686 -a "$(uname -s)" = Linux ]; then
|
||||
cd ${SCRATCH} && ./no-rpath
|
||||
fi
|
|
@ -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
|
||||
|
Loading…
Reference in a new issue