Am 09.03.2015 um 11:12 schrieb Thomas Huth: > On s390, we would like to load our "BIOS" s390-ccw.img to the end of the > RAM. Therefor we need the possibility to relocate the ELF file so that > it can also run from different addresses. This patch adds the necessary > code to the QEMU ELF loader function. > > Signed-off-by: Thomas Huth <th...@linux.vnet.ibm.com>
I think this was Acked by Alex? > --- > hw/core/loader.c | 2 + > include/elf.h | 2 + > include/hw/elf_ops.h | 78 > ++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 82 insertions(+), 0 deletions(-) > > diff --git a/hw/core/loader.c b/hw/core/loader.c > index e45dc0b..76d8aca 100644 > --- a/hw/core/loader.c > +++ b/hw/core/loader.c > @@ -297,6 +297,7 @@ static void *load_at(int fd, int offset, int size) > #undef elf_phdr > #undef elf_shdr > #undef elf_sym > +#undef elf_rela > #undef elf_note > #undef elf_word > #undef elf_sword > @@ -307,6 +308,7 @@ static void *load_at(int fd, int offset, int size) > #define elf_note elf64_note > #define elf_shdr elf64_shdr > #define elf_sym elf64_sym > +#define elf_rela elf64_rela > #define elf_word uint64_t > #define elf_sword int64_t > #define bswapSZs bswap64s > diff --git a/include/elf.h b/include/elf.h > index a516584..3e75f05 100644 > --- a/include/elf.h > +++ b/include/elf.h > @@ -1508,6 +1508,7 @@ struct elf32_fdpic_loadmap { > #define elf_shdr elf32_shdr > #define elf_sym elf32_sym > #define elf_addr_t Elf32_Off > +#define elf_rela elf32_rela > > #ifdef ELF_USES_RELOCA > # define ELF_RELOC Elf32_Rela > @@ -1523,6 +1524,7 @@ struct elf32_fdpic_loadmap { > #define elf_shdr elf64_shdr > #define elf_sym elf64_sym > #define elf_addr_t Elf64_Off > +#define elf_rela elf64_rela > > #ifdef ELF_USES_RELOCA > # define ELF_RELOC Elf64_Rela > diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h > index a517753..16a627b 100644 > --- a/include/hw/elf_ops.h > +++ b/include/hw/elf_ops.h > @@ -49,6 +49,13 @@ static void glue(bswap_sym, SZ)(struct elf_sym *sym) > bswap16s(&sym->st_shndx); > } > > +static void glue(bswap_rela, SZ)(struct elf_rela *rela) > +{ > + bswapSZs(&rela->r_offset); > + bswapSZs(&rela->r_info); > + bswapSZs((elf_word *)&rela->r_addend); > +} > + > static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table, > int n, int type) > { > @@ -182,6 +189,75 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, > int fd, int must_swab, > return -1; > } > > +static int glue(elf_reloc, SZ)(struct elfhdr *ehdr, int fd, int must_swab, > + uint64_t (*translate_fn)(void *, uint64_t), > + void *translate_opaque, uint8_t *data, > + struct elf_phdr *ph, int elf_machine) > +{ > + struct elf_shdr *reltab, *shdr_table = NULL; > + struct elf_rela *rels = NULL; > + int nrels, i, ret = -1; > + elf_word wordval; > + void *addr; > + > + shdr_table = load_at(fd, ehdr->e_shoff, > + sizeof(struct elf_shdr) * ehdr->e_shnum); > + if (!shdr_table) { > + return -1; > + } > + if (must_swab) { > + for (i = 0; i < ehdr->e_shnum; i++) { > + glue(bswap_shdr, SZ)(&shdr_table[i]); > + } > + } > + > + reltab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_RELA); > + if (!reltab) { > + goto fail; > + } > + rels = load_at(fd, reltab->sh_offset, reltab->sh_size); > + if (!rels) { > + goto fail; > + } > + nrels = reltab->sh_size / sizeof(struct elf_rela); > + > + for (i = 0; i < nrels; i++) { > + if (must_swab) { > + glue(bswap_rela, SZ)(&rels[i]); > + } > + if (rels[i].r_offset < ph->p_vaddr || > + rels[i].r_offset >= ph->p_vaddr + ph->p_filesz) { > + continue; > + } > + addr = &data[rels[i].r_offset - ph->p_vaddr]; > + switch (elf_machine) { > + case EM_S390: > + switch (rels[i].r_info) { > + case R_390_RELATIVE: > + wordval = *(elf_word *)addr; > + if (must_swab) { > + bswapSZs(&wordval); > + } > + wordval = translate_fn(translate_opaque, wordval); > + if (must_swab) { > + bswapSZs(&wordval); > + } > + *(elf_word *)addr = wordval; > + break; > + default: > + fprintf(stderr, "Unsupported relocation type %i!\n", > + (int)rels[i].r_info); > + } > + } > + } > + > + ret = 0; > +fail: > + g_free(rels); > + g_free(shdr_table); > + return ret; > +} > + > static int glue(load_elf, SZ)(const char *name, int fd, > uint64_t (*translate_fn)(void *, uint64_t), > void *translate_opaque, > @@ -271,6 +347,8 @@ static int glue(load_elf, SZ)(const char *name, int fd, > linked at the wrong physical address. */ > if (translate_fn) { > addr = translate_fn(translate_opaque, ph->p_paddr); > + glue(elf_reloc, SZ)(&ehdr, fd, must_swab, translate_fn, > + translate_opaque, data, ph, elf_machine); > } else { > addr = ph->p_paddr; > } >