tools: relocate-rela: Add support for elf32 decoding
authorMichal Simek <michal.simek@amd.com>
Fri, 24 Jun 2022 12:15:00 +0000 (14:15 +0200)
committerMichal Simek <michal.simek@amd.com>
Fri, 24 Jun 2022 12:15:00 +0000 (14:15 +0200)
Add support for 32bit ELF format which is used by Microblaze. Also check
that code runs only for Microblaze.

Function finds information about rela.dyn and dynsym which will be used
later for relocation.

Signed-off-by: Michal Simek <michal.simek@amd.com>
Link: https://lore.kernel.org/r/7491cc72fe04cbd48db014f1492ce463e91dfb42.1655299267.git.michal.simek@amd.com
tools/relocate-rela.c

index 2f7f179..7c2a441 100644 (file)
@@ -22,7 +22,7 @@
 
 static int ei_class;
 
-static uint64_t rela_start, rela_end, text_base;
+static uint64_t rela_start, rela_end, text_base, dyn_start;
 
 static const bool debug_en;
 
@@ -184,6 +184,142 @@ static int decode_elf64(FILE *felf, char **argv)
        return 0;
 }
 
+static int decode_elf32(FILE *felf, char **argv)
+{
+       size_t size;
+       Elf32_Ehdr header;
+       uint64_t section_header_base, section_header_size, sh_offset, sh_size;
+       Elf32_Shdr *sh_table; /* Elf symbol table */
+       int ret, i, machine;
+       char *sh_str;
+
+       debug("32bit version\n");
+
+       /* Make sure we are at start */
+       rewind(felf);
+
+       size = fread(&header, 1, sizeof(header), felf);
+       if (size != sizeof(header)) {
+               fclose(felf);
+               return 25;
+       }
+
+       machine = header.e_machine;
+       debug("Machine %d\n", machine);
+
+       if (machine != EM_MICROBLAZE) {
+               fprintf(stderr, "%s: Not supported machine type\n", argv[0]);
+               return 30;
+       }
+
+       text_base = header.e_entry;
+       section_header_base = header.e_shoff;
+
+       debug("Section header base %x\n", section_header_base);
+
+       section_header_size = header.e_shentsize * header.e_shnum;
+
+       debug("Section header size %d\n", section_header_size);
+
+       sh_table = malloc(section_header_size);
+       if (!sh_table) {
+               fprintf(stderr, "%s: Cannot allocate space for section header\n",
+                       argv[0]);
+               fclose(felf);
+               return 26;
+       }
+
+       ret = fseek(felf, section_header_base, SEEK_SET);
+       if (ret) {
+               fprintf(stderr, "%s: Can't set pointer to section header: %x/%lx\n",
+                       argv[0], ret, section_header_base);
+               free(sh_table);
+               fclose(felf);
+               return 26;
+       }
+
+       size = fread(sh_table, 1, section_header_size, felf);
+       if (size != section_header_size) {
+               fprintf(stderr, "%s: Can't read section header: %lx/%lx\n",
+                       argv[0], size, section_header_size);
+               free(sh_table);
+               fclose(felf);
+               return 27;
+       }
+
+       sh_size = sh_table[header.e_shstrndx].sh_size;
+       debug("e_shstrndx %x, sh_size %lx\n", header.e_shstrndx, sh_size);
+
+       sh_str = malloc(sh_size);
+       if (!sh_str) {
+               fprintf(stderr, "malloc failed\n");
+               free(sh_table);
+               fclose(felf);
+               return 28;
+       }
+
+       /*
+        * Specifies the byte offset from the beginning of the file
+        * to the first byte in the section.
+        */
+       sh_offset = sh_table[header.e_shstrndx].sh_offset;
+
+       debug("sh_offset %x\n", header.e_shnum);
+
+       ret = fseek(felf, sh_offset, SEEK_SET);
+       if (ret) {
+               fprintf(stderr, "Setting up sh_offset failed\n");
+               free(sh_str);
+               free(sh_table);
+               fclose(felf);
+               return 29;
+       }
+
+       size = fread(sh_str, 1, sh_size, felf);
+       if (size != sh_size) {
+               fprintf(stderr, "%s: Can't read section: %lx/%lx\n",
+                       argv[0], size, sh_size);
+               free(sh_str);
+               free(sh_table);
+               fclose(felf);
+               return 30;
+       }
+
+       for (i = 0; i < header.e_shnum; i++) {
+               debug("%s\n", sh_str + sh_table[i].sh_name);
+               if (!strcmp(".rela.dyn", (sh_str + sh_table[i].sh_name))) {
+                       debug("Found section\t\".rela_dyn\"\n");
+                       debug(" at addr\t0x%08x\n", (unsigned int)sh_table[i].sh_addr);
+                       debug(" at offset\t0x%08x\n", (unsigned int)sh_table[i].sh_offset);
+                       debug(" of size\t0x%08x\n", (unsigned int)sh_table[i].sh_size);
+                       rela_start = sh_table[i].sh_addr;
+                       rela_end = rela_start + sh_table[i].sh_size;
+               }
+               if (!strcmp(".dynsym", (sh_str + sh_table[i].sh_name))) {
+                       debug("Found section\t\".dynsym\"\n");
+                       debug(" at addr\t0x%08x\n", (unsigned int)sh_table[i].sh_addr);
+                       debug(" at offset\t0x%08x\n", (unsigned int)sh_table[i].sh_offset);
+                       debug(" of size\t0x%08x\n", (unsigned int)sh_table[i].sh_size);
+                       dyn_start = sh_table[i].sh_addr;
+               }
+       }
+
+       /* Clean up */
+       free(sh_str);
+       free(sh_table);
+       fclose(felf);
+
+       debug("text_base\t0x%08lx\n", text_base);
+       debug("rela_start\t0x%08lx\n", rela_start);
+       debug("rela_end\t0x%08lx\n", rela_end);
+       debug("dyn_start\t0x%08lx\n", dyn_start);
+
+       if (!rela_start)
+               return 1;
+
+       return 0;
+}
+
 static int decode_elf(char **argv)
 {
        FILE *felf;
@@ -218,7 +354,7 @@ static int decode_elf(char **argv)
        if (ei_class == 2)
                return decode_elf64(felf, argv);
 
-       return 1;
+       return decode_elf32(felf, argv);
 }
 
 static int rela_elf64(char **argv, FILE *f)
@@ -310,6 +446,7 @@ int main(int argc, char **argv)
 
        rela_start -= text_base;
        rela_end -= text_base;
+       dyn_start -= text_base;
 
        f = fopen(argv[1], "r+b");
        if (!f) {