summary refs log tree commit diff stats
path: root/linux-user/elfload.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2024-11-16 18:16:46 +0000
committerPeter Maydell <peter.maydell@linaro.org>2024-11-16 18:16:46 +0000
commitabb1565d3d863cf210f18f70c4a42b0f39b8ccdb (patch)
tree7198bb5e6ae6a5dde3c665aa6612771a6140c28b /linux-user/elfload.c
parent43f2def68476697deb0d119cbae51b20019c6c86 (diff)
parent8377e3fb854d126ba10e61cb6b60885af8443ad4 (diff)
downloadfocaccia-qemu-abb1565d3d863cf210f18f70c4a42b0f39b8ccdb.tar.gz
focaccia-qemu-abb1565d3d863cf210f18f70c4a42b0f39b8ccdb.zip
Merge tag 'pull-tcg-20241116' of https://gitlab.com/rth7680/qemu into staging
cpu: ensure we don't call start_exclusive from cpu_exec
tcg: Allow top bit of SIMD_DATA_BITS to be set in simd_desc()
accel/tcg: Fix user-only probe_access_internal plugin check
linux-user: Fix setreuid and setregid to use direct syscalls
linux-user: Tolerate CONFIG_LSM_MMAP_MIN_ADDR
linux-user: Honor elf alignment when placing images
linux-user/*: Reduce vdso alignment to 4k
linux-user/arm: Select vdso for be8 and be32 modes

# -----BEGIN PGP SIGNATURE-----
#
# iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmc4z/8dHHJpY2hhcmQu
# aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/vWgf5Af8105enuWEdJ9c+
# KiyTsOWQEOKXTUSlSUxPs9FEeEr2l/mccvqUhiD7ptZq7P5/40+3tB18KXc5YuiE
# 45CZGRAr/tjALGT5LidSYzm6RgljWXYlvWVShqKlQpOD2L0GP5k8a7KEKsT3SLtS
# 9l+SVvjNOE+Jv23FWSOVYq0K0e5dPKzS1gtviCg+obA56dsiSKiEwwg+a5ca6oRe
# 9SUKoRnudpUv3fiYo8yZaHPW0ADhsITAB20ncN+cI9t4li9q5AWUbPZ+ADP113+2
# pWlco1VqR4pONK2UgbSmxDtjQf1GBi7E2MBFBjBMxTaiw/jXAZcZGIK4geZYKdHT
# NJj/0Q==
# =oKCm
# -----END PGP SIGNATURE-----
# gpg: Signature made Sat 16 Nov 2024 17:01:51 GMT
# gpg:                using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg:                issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full]
# Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A  05C0 64DF 38E8 AF7E 215F

* tag 'pull-tcg-20241116' of https://gitlab.com/rth7680/qemu:
  tcg: Allow top bit of SIMD_DATA_BITS to be set in simd_desc()
  linux-user/arm: Select vdso for be8 and be32 modes
  linux-user/ppc: Reduce vdso alignment to 4k
  linux-user/loongarch64: Reduce vdso alignment to 4k
  linux-user/arm: Reduce vdso alignment to 4k
  linux-user/aarch64: Reduce vdso alignment to 4k
  linux-user: Drop image_info.alignment
  linux-user: Honor elf alignment when placing images
  cpu: ensure we don't call start_exclusive from cpu_exec
  target/i386: fix hang when using slow path for ptw_setl
  tests/tcg: Test that sigreturn() does not corrupt the signal mask
  linux-user: Tolerate CONFIG_LSM_MMAP_MIN_ADDR
  accel/tcg: Fix user-only probe_access_internal plugin check
  target/arm: Drop user-only special case in sve_stN_r
  linux-user: Fix setreuid and setregid to use direct syscalls

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'linux-user/elfload.c')
-rw-r--r--linux-user/elfload.c71
1 files changed, 55 insertions, 16 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 6cef8db3b5..471a384b22 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -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;