]> Git Repo - qemu.git/blobdiff - hw/elf_ops.h
virtio-blk-s390: switch to the new API.
[qemu.git] / hw / elf_ops.h
index 27d1ab9bc21a5543ff64cc436fa1228d2088ee20..acc701e3a4e36f7c278d8ddd376e560fbbe7369b 100644 (file)
@@ -62,27 +62,25 @@ static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
 
 static int glue(symfind, SZ)(const void *s0, const void *s1)
 {
-    struct elf_sym *key = (struct elf_sym *)s0;
+    hwaddr addr = *(hwaddr *)s0;
     struct elf_sym *sym = (struct elf_sym *)s1;
     int result = 0;
-    if (key->st_value < sym->st_value) {
+    if (addr < sym->st_value) {
         result = -1;
-    } else if (key->st_value >= sym->st_value + sym->st_size) {
+    } else if (addr >= sym->st_value + sym->st_size) {
         result = 1;
     }
     return result;
 }
 
 static const char *glue(lookup_symbol, SZ)(struct syminfo *s,
-                                           target_phys_addr_t orig_addr)
+                                           hwaddr orig_addr)
 {
     struct elf_sym *syms = glue(s->disas_symtab.elf, SZ);
-    struct elf_sym key;
     struct elf_sym *sym;
 
-    key.st_value = orig_addr;
-
-    sym = bsearch(&key, syms, s->disas_num_syms, sizeof(*syms), glue(symfind, SZ));
+    sym = bsearch(&orig_addr, syms, s->disas_num_syms, sizeof(*syms),
+                  glue(symfind, SZ));
     if (sym != NULL) {
         return s->disas_strtab + sym->st_name;
     }
@@ -150,11 +148,16 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
         i++;
     }
     if (nsyms) {
-        syms = qemu_realloc(syms, nsyms * sizeof(*syms));
+        syms = g_realloc(syms, nsyms * sizeof(*syms));
 
         qsort(syms, nsyms, sizeof(*syms), glue(symcmp, SZ));
+        for (i = 0; i < nsyms - 1; i++) {
+            if (syms[i].st_size == 0) {
+                syms[i].st_size = syms[i + 1].st_value - syms[i].st_value;
+            }
+        }
     } else {
-        qemu_free(syms);
+        g_free(syms);
         syms = NULL;
     }
 
@@ -168,19 +171,19 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
         goto fail;
 
     /* Commit */
-    s = qemu_mallocz(sizeof(*s));
+    s = g_malloc0(sizeof(*s));
     s->lookup_symbol = glue(lookup_symbol, SZ);
     glue(s->disas_symtab.elf, SZ) = syms;
     s->disas_num_syms = nsyms;
     s->disas_strtab = str;
     s->next = syminfos;
     syminfos = s;
-    qemu_free(shdr_table);
+    g_free(shdr_table);
     return 0;
  fail:
-    qemu_free(syms);
-    qemu_free(str);
-    qemu_free(shdr_table);
+    g_free(syms);
+    g_free(str);
+    g_free(shdr_table);
     return -1;
 }
 
@@ -194,7 +197,7 @@ static int glue(load_elf, SZ)(const char *name, int fd,
     struct elfhdr ehdr;
     struct elf_phdr *phdr = NULL, *ph;
     int size, i, total_size;
-    elf_word mem_size;
+    elf_word mem_size, file_size;
     uint64_t addr, low = (uint64_t)-1, high = 0;
     uint8_t *data = NULL;
     char label[128];
@@ -233,7 +236,7 @@ static int glue(load_elf, SZ)(const char *name, int fd,
 
     size = ehdr.e_phnum * sizeof(phdr[0]);
     lseek(fd, ehdr.e_phoff, SEEK_SET);
-    phdr = qemu_mallocz(size);
+    phdr = g_malloc0(size);
     if (!phdr)
         goto fail;
     if (read(fd, phdr, size) != size)
@@ -249,14 +252,16 @@ static int glue(load_elf, SZ)(const char *name, int fd,
     for(i = 0; i < ehdr.e_phnum; i++) {
         ph = &phdr[i];
         if (ph->p_type == PT_LOAD) {
-            mem_size = ph->p_memsz;
-            /* XXX: avoid allocating */
-            data = qemu_mallocz(mem_size);
+            mem_size = ph->p_memsz; /* Size of the ROM */
+            file_size = ph->p_filesz; /* Size of the allocated data */
+            data = g_malloc0(file_size);
             if (ph->p_filesz > 0) {
-                if (lseek(fd, ph->p_offset, SEEK_SET) < 0)
+                if (lseek(fd, ph->p_offset, SEEK_SET) < 0) {
                     goto fail;
-                if (read(fd, data, ph->p_filesz) != ph->p_filesz)
+                }
+                if (read(fd, data, file_size) != file_size) {
                     goto fail;
+                }
             }
             /* address_offset is hack for kernel images that are
                linked at the wrong physical address.  */
@@ -266,8 +271,21 @@ static int glue(load_elf, SZ)(const char *name, int fd,
                 addr = ph->p_paddr;
             }
 
+            /* the entry pointer in the ELF header is a virtual
+             * address, if the text segments paddr and vaddr differ
+             * we need to adjust the entry */
+            if (pentry && !translate_fn &&
+                    ph->p_vaddr != ph->p_paddr &&
+                    ehdr.e_entry >= ph->p_vaddr &&
+                    ehdr.e_entry < ph->p_vaddr + ph->p_filesz &&
+                    ph->p_flags & PF_X) {
+                *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr;
+            }
+
             snprintf(label, sizeof(label), "phdr #%d: %s", i, name);
-            rom_add_blob_fixed(label, data, mem_size, addr);
+
+            /* rom_add_elf_program() seize the ownership of 'data' */
+            rom_add_elf_program(label, data, file_size, mem_size, addr);
 
             total_size += mem_size;
             if (addr < low)
@@ -275,18 +293,17 @@ static int glue(load_elf, SZ)(const char *name, int fd,
             if ((addr + mem_size) > high)
                 high = addr + mem_size;
 
-            qemu_free(data);
             data = NULL;
         }
     }
-    qemu_free(phdr);
+    g_free(phdr);
     if (lowaddr)
         *lowaddr = (uint64_t)(elf_sword)low;
     if (highaddr)
         *highaddr = (uint64_t)(elf_sword)high;
     return total_size;
  fail:
-    qemu_free(data);
-    qemu_free(phdr);
+    g_free(data);
+    g_free(phdr);
     return -1;
 }
This page took 0.030368 seconds and 4 git commands to generate.