[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC v3 16/27] x86/relocs: Handle PIE relocations



Change the relocation tool to correctly handle relocations generated by
-fPIE option:

 - Add relocation for each entry of the .got section given the linker does not
   generate R_X86_64_GLOB_DAT on a simple link.
 - Ignore R_X86_64_GOTPCREL and R_X86_64_PLT32.

Signed-off-by: Thomas Garnier <thgarnie@xxxxxxxxxx>
---
 arch/x86/tools/relocs.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 93 insertions(+), 1 deletion(-)

diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index 73eb7fd4aec4..5d3eb2760198 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -31,6 +31,7 @@ struct section {
        Elf_Sym        *symtab;
        Elf_Rel        *reltab;
        char           *strtab;
+       Elf_Addr       *got;
 };
 static struct section *secs;
 
@@ -292,6 +293,35 @@ static Elf_Sym *sym_lookup(const char *symname)
        return 0;
 }
 
+static Elf_Sym *sym_lookup_addr(Elf_Addr addr, const char **name)
+{
+       int i;
+       for (i = 0; i < ehdr.e_shnum; i++) {
+               struct section *sec = &secs[i];
+               long nsyms;
+               Elf_Sym *symtab;
+               Elf_Sym *sym;
+
+               if (sec->shdr.sh_type != SHT_SYMTAB)
+                       continue;
+
+               nsyms = sec->shdr.sh_size/sizeof(Elf_Sym);
+               symtab = sec->symtab;
+
+               for (sym = symtab; --nsyms >= 0; sym++) {
+                       if (sym->st_value == addr) {
+                               if (name) {
+                                       *name = sym_name(sec->link->strtab,
+                                                        sym);
+                               }
+                               return sym;
+                       }
+               }
+       }
+       return 0;
+}
+
+
 #if BYTE_ORDER == LITTLE_ENDIAN
 #define le16_to_cpu(val) (val)
 #define le32_to_cpu(val) (val)
@@ -512,6 +542,33 @@ static void read_relocs(FILE *fp)
        }
 }
 
+static void read_got(FILE *fp)
+{
+       int i;
+       for (i = 0; i < ehdr.e_shnum; i++) {
+               struct section *sec = &secs[i];
+               sec->got = NULL;
+               if (sec->shdr.sh_type != SHT_PROGBITS ||
+                   strcmp(sec_name(i), ".got")) {
+                       continue;
+               }
+               sec->got = malloc(sec->shdr.sh_size);
+               if (!sec->got) {
+                       die("malloc of %d bytes for got failed\n",
+                               sec->shdr.sh_size);
+               }
+               if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+                       die("Seek to %d failed: %s\n",
+                               sec->shdr.sh_offset, strerror(errno));
+               }
+               if (fread(sec->got, 1, sec->shdr.sh_size, fp)
+                   != sec->shdr.sh_size) {
+                       die("Cannot read got: %s\n",
+                               strerror(errno));
+               }
+       }
+}
+
 
 static void print_absolute_symbols(void)
 {
@@ -642,6 +699,32 @@ static void add_reloc(struct relocs *r, uint32_t offset)
        r->offset[r->count++] = offset;
 }
 
+/*
+ * The linker does not generate relocations for the GOT for the kernel.
+ * If a GOT is found, simulate the relocations that should have been included.
+ */
+static void walk_got_table(int (*process)(struct section *sec, Elf_Rel *rel,
+                                         Elf_Sym *sym, const char *symname),
+                          struct section *sec)
+{
+       int i;
+       Elf_Addr entry;
+       Elf_Sym *sym;
+       const char *symname;
+       Elf_Rel rel;
+
+       for (i = 0; i < sec->shdr.sh_size/sizeof(Elf_Addr); i++) {
+               entry = sec->got[i];
+               sym = sym_lookup_addr(entry, &symname);
+               if (!sym)
+                       die("Could not found got symbol for entry %d\n", i);
+               rel.r_offset = sec->shdr.sh_addr + i * sizeof(Elf_Addr);
+               rel.r_info = ELF_BITS == 64 ? R_X86_64_GLOB_DAT
+                            : R_386_GLOB_DAT;
+               process(sec, &rel, sym, symname);
+       }
+}
+
 static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel,
                        Elf_Sym *sym, const char *symname))
 {
@@ -655,6 +738,8 @@ static void walk_relocs(int (*process)(struct section *sec, 
Elf_Rel *rel,
                struct section *sec = &secs[i];
 
                if (sec->shdr.sh_type != SHT_REL_TYPE) {
+                       if (sec->got)
+                               walk_got_table(process, sec);
                        continue;
                }
                sec_symtab  = sec->link;
@@ -764,6 +849,8 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, 
ElfW(Sym) *sym,
                offset += per_cpu_load_addr;
 
        switch (r_type) {
+       case R_X86_64_PLT32:
+       case R_X86_64_GOTPCREL:
        case R_X86_64_NONE:
                /* NONE can be ignored. */
                break;
@@ -805,7 +892,7 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, 
ElfW(Sym) *sym,
                 * the relocations are processed.
                 * Make sure that the offset will fit.
                 */
-               if ((int32_t)offset != (int64_t)offset)
+               if (r_type != R_X86_64_64 && (int32_t)offset != (int64_t)offset)
                        die("Relocation offset doesn't fit in 32 bits\n");
 
                if (r_type == R_X86_64_64)
@@ -814,6 +901,10 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, 
ElfW(Sym) *sym,
                        add_reloc(&relocs32, offset);
                break;
 
+       case R_X86_64_GLOB_DAT:
+               add_reloc(&relocs64, offset);
+               break;
+
        default:
                die("Unsupported relocation type: %s (%d)\n",
                    rel_type(r_type), r_type);
@@ -1083,6 +1174,7 @@ void process(FILE *fp, int use_real_mode, int as_text,
        read_strtabs(fp);
        read_symtabs(fp);
        read_relocs(fp);
+       read_got(fp);
        if (ELF_BITS == 64)
                percpu_init();
        if (show_absolute_syms) {
-- 
2.14.2.920.gcf0c67979c-goog


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.