diff mbox series

[v4,07/18] linux-user: Load vdso image if available

Message ID 20230816180338.572576-8-richard.henderson@linaro.org
State Superseded
Headers show
Series linux-user: Implement VDSOs | expand

Commit Message

Richard Henderson Aug. 16, 2023, 6:03 p.m. UTC
The vdso image will be pre-processed into a C data array, with
a simple list of relocations to perform, and identifying the
location of signal trampolines.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/elfload.c | 87 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 78 insertions(+), 9 deletions(-)

Comments

Song Gao Aug. 18, 2023, 7:28 a.m. UTC | #1
Hi, Richard

在 2023/8/17 上午2:03, Richard Henderson 写道:
> @@ -3629,10 +3694,13 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
>       }
>   
>       /*
> -     * TODO: load a vdso, which would also contain the signal trampolines.
> -     * Otherwise, allocate a private page to hold them.
> +     * Load a vdso if available, which will amongst other things contain the
> +     * signal trampolines.  Otherwise, allocate a separate page for them.
>        */
> -    if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
> +    const VdsoImageInfo *vdso = vdso_image_info();
> +    if (vdso) {
> +        load_elf_vdso(&vdso_info, vdso);
> +    } else if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
I see some targets already support vdso.

./linux-user/aarch64/vdso-be.so
./linux-user/aarch64/vdso-le.so
./linux-user/arm/vdso-arm-be.so
./linux-user/arm/vdso-arm-le.so
./linux-user/arm/vdso-thm-be.so
./linux-user/arm/vdso-thm-le.so
./linux-user/hppa/vdso.so
./linux-user/i386/vdso.so
./linux-user/loongarch64/vdso.so
./linux-user/ppc/vdso-32.so
./linux-user/ppc/vdso-64.so
./linux-user/ppc/vdso-64le.so
./linux-user/riscv/vdso-32.so
./linux-user/riscv/vdso-64.so
./linux-user/s390x/vdso.so
./linux-user/x86_64/vdso.so

This branch will never reach.

what about remove TARGET_ARCH_HAS_SIGTRAMP_PAGE and setup_sigtramp() for 
these targets?

Thanks.
Song Gao
Richard Henderson Aug. 18, 2023, 3:38 p.m. UTC | #2
On 8/18/23 00:28, gaosong wrote:
> Hi, Richard
> 
> 在 2023/8/17 上午2:03, Richard Henderson 写道:
>> @@ -3629,10 +3694,13 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info 
>> *info)
>>       }
>>       /*
>> -     * TODO: load a vdso, which would also contain the signal trampolines.
>> -     * Otherwise, allocate a private page to hold them.
>> +     * Load a vdso if available, which will amongst other things contain the
>> +     * signal trampolines.  Otherwise, allocate a separate page for them.
>>        */
>> -    if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
>> +    const VdsoImageInfo *vdso = vdso_image_info();
>> +    if (vdso) {
>> +        load_elf_vdso(&vdso_info, vdso);
>> +    } else if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
> I see some targets already support vdso.
> 
> ./linux-user/aarch64/vdso-be.so
> ./linux-user/aarch64/vdso-le.so
> ./linux-user/arm/vdso-arm-be.so
> ./linux-user/arm/vdso-arm-le.so
> ./linux-user/arm/vdso-thm-be.so
> ./linux-user/arm/vdso-thm-le.so
> ./linux-user/hppa/vdso.so
> ./linux-user/i386/vdso.so
> ./linux-user/loongarch64/vdso.so
> ./linux-user/ppc/vdso-32.so
> ./linux-user/ppc/vdso-64.so
> ./linux-user/ppc/vdso-64le.so
> ./linux-user/riscv/vdso-32.so
> ./linux-user/riscv/vdso-64.so
> ./linux-user/s390x/vdso.so
> ./linux-user/x86_64/vdso.so
> 
> This branch will never reach.
> 
> what about remove TARGET_ARCH_HAS_SIGTRAMP_PAGE and setup_sigtramp() for these targets?

I can do that as a follow-up, yes.

r~
diff mbox series

Patch

diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 19d3cac039..f94963638a 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -33,6 +33,19 @@ 
 #undef ELF_ARCH
 #endif
 
+#ifndef TARGET_ARCH_HAS_SIGTRAMP_PAGE
+#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
+#endif
+
+typedef struct {
+    const uint8_t *image;
+    const uint32_t *relocs;
+    unsigned image_size;
+    unsigned reloc_count;
+    unsigned sigreturn_ofs;
+    unsigned rt_sigreturn_ofs;
+} VdsoImageInfo;
+
 #define ELF_OSABI   ELFOSABI_SYSV
 
 /* from personality.h */
@@ -2291,7 +2304,8 @@  static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong s
 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
                                    struct elfhdr *exec,
                                    struct image_info *info,
-                                   struct image_info *interp_info)
+                                   struct image_info *interp_info,
+                                   struct image_info *vdso_info)
 {
     abi_ulong sp;
     abi_ulong u_argc, u_argv, u_envp, u_auxv;
@@ -2379,10 +2393,15 @@  static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     }
 
     size = (DLINFO_ITEMS + 1) * 2;
-    if (k_base_platform)
+    if (k_base_platform) {
         size += 2;
-    if (k_platform)
+    }
+    if (k_platform) {
         size += 2;
+    }
+    if (vdso_info) {
+        size += 2;
+    }
 #ifdef DLINFO_ARCH_ITEMS
     size += DLINFO_ARCH_ITEMS * 2;
 #endif
@@ -2464,6 +2483,9 @@  static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
     if (u_platform) {
         NEW_AUX_ENT(AT_PLATFORM, u_platform);
     }
+    if (vdso_info) {
+        NEW_AUX_ENT(AT_SYSINFO_EHDR, vdso_info->load_addr);
+    }
     NEW_AUX_ENT (AT_NULL, 0);
 #undef NEW_AUX_ENT
 
@@ -3341,6 +3363,49 @@  static void load_elf_interp(const char *filename, struct image_info *info,
     load_elf_image(filename, &src, info, &ehdr, NULL);
 }
 
+#ifndef vdso_image_info
+#define vdso_image_info()    NULL
+#endif
+
+static void load_elf_vdso(struct image_info *info, const VdsoImageInfo *vdso)
+{
+    ImageSource src;
+    struct elfhdr ehdr;
+    abi_ulong load_bias, load_addr;
+
+    src.fd = -1;
+    src.cache = vdso->image;
+    src.cache_size = vdso->image_size;
+
+    load_elf_image("<internal-vdso>", &src, info, &ehdr, NULL);
+    load_addr = info->load_addr;
+    load_bias = info->load_bias;
+
+    /*
+     * We need to relocate the VDSO image.  The one built into the kernel
+     * is built for a fixed address.  The one built for QEMU is not, since
+     * that requires close control of the guest address space.
+     * We pre-processed the image to locate all of the addresses that need
+     * to be updated.
+     */
+    for (unsigned i = 0, n = vdso->reloc_count; i < n; i++) {
+        abi_ulong *addr = g2h_untagged(load_addr + vdso->relocs[i]);
+        *addr = tswapal(tswapal(*addr) + load_bias);
+    }
+
+    /* Install signal trampolines, if present. */
+    if (vdso->sigreturn_ofs) {
+        default_sigreturn = load_addr + vdso->sigreturn_ofs;
+    }
+    if (vdso->rt_sigreturn_ofs) {
+        default_rt_sigreturn = load_addr + vdso->rt_sigreturn_ofs;
+    }
+
+    /* Remove write from VDSO segment. */
+    target_mprotect(info->start_data, info->end_data - info->start_data,
+                    PROT_READ | PROT_EXEC);
+}
+
 static int symfind(const void *s0, const void *s1)
 {
     struct elf_sym *sym = (struct elf_sym *)s1;
@@ -3546,7 +3611,7 @@  int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
      * and let elf_load_image do any swapping that may be required.
      */
     struct elfhdr ehdr;
-    struct image_info interp_info;
+    struct image_info interp_info, vdso_info;
     char *elf_interpreter = NULL;
     char *scratch;
 
@@ -3629,10 +3694,13 @@  int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
     }
 
     /*
-     * TODO: load a vdso, which would also contain the signal trampolines.
-     * Otherwise, allocate a private page to hold them.
+     * Load a vdso if available, which will amongst other things contain the
+     * signal trampolines.  Otherwise, allocate a separate page for them.
      */
-    if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
+    const VdsoImageInfo *vdso = vdso_image_info();
+    if (vdso) {
+        load_elf_vdso(&vdso_info, vdso);
+    } else if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
         abi_long tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
                                           PROT_READ | PROT_WRITE,
                                           MAP_PRIVATE | MAP_ANON, -1, 0);
@@ -3644,8 +3712,9 @@  int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
         target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
     }
 
-    bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &ehdr,
-                                info, (elf_interpreter ? &interp_info : NULL));
+    bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &ehdr, info,
+                                elf_interpreter ? &interp_info : NULL,
+                                vdso ? &vdso_info : NULL);
     info->start_stack = bprm->p;
 
     /* If we have an interpreter, set that as the program's entry point.