Skip to content

Commit

Permalink
Improve the default section alignment choice
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
delroth committed Jun 19, 2020
1 parent 7013e59 commit 0470d69
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 23 deletions.
17 changes: 5 additions & 12 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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])
)
Expand Down
43 changes: 32 additions & 11 deletions src/patchelf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -161,6 +159,8 @@ class ElfFile

friend struct CompShdr;

unsigned int getPageSize() const;

void sortShdrs();

void shiftFile(unsigned int extraPages, Elf_Addr startPage);
Expand Down Expand Up @@ -443,6 +443,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()
{
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 0470d69

Please sign in to comment.