summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre Bourdon <delroth@gmail.com>2020-06-19 23:46:23 (GMT)
committerPierre Bourdon <delroth@gmail.com>2020-06-19 23:46:23 (GMT)
commit0470d6921b5a3fe8e92e356c8e11d120dbbb06c0 (patch)
tree276dcd224628536e1d8e9d29f8cd23a2c3f47268
parent7013e59d5ae974006c088663559613bf23a66414 (diff)
downloadpatchelf-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.ac17
-rw-r--r--src/patchelf.cc43
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;