diff options
-rw-r--r-- | elf.c | 84 |
1 files changed, 79 insertions, 5 deletions
@@ -9,6 +9,7 @@ */ #include <stdio.h> +#include <stdbool.h> #include <stdint.h> #include <libelf.h> #include <gelf.h> @@ -23,11 +24,34 @@ * http://elftoolchain.sourceforge.net/for-review/libelf-by-example-20100112.pdf */ +static bool elf_is_text_section(GElf_Shdr *shdr) +{ + if (shdr->sh_type == SHT_PROGBITS + && (shdr->sh_flags & ~SHF_WRITE) == (SHF_ALLOC | SHF_EXECINSTR)) + return true; + return false; +} + +static bool elf_is_data_section(GElf_Shdr *shdr) +{ + if (shdr->sh_type == SHT_PROGBITS + && (shdr->sh_flags & ~SHF_WRITE) == SHF_ALLOC) + return true; + + if (shdr->sh_type == SHT_NOBITS + && (shdr->sh_flags == (SHF_ALLOC | SHF_WRITE))) + return true; + + return false; +} + static int elf_read_sections(Elf *e, struct memory *mem) { Elf_Scn *scn = NULL; size_t shstrndx; char *name; + bool found_text = false; + bool found_data = false; if (elf_getshdrstrndx(e, &shstrndx) != 0) { err("elf_getshdrstrndx() failed: %s\n", elf_errmsg(-1)); @@ -36,7 +60,6 @@ static int elf_read_sections(Elf *e, struct memory *mem) while ((scn = elf_nextscn(e, scn)) != NULL) { GElf_Shdr shdr; - GElf_Phdr phdr; if (gelf_getshdr(scn, &shdr) == NULL) { err("Couldn't get section header: %s\n", elf_errmsg(-1)); @@ -44,8 +67,34 @@ static int elf_read_sections(Elf *e, struct memory *mem) } /* Is it a .text section? */ - if (shdr.sh_type == SHT_PROGBITS - && (shdr.sh_flags & ~SHF_WRITE) == (SHF_ALLOC | SHF_EXECINSTR)) { + if (elf_is_text_section(&shdr)) { + Elf_Data *text; + size_t n; + + if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) { + err("Couldn't get section name: %s\n", elf_errmsg(-1)); + return -1; + } + + dbg("text section %zu: %s (size=%zu, flags=%08lx, addr=%08lx, off=%08lx)\n", + elf_ndxscn(scn), name, shdr.sh_size, shdr.sh_flags, shdr.sh_addr, shdr.sh_offset); + + text = NULL; + n = 0; + while (n < shdr.sh_size && + (text = elf_getdata(scn, text)) != NULL) { + if (shdr.sh_addr + n + text->d_size > mem->size) { + err("Would write behind memory\n"); + return -1; + } + + memcpy(&mem->base[(shdr.sh_addr + n) / 4], text->d_buf, text->d_size); + + n += text->d_size; + } + + found_text = true; + } else if (elf_is_data_section(&shdr)) { Elf_Data *data; size_t n; @@ -54,19 +103,43 @@ static int elf_read_sections(Elf *e, struct memory *mem) return -1; } - dbg("Section %zu: %s (size=%zu, flags=%08lx, addr=%08lx, off=%08lx)\n", elf_ndxscn(scn), name, shdr.sh_size, shdr.sh_flags, shdr.sh_addr, shdr.sh_offset); + dbg("data section %zu: %s (size=%zu, flags=%08lx, addr=%08lx, off=%08lx)\n", + elf_ndxscn(scn), name, shdr.sh_size, shdr.sh_flags, shdr.sh_addr, shdr.sh_offset); data = NULL; n = 0; while (n < shdr.sh_size && (data = elf_getdata(scn, data)) != NULL) { + if (shdr.sh_addr + n + data->d_size > mem->size) { + err("Would write behind memory\n"); + return -1; + } + + /* XXX: why could this ever be NULL? */ + if (data->d_buf == NULL) { + err("data section %s is empty\n", name); + break; + } + memcpy(&mem->base[(shdr.sh_addr + n) / 4], data->d_buf, data->d_size); n += data->d_size; } + + found_data = true; } } + if (!found_text) { + err("No text section found in binary\n"); + return -1; + } + + if (!found_data) { + err("No data section found in binary\n"); + return -1; + } + return 0; } @@ -76,7 +149,6 @@ int elf_load(FILE *fp, const char *name, struct memory *mem) int ret; Elf *e; GElf_Ehdr ehdr; - size_t n; if (unlikely(fd < 0)) { err("Couldn't get file descriptor for '%s'\n", name); @@ -95,6 +167,8 @@ int elf_load(FILE *fp, const char *name, struct memory *mem) goto out; } + /* Check whether we've got a valid ELF executable for Nios II */ + if (elf_kind(e) != ELF_K_ELF) { err("'%s' is not an ELF object\n", name); goto out; |