On Mon, 09 Mar 2015 12:11:49 +0100 Christian Borntraeger <borntrae...@de.ibm.com> wrote:
> 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? Well, that was on the first version which still had endianess bugs ... Alex, does your Ack still stand for v2, too? Thomas > > --- > > 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; > > } > > >