qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC/PATCH] elfload: add FDPIC support


From: Mike Frysinger
Subject: [Qemu-devel] [RFC/PATCH] elfload: add FDPIC support
Date: Sun, 9 Jan 2011 03:48:58 -0500

This is a PoC at this point, but it seems to be working for me.  At
least, all the current crashes I'm seeing are due to my Blackfin port
being incomplete.  All of the FDPIC table parsing seems to be OK ...

If someone with a more functional target would like to try this, that'd
be cool.  Or if people want to give feedback on how to approach this
problem so I can adjust the details now.

Signed-off-by: Mike Frysinger <address@hidden>
---
 elf.h                |   19 ++++++++++++++
 linux-user/elfload.c |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++
 linux-user/qemu.h    |    8 ++++++
 3 files changed, 94 insertions(+), 0 deletions(-)

diff --git a/elf.h b/elf.h
index 7067c90..d2f24f4 100644
--- a/elf.h
+++ b/elf.h
@@ -1191,6 +1191,25 @@ typedef struct elf64_note {
   Elf64_Word n_type;   /* Content type */
 } Elf64_Nhdr;
 
+
+/* This data structure represents a PT_LOAD segment.  */
+struct elf32_fdpic_loadseg {
+  /* Core address to which the segment is mapped.  */
+  Elf32_Addr addr;
+  /* VMA recorded in the program header.  */
+  Elf32_Addr p_vaddr;
+  /* Size of this segment in memory.  */
+  Elf32_Word p_memsz;
+};
+struct elf32_fdpic_loadmap {
+  /* Protocol version number, must be zero.  */
+  Elf32_Half version;
+  /* Number of segments in this map.  */
+  Elf32_Half nsegs;
+  /* The actual memory map.  */
+  struct elf32_fdpic_loadseg segs[/*nsegs*/];
+};
+
 #ifdef ELF_CLASS
 #if ELF_CLASS == ELFCLASS32
 
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 33d776d..8100ffd 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1075,6 +1075,32 @@ static void zero_bss(abi_ulong elf_bss, abi_ulong 
last_bss, int prot)
     }
 }
 
+#ifdef CONFIG_USE_FDPIC
+static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong 
sp)
+{
+    uint16_t n;
+    struct elf32_fdpic_loadseg *loadsegs = info->loadsegs;
+
+    /* elf32_fdpic_loadseg */
+    for (n = 0; n < info->nsegs; ++n) {
+        sp -= 12;
+        put_user_u32(loadsegs[n].addr, sp+0);
+        put_user_u32(loadsegs[n].p_vaddr, sp+4);
+        put_user_u32(loadsegs[n].p_memsz, sp+8);
+    }
+
+    /* elf32_fdpic_loadmap */
+    sp -= 4;
+    put_user_u16(0, sp+0); /* version */
+    put_user_u16(info->nsegs, sp+2); /* nsegs */
+
+    info->personality = PER_LINUX_FDPIC;
+    info->loadmap_addr = sp;
+
+    return sp;
+}
+#endif
+
 static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
                                    struct elfhdr *exec,
                                    struct image_info *info,
@@ -1087,6 +1113,21 @@ static abi_ulong create_elf_tables(abi_ulong p, int 
argc, int envc,
     const int n = sizeof(elf_addr_t);
 
     sp = p;
+
+#ifdef CONFIG_USE_FDPIC
+    /* Needs to be before we load the env/argc/... */
+    if (elf_is_fdpic(exec)) {
+        /* Need 4 byte alignment for these structs */
+        sp &= ~3;
+        sp = loader_build_fdpic_loadmap(info, sp);
+        info->other_info = interp_info;
+        if (interp_info) {
+            interp_info->other_info = info;
+            sp = loader_build_fdpic_loadmap(interp_info, sp);
+        }
+    }
+#endif
+
     u_platform = 0;
     k_platform = ELF_PLATFORM;
     if (k_platform) {
@@ -1197,6 +1238,11 @@ static void load_elf_image(const char *image_name, int 
image_fd,
     }
     bswap_phdr(phdr, ehdr->e_phnum);
 
+#ifdef CONFIG_USE_FDPIC
+    info->nsegs = 0;
+    info->pt_dynamic_addr = 0;
+#endif
+
     /* Find the maximum size of the image and allocate an appropriate
        amount of memory to handle that.  */
     loaddr = -1, hiaddr = 0;
@@ -1210,6 +1256,11 @@ static void load_elf_image(const char *image_name, int 
image_fd,
             if (a > hiaddr) {
                 hiaddr = a;
             }
+#ifdef CONFIG_USE_FDPIC
+            ++info->nsegs;
+        } else if (phdr[i].p_type == PT_DYNAMIC) {
+            info->pt_dynamic_addr = phdr[i].p_vaddr;
+#endif
         }
     }
 
@@ -1290,6 +1341,22 @@ static void load_elf_image(const char *image_name, int 
image_fd,
     }
     load_bias = load_addr - loaddr;
 
+#ifdef CONFIG_USE_FDPIC
+    {
+        struct elf32_fdpic_loadseg *loadsegs = info->loadsegs =
+            qemu_malloc(sizeof(*loadsegs) * info->nsegs);
+
+        for (i = 0; i < ehdr->e_phnum; ++i) {
+            if (phdr[i].p_type != PT_LOAD)
+                continue;
+            loadsegs->addr = phdr[i].p_vaddr + load_bias;
+            loadsegs->p_vaddr = phdr[i].p_vaddr;
+            loadsegs->p_memsz = phdr[i].p_memsz;
+                       ++loadsegs;
+        }
+    }
+#endif
+
     info->load_bias = load_bias;
     info->load_addr = load_addr;
     info->entry = ehdr->e_entry + load_bias;
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 32de241..0924a1a 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -51,6 +51,14 @@ struct image_info {
         abi_ulong       arg_start;
         abi_ulong       arg_end;
        int             personality;
+#ifdef CONFIG_USE_FDPIC
+#define FDPIC_MAX_LOAD_SEGS 4
+        abi_ulong       loadmap_addr;
+        uint16_t        nsegs;
+        void           *loadsegs;
+        abi_ulong       pt_dynamic_addr;
+        struct image_info *other_info;
+#endif
 };
 
 #ifdef TARGET_I386
-- 
1.7.4.rc1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]