[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2 1/2] elf-loader: Provide the possibility to r
From: |
Christian Borntraeger |
Subject: |
Re: [Qemu-devel] [PATCH v2 1/2] elf-loader: Provide the possibility to relocate s390 ELF files |
Date: |
Mon, 09 Mar 2015 12:11:49 +0100 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.5.0 |
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 <address@hidden>
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;
> }
>