summaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-06-27 17:49:58 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-06-29 10:25:26 +0100
commit82991bed738783d68c9950840b2e98d84b9f0621 (patch)
treed0d23e454fa4705eef7a89f032401ef821621f63 /linux-user
parent577caa2672ccde7352fda3ef17e44993de862f0e (diff)
linux-user: Put PPC AT_IGNOREPPC auxv entries in the right place
The 32-bit PPC auxv is a bit complicated because in the mists of time it used to be 16-aligned rather than directly after the environment. Older glibc versions had code to try to probe for whether it needed alignment or not: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/powerpc/dl-sysdep.c;hb=e84eabb3871c9b39e59323bf3f6b98c2ca9d1cd0 and the kernel has code which puts some magic entries at the bottom to ensure that the alignment probe fails: http://elixir.free-electrons.com/linux/latest/source/arch/powerpc/include/asm/elf.h#L158 QEMU has similar code too, but it was broken by commit 7c4ee5bcc82e64, which changed elfload.c from filling in the auxv starting at the highest address and working down to starting at the lowest address and working up. This means that the ARCH_DLINFO hook must now be invoked first rather than last, and the entries in it for PPC must be reversed so that the magic AT_IGNOREPPC entries come at the lowest address in the auxv as they should. The effect of this was that if running a guest binary that used an old glibc with the alignment probing the guest ld.so code would segfault if the size of the guest environment and argv happened to put the auxv at an address that triggered the alignment code in the guest glibc. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <rth@twiddle.net> Tested-by: Richard Henderson <rth@twiddle.net> Message-id: 1498582198-6649-1-git-send-email-peter.maydell@linaro.org
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/elfload.c23
1 files changed, 12 insertions, 11 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index ce77317e09..2a902f7806 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -802,14 +802,15 @@ static uint32_t get_elf_hwcap2(void)
#define ARCH_DLINFO \
do { \
PowerPCCPU *cpu = POWERPC_CPU(thread_cpu); \
- NEW_AUX_ENT(AT_DCACHEBSIZE, cpu->env.dcache_line_size); \
- NEW_AUX_ENT(AT_ICACHEBSIZE, cpu->env.icache_line_size); \
- NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \
/* \
- * Now handle glibc compatibility. \
+ * Handle glibc compatibility: these magic entries must \
+ * be at the lowest addresses in the final auxv. \
*/ \
NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
+ NEW_AUX_ENT(AT_DCACHEBSIZE, cpu->env.dcache_line_size); \
+ NEW_AUX_ENT(AT_ICACHEBSIZE, cpu->env.icache_line_size); \
+ NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \
} while (0)
static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
@@ -1760,6 +1761,13 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
} while(0)
/* There must be exactly DLINFO_ITEMS entries here. */
+#ifdef ARCH_DLINFO
+ /*
+ * ARCH_DLINFO must come first so platform specific code can enforce
+ * special alignment requirements on the AUXV if necessary (eg. PPC).
+ */
+ ARCH_DLINFO;
+#endif
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));
@@ -1782,13 +1790,6 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
if (u_platform) {
NEW_AUX_ENT(AT_PLATFORM, u_platform);
}
-#ifdef ARCH_DLINFO
- /*
- * ARCH_DLINFO must come last so platform specific code can enforce
- * special alignment requirements on the AUXV if necessary (eg. PPC).
- */
- ARCH_DLINFO;
-#endif
NEW_AUX_ENT (AT_NULL, 0);
#undef NEW_AUX_ENT