aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Vivier <laurent@vivier.eu>2018-07-16 21:53:49 +0200
committerLaurent Vivier <laurent@vivier.eu>2018-07-22 21:32:50 +0200
commit33143c446eb88de28ea3088b279feda8f693e398 (patch)
tree5301441d6ca8958b24bd207ce71817cf8da6afe7
parent5b3ecd3d941a0ae8a8cfbba5ab8139b2bf104822 (diff)
linux-user: fix ELF load alignment error
When we try to use some targets on ppc64, it can happen the target doesn't support the host page size to align ELF load sections and fails with: ELF load command alignment not page-aligned Since commit a70daba3771 ("linux-user: Tell guest about big host page sizes") the host page size is used to align ELF sections, but this doesn't work if the alignment required by the load section is smaller than the host one. For these cases, we continue to use the TARGET_PAGE_SIZE instead of the host one. I have tested this change on ppc64, and it fixes qemu linux-user for: s390x, m68k, i386, arm, aarch64, hppa and I have tested it doesn't break the following targets: x86_64, mips64el, sh4 mips and mipsel abort, but I think for another reason. Signed-off-by: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> [lv: fixed "info->alignment = 0"] Message-Id: <20180716195349.29959-1-laurent@vivier.eu>
-rw-r--r--linux-user/elfload.c10
-rw-r--r--linux-user/qemu.h1
2 files changed, 10 insertions, 1 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 942a1b661f..df07055361 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1875,7 +1875,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
NEW_AUX_ENT(AT_PHDR, (abi_ulong)(info->load_addr + exec->e_phoff));
NEW_AUX_ENT(AT_PHENT, (abi_ulong)(sizeof (struct elf_phdr)));
NEW_AUX_ENT(AT_PHNUM, (abi_ulong)(exec->e_phnum));
- NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(MAX(TARGET_PAGE_SIZE, getpagesize())));
+ if ((info->alignment & ~qemu_host_page_mask) != 0) {
+ /* Target doesn't support host page size alignment */
+ NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(TARGET_PAGE_SIZE));
+ } else {
+ NEW_AUX_ENT(AT_PAGESZ, (abi_ulong)(MAX(TARGET_PAGE_SIZE,
+ qemu_host_page_size)));
+ }
NEW_AUX_ENT(AT_BASE, (abi_ulong)(interp_info ? interp_info->load_addr : 0));
NEW_AUX_ENT(AT_FLAGS, (abi_ulong)0);
NEW_AUX_ENT(AT_ENTRY, info->entry);
@@ -2202,6 +2208,7 @@ static void load_elf_image(const char *image_name, int image_fd,
/* Find the maximum size of the image and allocate an appropriate
amount of memory to handle that. */
loaddr = -1, hiaddr = 0;
+ info->alignment = 0;
for (i = 0; i < ehdr->e_phnum; ++i) {
if (phdr[i].p_type == PT_LOAD) {
abi_ulong a = phdr[i].p_vaddr - phdr[i].p_offset;
@@ -2213,6 +2220,7 @@ static void load_elf_image(const char *image_name, int image_fd,
hiaddr = a;
}
++info->nsegs;
+ info->alignment |= phdr[i].p_align;
}
}
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index bb85c81aa4..7b16a1cdea 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -51,6 +51,7 @@ struct image_info {
abi_ulong file_string;
uint32_t elf_flags;
int personality;
+ abi_ulong alignment;
/* The fields below are used in FDPIC mode. */
abi_ulong loadmap_addr;