From 0470d6921b5a3fe8e92e356c8e11d120dbbb06c0 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 20 Jun 2020 01:46:23 +0200 Subject: Improve the default section alignment choice Currently patchelf uses the host system's page size (determined at build time) as the default section load memory alignment. This causes multiple issues - Cross-compilation: when using patchelf on ELFs targetting a different architecture from the host, the host page size is still used by default. - Variable page size architectures: ARMv8 systems can be configured in either 4K, 16K, or 64K page size mode depending on kernel configuration. An ARMv8 patchelf built on a 4K page size system will end up creating ELFs that cannot be used on a 64K page size system. - Reproducibility: the page size of the machine that built patchelf "leaks" into the binary. The build time --with-page-size as well as the run time --page-size options can be used to work around some of these issues. But it's much better to have patchelf do the right thing without explicit configuration. This commit adds support for inferring page size from the ELF header's "machine" field. The default values are extracted from GNU gold's source code. Note that both --with-page-size as well as --page-size continue to work and take precedence on the default value. --- configure.ac | 17 +++++------------ src/patchelf.cc | 43 ++++++++++++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/configure.ac b/configure.ac index 80f82d7..3af271f 100644 --- a/configure.ac +++ b/configure.ac @@ -7,24 +7,17 @@ AM_INIT_AUTOMAKE([1.11.1 -Wall -Werror dist-bzip2 foreign color-tests parallel-t AM_PROG_CC_C_O AC_PROG_CXX -PAGESIZE=auto +DEFAULT_PAGESIZE=auto AC_ARG_WITH([page-size], AS_HELP_STRING([--with-page-size=SIZE], [Specify default pagesize (default auto)]), - PAGESIZE=$withval + DEFAULT_PAGESIZE=$withval ) -if test "$PAGESIZE" = auto; then - if command -v getconf >/dev/null; then - PAGESIZE=$(getconf PAGESIZE || getconf PAGE_SIZE) - fi - if test "$PAGESIZE" = auto -o -z "$PAGESIZE"; then - PAGESIZE=4096 - fi +if test "$DEFAULT_PAGESIZE" != auto; then + AC_DEFINE_UNQUOTED(DEFAULT_PAGESIZE, ${DEFAULT_PAGESIZE}) + AC_MSG_RESULT([Setting page size to ${DEFAULT_PAGESIZE}]) fi -AC_DEFINE_UNQUOTED(PAGESIZE, ${PAGESIZE}) -AC_MSG_RESULT([Setting page size to ${PAGESIZE}]) - AC_ARG_WITH([asan], AS_HELP_STRING([--with-asan], [Link with libasan]) ) diff --git a/src/patchelf.cc b/src/patchelf.cc index 2d9077c..ea6c6c0 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -48,7 +48,11 @@ static bool forceRPath = false; static std::vector fileNames; static std::string outputFileName; static bool alwaysWrite = false; -static int pageSize = PAGESIZE; +#ifdef DEFAULT_PAGESIZE +static int forcedPageSize = DEFAULT_PAGESIZE; +#else +static int forcedPageSize = -1; +#endif typedef std::shared_ptr> FileContents; @@ -81,12 +85,6 @@ static bool hasAllowedPrefix(const std::string & s, const std::vector class ElfFile { @@ -161,6 +159,8 @@ private: friend struct CompShdr; + unsigned int getPageSize() const; + void sortShdrs(); void shiftFile(unsigned int extraPages, Elf_Addr startPage); @@ -444,6 +444,29 @@ ElfFile::ElfFile(FileContents fileContents) template +unsigned int ElfFile::getPageSize() const +{ + if (forcedPageSize > 0) + return forcedPageSize; + + // Architectures (and ABIs) can have different minimum section alignment + // requirements. There is no authoritative list of these values. The + // current list is extracted from GNU gold's source code (abi_pagesize). + switch (hdr->e_machine) { + case EM_SPARC: + case EM_MIPS: + case EM_PPC: + case EM_PPC64: + case EM_AARCH64: + case EM_TILEGX: + return 0x10000; + default: + return 0x1000; + } +} + + +template void ElfFile::sortPhdrs() { /* Sort the segments by offset. */ @@ -1608,8 +1631,6 @@ static void patchElf() if (!printInterpreter && !printRPath && !printSoname && !printNeeded) debug("patching ELF file '%s'\n", fileName.c_str()); - debug("Kernel page size is %u bytes\n", getPageSize()); - auto fileContents = readFile(fileName); std::string outputFileName2 = outputFileName.empty() ? fileName : outputFileName; @@ -1665,8 +1686,8 @@ int mainWrapped(int argc, char * * argv) } else if (arg == "--page-size") { if (++i == argc) error("missing argument"); - pageSize = atoi(argv[i]); - if (pageSize <= 0) error("invalid argument to --page-size"); + forcedPageSize = atoi(argv[i]); + if (forcedPageSize <= 0) error("invalid argument to --page-size"); } else if (arg == "--print-interpreter") { printInterpreter = true; -- cgit v0.12