From e3fe0dc89b1f7b04135647ed5a0fc9e5b5e1d683 Mon Sep 17 00:00:00 2001 From: John Reiser Date: Mon, 3 Oct 2016 09:41:05 -0700 Subject: [PATCH] Avoid bug in ld-linux to set brk(0) when .p_align is large. modified: p_lx_elf.cpp --- src/p_lx_elf.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 226c772b..f85548ba 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -2286,7 +2286,17 @@ PackLinuxElf64::generateElfHdr( // linux-2.6.14 binfmt_elf.c: SIGKILL if (0==.p_memsz) on a page boundary unsigned const brkb = brka | ((0==(~page_mask & brka)) ? 0x20 : 0); set_te32(&h2->phdr[1].p_type, PT_LOAD64); // be sure - set_te64(&h2->phdr[1].p_offset, ~page_mask & brkb); + + // Invoking by ld-linux-x86_64-2.21 complains if (filesize < .p_offset), + // which can happen with good compression of a stripped executable + // and large .p_align. However (0==.p_filesz) so ld-linux has a bug. + // Try to evade the bug by reducing .p_align. The alignment is forced + // anyway by phdr[0].p_align and constant offset from phdr[0].p_vaddr. + // However, somebody might complain because (.p_vaddr - .p_offset) + // is divisible only by phdr[1].p_align, and not by phdr[0].p_align. + set_te64(&h2->phdr[1].p_align, 0x1000); + set_te64(&h2->phdr[1].p_offset, /*~page_mask*/ 0xfff & brkb); + set_te64(&h2->phdr[1].p_vaddr, brkb); set_te64(&h2->phdr[1].p_paddr, brkb); h2->phdr[1].p_filesz = 0;