elf loader now mostly supports 64b elfs
authorAndrew Waterman <waterman@s141.Millennium.Berkeley.EDU>
Wed, 1 Jun 2011 11:18:08 +0000 (04:18 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:03 +0000 (17:36 -0700)
kern/include/elf.h
kern/src/elf.c

index 5b6eada..6afb703 100644 (file)
@@ -12,9 +12,9 @@
 #  error I know not my endianness!
 #endif
 
-typedef struct Elf {
+typedef struct Elf32 {
        uint32_t e_magic;       // must equal ELF_MAGIC
-       uint8_t e_elf[12];
+       uint8_t e_ident[12];
        uint16_t e_type;
        uint16_t e_machine;
        uint32_t e_version;
@@ -28,9 +28,9 @@ typedef struct Elf {
        uint16_t e_shentsize;
        uint16_t e_shnum;
        uint16_t e_shstrndx;
-} elf_t;
+} elf32_t;
 
-typedef struct Proghdr {
+typedef struct Proghdr32 {
        uint32_t p_type;
        uint32_t p_offset;
        uint32_t p_va;
@@ -39,9 +39,9 @@ typedef struct Proghdr {
        uint32_t p_memsz;
        uint32_t p_flags;
        uint32_t p_align;
-} proghdr_t;
+} proghdr32_t;
 
-typedef struct Secthdr {
+typedef struct Secthdr32 {
        uint32_t sh_name;
        uint32_t sh_type;
        uint32_t sh_flags;
@@ -52,7 +52,49 @@ typedef struct Secthdr {
        uint32_t sh_info;
        uint32_t sh_addralign;
        uint32_t sh_entsize;
-} secthdr_t;
+} secthdr32_t;
+
+typedef struct Elf64 {
+       uint32_t e_magic;       // must equal ELF_MAGIC
+       uint8_t e_ident[12];
+       uint16_t e_type;
+       uint16_t e_machine;
+       uint32_t e_version;
+       uint64_t e_entry;
+       uint64_t e_phoff;
+       uint64_t e_shoff;
+       uint32_t e_flags;
+       uint16_t e_ehsize;
+       uint16_t e_phentsize;
+       uint16_t e_phnum;
+       uint16_t e_shentsize;
+       uint16_t e_shnum;
+       uint16_t e_shstrndx;
+} elf64_t;
+
+typedef struct Proghdr64 {
+       uint32_t p_type;
+       uint32_t p_flags;
+       uint64_t p_offset;
+       uint64_t p_va;
+       uint64_t p_pa;
+       uint64_t p_filesz;
+       uint64_t p_memsz;
+       uint64_t p_align;
+} proghdr64_t;
+
+typedef struct Secthdr64 {
+       uint32_t sh_name;
+       uint32_t sh_type;
+       uint64_t sh_flags;
+       uint64_t sh_addr;
+       uint64_t sh_offset;
+       uint64_t sh_size;
+       uint32_t sh_link;
+       uint32_t sh_info;
+       uint64_t sh_addralign;
+       uint64_t sh_entsize;
+} secthdr64_t;
 
 typedef struct
 {
@@ -61,11 +103,17 @@ typedef struct
        long phdr;
        int phnum;
        int dynamic;
+       bool elf64;
        char interp[256];
 } elf_info_t;
 
 typedef long elf_aux_t[2];
 
+#define ELF_IDENT_CLASS 0
+// Values for Elf::e_ident[ELF_IDENT_CLASS]
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+
 // Values for Proghdr::p_type
 #define ELF_PROG_LOAD          1
 #define ELF_PROG_INTERP                3
index 8a7d97e..0c56d94 100644 (file)
@@ -7,7 +7,13 @@
 #include <elf.h>
 #include <pmap.h>
 #include <smp.h>
+#include <arch/arch.h>
 
+#ifdef KERN64
+# define elf_field(obj, field) (elf64 ? (obj##64)->field : (obj##32)->field)
+#else
+# define elf_field(obj, field) ((obj##32)->field)
+#endif
 
 static int load_one_elf(struct proc *p, struct file *f, int pgoffset,
                         elf_info_t *ei)
@@ -30,40 +36,61 @@ static int load_one_elf(struct proc *p, struct file *f, int pgoffset,
                goto fail;
        current = cur_proc;
 
-       elf_t* elfhdr = (elf_t*)elf;
-       proghdr_t* proghdrs = (proghdr_t*)(elf + elfhdr->e_phoff);
-       if (elfhdr->e_phoff + elfhdr->e_phnum * sizeof(proghdr_t) > PGSIZE)
+       elf32_t* elfhdr32 = (elf32_t*)elf;
+       elf64_t* elfhdr64 = (elf64_t*)elf;
+       bool elf32 = elfhdr32->e_ident[ELF_IDENT_CLASS] == ELFCLASS32;
+       bool elf64 = elfhdr32->e_ident[ELF_IDENT_CLASS] == ELFCLASS64;
+       if (!elf64 && !elf32)
                goto fail;
-       if (elfhdr->e_phentsize != sizeof(proghdr_t))
+       #ifndef KERN64
+       if(elf64)
+               goto fail;
+       #endif
+       
+       proghdr32_t* proghdrs32 = (proghdr32_t*)(elf + elfhdr32->e_phoff);
+       proghdr64_t* proghdrs64 = (proghdr64_t*)(elf + elfhdr64->e_phoff);
+       uintptr_t e_phoff = elf_field(elfhdr, e_phoff);
+       size_t phsz = elf64 ? sizeof(proghdr64_t) : sizeof(proghdr32_t);
+       uint16_t e_phnum = elf_field(elfhdr, e_phnum);
+       // we don't support prog hdrs extending past the first elf page
+       if (e_phoff + e_phnum * phsz > PGSIZE)
                goto fail;
 
-       for (int i = 0; i < elfhdr->e_phnum; i++) {
-               proghdr_t* ph = proghdrs+i;
-               if (ph->p_type == ELF_PROG_PHDR)
-                       ei->phdr = ph->p_va;
-               if (ph->p_type == ELF_PROG_INTERP) {
-                       int maxlen = MIN(PGSIZE-ph->p_offset, sizeof(ei->interp));
-                       int len = strnlen(elf + ph->p_offset, maxlen);
+       for (int i = 0; i < e_phnum; i++) {
+               proghdr32_t* ph32 = proghdrs32+i;
+               proghdr64_t* ph64 = proghdrs64+i;
+               uint16_t p_type = elf_field(ph, p_type);
+               uintptr_t p_va = elf_field(ph, p_va);
+               uintptr_t p_offset = elf_field(ph, p_offset);
+               uintptr_t p_align = elf_field(ph, p_align);
+               uintptr_t p_memsz = elf_field(ph, p_memsz);
+               uintptr_t p_filesz = elf_field(ph, p_filesz);
+
+               if (p_type == ELF_PROG_PHDR)
+                       ei->phdr = elf_field(ph, p_va);
+               if (p_type == ELF_PROG_INTERP) {
+                       int maxlen = MIN(PGSIZE - p_offset, sizeof(ei->interp));
+                       int len = strnlen(elf + p_offset, maxlen);
                        if (len < maxlen) {
-                               memcpy(ei->interp, elf+ph->p_offset, maxlen + 1);
+                               memcpy(ei->interp, elf + p_offset, maxlen + 1);
                                ei->dynamic = 1;
                        }
                        else
                                goto fail;
                }
 
-               if (ph->p_type == ELF_PROG_LOAD && ph->p_memsz) {
-                       if (ph->p_align % PGSIZE)
+               if (p_type == ELF_PROG_LOAD && p_memsz) {
+                       if (p_align % PGSIZE)
                                goto fail;
-                       if (ph->p_offset % PGSIZE != ph->p_va % PGSIZE)
+                       if (p_offset % PGSIZE != p_va % PGSIZE)
                                goto fail;
 
-                       uintptr_t filestart = ROUNDDOWN(ph->p_offset, PGSIZE);
-                       uintptr_t fileend = ph->p_offset + ph->p_filesz;
+                       uintptr_t filestart = ROUNDDOWN(p_offset, PGSIZE);
+                       uintptr_t fileend = p_offset + p_filesz;
                        uintptr_t filesz = fileend - filestart;
 
-                       uintptr_t memstart = ROUNDDOWN(ph->p_va, PGSIZE);
-                       uintptr_t memend = ROUNDUP(ph->p_va + ph->p_memsz, PGSIZE);
+                       uintptr_t memstart = ROUNDDOWN(p_va, PGSIZE);
+                       uintptr_t memend = ROUNDUP(p_va + p_memsz, PGSIZE);
                        uintptr_t memsz = memend - memstart;
                        if (memend > ei->highest_addr)
                                ei->highest_addr = memend;
@@ -102,10 +129,11 @@ static int load_one_elf(struct proc *p, struct file *f, int pgoffset,
                                          0);
                if (phdr_addr == MAP_FAILED)
                        goto fail;
-               ei->phdr = (long)phdr_addr + elfhdr->e_phoff;
+               ei->phdr = (long)phdr_addr + e_phoff;
        }
-       ei->entry = elfhdr->e_entry + pgoffset*PGSIZE;
-       ei->phnum = elfhdr->e_phnum;
+       ei->entry = elf_field(elfhdr, e_entry) + pgoffset*PGSIZE;
+       ei->phnum = e_phnum;
+       ei->elf64 = elf64;
        ret = 0;
 fail:
        kfree(elf);
@@ -131,7 +159,7 @@ int load_elf(struct proc* p, struct file* f)
 
        // fill in auxiliary info for dynamic linker/runtime
        elf_aux_t auxp[] = {{ELF_AUX_PHDR, ei.phdr},
-                           {ELF_AUX_PHENT, sizeof(proghdr_t)},
+                           {ELF_AUX_PHENT, sizeof(proghdr32_t)},
                            {ELF_AUX_PHNUM, ei.phnum},
                            {ELF_AUX_ENTRY, ei.entry},
                            #ifdef __sparc_v8__