summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--elf.c84
1 files changed, 79 insertions, 5 deletions
diff --git a/elf.c b/elf.c
index 439433b..eca6d9f 100644
--- a/elf.c
+++ b/elf.c
@@ -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;