diff options
author | Pierre Bourdon <delroth@gmail.com> | 2020-06-19 23:46:23 (GMT) |
---|---|---|
committer | Pierre Bourdon <delroth@gmail.com> | 2020-06-19 23:46:23 (GMT) |
commit | 0470d6921b5a3fe8e92e356c8e11d120dbbb06c0 (patch) | |
tree | 276dcd224628536e1d8e9d29f8cd23a2c3f47268 | |
parent | 7013e59d5ae974006c088663559613bf23a66414 (diff) | |
download | patchelf-0470d6921b5a3fe8e92e356c8e11d120dbbb06c0.zip patchelf-0470d6921b5a3fe8e92e356c8e11d120dbbb06c0.tar.gz patchelf-0470d6921b5a3fe8e92e356c8e11d120dbbb06c0.tar.bz2 |
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.
-rw-r--r-- | configure.ac | 17 | ||||
-rw-r--r-- | 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<std::string> 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<std::vector<unsigned char>> FileContents; @@ -81,12 +85,6 @@ static bool hasAllowedPrefix(const std::string & s, const std::vector<std::strin } -static unsigned int getPageSize() -{ - return pageSize; -} - - template<ElfFileParams> 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<ElfFileParamNames>::ElfFile(FileContents fileContents) template<ElfFileParams> +unsigned int ElfFile<ElfFileParamNames>::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<ElfFileParams> void ElfFile<ElfFileParamNames>::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; |