summaryrefslogtreecommitdiff
path: root/elf.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf.c')
-rw-r--r--elf.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/elf.c b/elf.c
new file mode 100644
index 0000000..cc90b18
--- /dev/null
+++ b/elf.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ *
+ * This file is part of nios2sim-ng.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <libelf.h>
+#include <gelf.h>
+
+#include "nios2sim-ng.h"
+#include "image.h"
+
+/* not defined with libelf */
+#define EM_ALTERA_NIOS2 113
+
+/*
+ * http://elftoolchain.sourceforge.net/for-review/libelf-by-example-20100112.pdf
+ */
+
+static int elf_read_sections(Elf *e)
+{
+ Elf_Scn *scn = NULL;
+ GElf_Shdr shdr;
+ size_t shstrndx;
+ char *name;
+
+ if (elf_getshdrstrndx(e, &shstrndx) != 0) {
+ err("elf_getshdrstrndx() failed: %s\n", elf_errmsg(-1));
+ return -1;
+ }
+
+ while ((scn = elf_nextscn(e, scn)) != NULL) {
+ GElf_Phdr phdr;
+
+ if (gelf_getshdr(scn, &shdr) != &shdr) {
+ err("Couldn't get section header: %s\n", elf_errmsg(-1));
+ return -1;
+ }
+
+ if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) {
+ err("Couldn't get section name: %s\n", elf_errmsg(-1));
+ return -1;
+ }
+
+ dbg("Section %zu: %s\n", elf_ndxscn(scn), name);
+ }
+
+ return 0;
+}
+
+int elf_load(FILE *fp, const char *name, uint8_t *mem_base, size_t mem_size)
+{
+ int fd = fileno(fp);
+ int ret;
+ Elf *e;
+ GElf_Ehdr ehdr;
+ size_t n;
+
+ if (unlikely(fd < 0)) {
+ err("Couldn't get file descriptor for '%s'\n", name);
+ return -1;
+ }
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ err("ELF library initialization failed\n");
+ return -1;
+ }
+
+ ret = -1;
+ e = elf_begin(fd, ELF_C_READ, NULL);
+ if (unlikely(e == NULL)) {
+ err("Couldn't get ELF file handle for '%s': %s\n", name, elf_errmsg(-1));
+ goto out;
+ }
+
+ if (elf_kind(e) != ELF_K_ELF) {
+ err("'%s' is not an ELF object\n", name);
+ goto out;
+ }
+
+ if (gelf_getclass(e) != ELFCLASS32) {
+ err("'%s' has invalid ELF class\n", name);
+ goto out;
+ }
+
+ if (gelf_getehdr(e, &ehdr) == NULL) {
+ err("gelf_getehdr() failed: %s\n", elf_errmsg(-1));
+ goto out;
+ }
+
+ if (ehdr.e_type != ET_EXEC || ehdr.e_machine != EM_ALTERA_NIOS2) {
+ err("'%s' is not a Nios2 ELF executable (%x, %x)\n", name, ehdr.e_type, ehdr.e_machine);
+ goto out;
+ }
+
+ ret = elf_read_sections(e);
+out:
+ elf_end(e);
+ return ret;
+}