File 0194-elf-loader-Provide-the-possibility-.patch of Package qemu.6354

From f806f6ba377a54d7128096a936e6fd90620635a2 Mon Sep 17 00:00:00 2001
From: Thomas Huth <thuth@linux.vnet.ibm.com>
Date: Mon, 9 Mar 2015 11:12:52 +0100
Subject: [PATCH] elf-loader: Provide the possibility to relocate s390 ELF
 files
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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 <thuth@linux.vnet.ibm.com>
Message-Id: <1425895973-15239-2-git-send-email-thuth@linux.vnet.ibm.com>
Acked-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
(cherry picked from commit 5dce07e1cb67aab265b16e39b0b9d812199a4d22)
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 hw/core/loader.c     |  2 ++
 include/elf.h        |  2 ++
 include/hw/elf_ops.h | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+)

diff --git a/hw/core/loader.c b/hw/core/loader.c
index 2bf6b8ff85..a3fc5f629d 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -269,6 +269,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
@@ -279,6 +280,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 667af6fc63..fcd85c12de 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -1479,6 +1479,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
@@ -1494,6 +1495,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 c6b5129bab..0e3972e0d7 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)
 {
@@ -187,6 +194,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,
@@ -276,6 +352,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;
             }
openSUSE Build Service is sponsored by