diff mbox series

[v3,21/23] tools: relocate-rela: Add support for elf32 decoding

Message ID 492b086f35e57e52a286eb19b130e92745b4202d.1655287429.git.michal.simek@amd.com
State Superseded
Delegated to: Michal Simek
Headers show
Series microblaze: Add support for full relocation | expand

Commit Message

Michal Simek June 15, 2022, 10:03 a.m. UTC
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>
---

(no changes since v1)

 tools/relocate-rela.c | 141 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 139 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c
index 2f7f1796a0ef..7c2a441a8e91 100644
--- a/tools/relocate-rela.c
+++ b/tools/relocate-rela.c
@@ -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) {