|
@@ -659,6 +659,23 @@ static const char *get_elf_platform(void)
|
|
|
#undef END
|
|
|
}
|
|
|
|
|
|
+#if TARGET_BIG_ENDIAN
|
|
|
+#include "elf.h"
|
|
|
+#include "vdso-be8.c.inc"
|
|
|
+#include "vdso-be32.c.inc"
|
|
|
+
|
|
|
+static const VdsoImageInfo *vdso_image_info(uint32_t elf_flags)
|
|
|
+{
|
|
|
+ return (EF_ARM_EABI_VERSION(elf_flags) >= EF_ARM_EABI_VER4
|
|
|
+ && (elf_flags & EF_ARM_BE8)
|
|
|
+ ? &vdso_be8_image_info
|
|
|
+ : &vdso_be32_image_info);
|
|
|
+}
|
|
|
+#define vdso_image_info vdso_image_info
|
|
|
+#else
|
|
|
+# define VDSO_HEADER "vdso-le.c.inc"
|
|
|
+#endif
|
|
|
+
|
|
|
#else
|
|
|
/* 64 bit ARM definitions */
|
|
|
|
|
@@ -958,14 +975,14 @@ const char *elf_hwcap2_str(uint32_t bit)
|
|
|
|
|
|
#undef GET_FEATURE_ID
|
|
|
|
|
|
-#endif /* not TARGET_AARCH64 */
|
|
|
-
|
|
|
#if TARGET_BIG_ENDIAN
|
|
|
# define VDSO_HEADER "vdso-be.c.inc"
|
|
|
#else
|
|
|
# define VDSO_HEADER "vdso-le.c.inc"
|
|
|
#endif
|
|
|
|
|
|
+#endif /* not TARGET_AARCH64 */
|
|
|
+
|
|
|
#endif /* TARGET_ARM */
|
|
|
|
|
|
#ifdef TARGET_SPARC
|
|
@@ -2898,7 +2915,7 @@ static uintptr_t pgb_try_itree(const PGBAddrs *ga, uintptr_t base,
|
|
|
static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root,
|
|
|
uintptr_t align, uintptr_t brk)
|
|
|
{
|
|
|
- uintptr_t last = mmap_min_addr;
|
|
|
+ uintptr_t last = sizeof(uintptr_t) == 4 ? MiB : GiB;
|
|
|
uintptr_t base, skip;
|
|
|
|
|
|
while (true) {
|
|
@@ -3179,7 +3196,8 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
|
|
|
char **pinterp_name)
|
|
|
{
|
|
|
g_autofree struct elf_phdr *phdr = NULL;
|
|
|
- abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
|
|
|
+ abi_ulong load_addr, load_bias, loaddr, hiaddr, error, align;
|
|
|
+ size_t reserve_size, align_size;
|
|
|
int i, prot_exec;
|
|
|
Error *err = NULL;
|
|
|
|
|
@@ -3219,7 +3237,7 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
|
|
|
* amount of memory to handle that. Locate the interpreter, if any.
|
|
|
*/
|
|
|
loaddr = -1, hiaddr = 0;
|
|
|
- info->alignment = 0;
|
|
|
+ align = 0;
|
|
|
info->exec_stack = EXSTACK_DEFAULT;
|
|
|
for (i = 0; i < ehdr->e_phnum; ++i) {
|
|
|
struct elf_phdr *eppnt = phdr + i;
|
|
@@ -3233,7 +3251,7 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
|
|
|
hiaddr = a;
|
|
|
}
|
|
|
++info->nsegs;
|
|
|
- info->alignment |= eppnt->p_align;
|
|
|
+ align |= eppnt->p_align;
|
|
|
} else if (eppnt->p_type == PT_INTERP && pinterp_name) {
|
|
|
g_autofree char *interp_name = NULL;
|
|
|
|
|
@@ -3263,6 +3281,8 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
|
|
|
|
|
|
load_addr = loaddr;
|
|
|
|
|
|
+ align = pow2ceil(align);
|
|
|
+
|
|
|
if (pinterp_name != NULL) {
|
|
|
if (ehdr->e_type == ET_EXEC) {
|
|
|
/*
|
|
@@ -3271,8 +3291,6 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
|
|
|
*/
|
|
|
probe_guest_base(image_name, loaddr, hiaddr);
|
|
|
} else {
|
|
|
- abi_ulong align;
|
|
|
-
|
|
|
/*
|
|
|
* The binary is dynamic, but we still need to
|
|
|
* select guest_base. In this case we pass a size.
|
|
@@ -3290,10 +3308,7 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
|
|
|
* Since we do not have complete control over the guest
|
|
|
* address space, we prefer the kernel to choose some address
|
|
|
* rather than force the use of LOAD_ADDR via MAP_FIXED.
|
|
|
- * But without MAP_FIXED we cannot guarantee alignment,
|
|
|
- * only suggest it.
|
|
|
*/
|
|
|
- align = pow2ceil(info->alignment);
|
|
|
if (align) {
|
|
|
load_addr &= -align;
|
|
|
}
|
|
@@ -3317,13 +3332,35 @@ static void load_elf_image(const char *image_name, const ImageSource *src,
|
|
|
* In both cases, we will overwrite pages in this range with mappings
|
|
|
* from the executable.
|
|
|
*/
|
|
|
- load_addr = target_mmap(load_addr, (size_t)hiaddr - loaddr + 1, PROT_NONE,
|
|
|
+ reserve_size = (size_t)hiaddr - loaddr + 1;
|
|
|
+ align_size = reserve_size;
|
|
|
+
|
|
|
+ if (ehdr->e_type != ET_EXEC && align > qemu_real_host_page_size()) {
|
|
|
+ align_size += align - 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ load_addr = target_mmap(load_addr, align_size, PROT_NONE,
|
|
|
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE |
|
|
|
(ehdr->e_type == ET_EXEC ? MAP_FIXED_NOREPLACE : 0),
|
|
|
-1, 0);
|
|
|
if (load_addr == -1) {
|
|
|
goto exit_mmap;
|
|
|
}
|
|
|
+
|
|
|
+ if (align_size != reserve_size) {
|
|
|
+ abi_ulong align_addr = ROUND_UP(load_addr, align);
|
|
|
+ abi_ulong align_end = align_addr + reserve_size;
|
|
|
+ abi_ulong load_end = load_addr + align_size;
|
|
|
+
|
|
|
+ if (align_addr != load_addr) {
|
|
|
+ target_munmap(load_addr, align_addr - load_addr);
|
|
|
+ }
|
|
|
+ if (align_end != load_end) {
|
|
|
+ target_munmap(align_end, load_end - align_end);
|
|
|
+ }
|
|
|
+ load_addr = align_addr;
|
|
|
+ }
|
|
|
+
|
|
|
load_bias = load_addr - loaddr;
|
|
|
|
|
|
if (elf_is_fdpic(ehdr)) {
|
|
@@ -3504,12 +3541,14 @@ static void load_elf_interp(const char *filename, struct image_info *info,
|
|
|
load_elf_image(filename, &src, info, &ehdr, NULL);
|
|
|
}
|
|
|
|
|
|
+#ifndef vdso_image_info
|
|
|
#ifdef VDSO_HEADER
|
|
|
#include VDSO_HEADER
|
|
|
-#define vdso_image_info() &vdso_image_info
|
|
|
+#define vdso_image_info(flags) &vdso_image_info
|
|
|
#else
|
|
|
-#define vdso_image_info() NULL
|
|
|
-#endif
|
|
|
+#define vdso_image_info(flags) NULL
|
|
|
+#endif /* VDSO_HEADER */
|
|
|
+#endif /* vdso_image_info */
|
|
|
|
|
|
static void load_elf_vdso(struct image_info *info, const VdsoImageInfo *vdso)
|
|
|
{
|
|
@@ -3840,7 +3879,7 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
|
|
|
* Load a vdso if available, which will amongst other things contain the
|
|
|
* signal trampolines. Otherwise, allocate a separate page for them.
|
|
|
*/
|
|
|
- const VdsoImageInfo *vdso = vdso_image_info();
|
|
|
+ const VdsoImageInfo *vdso = vdso_image_info(info->elf_flags);
|
|
|
if (vdso) {
|
|
|
load_elf_vdso(&vdso_info, vdso);
|
|
|
info->vdso = vdso_info.load_bias;
|