summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob McDonnell <jacob@jacobmcdonnell.com>2024-05-28 00:33:52 -0400
committerJacob McDonnell <jacob@jacobmcdonnell.com>2024-05-28 00:33:52 -0400
commit83b0b878db0bcb29f7fb70a9fbcab30d793f7b1e (patch)
tree618d8206836a6d29d3dc473380167ddf79d7a403
parent0f1f3a13ac3c3b23510e142f042d25ca17de2b2f (diff)
Initial Implementation of ELF
-rwxr-xr-xelf.c68
-rwxr-xr-xelf.h54
-rwxr-xr-xmakefile4
-rwxr-xr-xqdme.c66
4 files changed, 178 insertions, 14 deletions
diff --git a/elf.c b/elf.c
new file mode 100755
index 0000000..2219d5f
--- /dev/null
+++ b/elf.c
@@ -0,0 +1,68 @@
+#include "elf.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <arpa/inet.h>
+
+static inline bool IsBigEndian(void);
+
+/* Elf Header for Little Endian Machines */
+const uint8_t e_ident_le[EI_NIDENT] = {
+ 0x7f, 0x45, 0x4c, 0x46, // ELF Magic Number
+ BIT_WIDTH, // 32-bit format
+ _LITTLE_ENDIAN_, // Little Endian
+ ELF_VERSION, // ELF Version
+ 0x00, // Target OS
+ 0x00, // Target ABI
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Padding
+};
+
+/* Elf Header for Big Endian Machines */
+const uint8_t e_ident_be[EI_NIDENT] = {
+ 0x7f, 0x45, 0x4c, 0x46, // ELF Magic Number
+ BIT_WIDTH, // 32-bit format
+ _BIG_ENDIAN_, // Big Endian
+ ELF_VERSION, // ELF Version
+ 0x00, // Target OS
+ 0x00, // Target ABI
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Padding
+};
+
+/* ReadElf: Read the elf header into e from file fp */
+ElfHeader_t ReadElf(FILE *fp) {
+ ElfHeader_t e;
+ fread(&e, sizeof(e), 1, fp);
+ if (ferror(fp)) {
+ perror("ReadElf");
+ }
+ return e;
+}
+
+/* ValidateElf: Validate the elf header for the given system */
+bool ValidateElf(ElfHeader_t e) {
+ const uint8_t * const e_ident = IsBigEndian() ? e_ident_be : e_ident_le;
+ for (size_t i = 0; i < EI_NIDENT; i++) {
+ if (e.e_ident[i] != e_ident[i]) {
+ return false;
+ }
+ }
+ if (e.e_machine != MIPS || e.e_version != ELF_VERSION ||
+ e.e_type != ET_EXEC || e.e_phentsize != sizeof(ProgramHeader_t)) {
+ return false;
+ }
+ return true;
+}
+
+/* ReadProgramHeader: Read n program headers into array p of size n from file
+ * fp */
+void ReadProgramHeader(size_t n, ProgramHeader_t p[n], FILE *fp) {
+ fread(p, sizeof(ProgramHeader_t), n, fp);
+ if (ferror(fp)) {
+ perror("ReadElf");
+ }
+}
+
+static inline bool IsBigEndian(void) {
+ int32_t x = 10;
+ return x == htonl(x);
+}
diff --git a/elf.h b/elf.h
new file mode 100755
index 0000000..953f748
--- /dev/null
+++ b/elf.h
@@ -0,0 +1,54 @@
+#ifndef ELF_H
+#define ELF_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#define EI_NIDENT 16
+#define MIPS 0x08
+#define PF_READ 4
+#define PF_WRITE 2
+#define PF_EXEC 1
+#define _LITTLE_ENDIAN_ 0x01
+#define _BIG_ENDIAN_ 0x02
+#define ELF_VERSION 0x01
+#define BIT_WIDTH 0x01 // 32-bit Format
+
+
+enum {ET_NONE, ET_REL, ET_EXEC, ET_DYN, ET_CORE};
+enum {PT_NULL, PT_LOAD, PT_DYNAMIC, PT_INTERP, PT_NOTE, PT_SHLIB, PT_TLS};
+
+typedef struct {
+ uint8_t e_ident[EI_NIDENT];
+ uint16_t e_type;
+ uint16_t e_machine;
+ uint32_t e_version;
+ uint32_t e_entry;
+ uint32_t e_phoff;
+ uint32_t e_shoff;
+ uint32_t e_flags;
+ uint16_t e_ehsize;
+ uint16_t e_phentsize;
+ uint16_t e_phnum;
+ uint16_t e_shentsize;
+ uint16_t e_shnum;
+ uint16_t e_shstrndx;
+} ElfHeader_t;
+
+typedef struct {
+ uint32_t ptype;
+ uint32_t offset;
+ uint32_t vaddr;
+ uint32_t paddr;
+ uint32_t filesz;
+ uint32_t memsz;
+ uint32_t flags;
+ uint32_t align;
+} ProgramHeader_t;
+
+ElfHeader_t ReadElf(FILE *fp);
+bool ValidateElf(ElfHeader_t e);
+void ReadProgramHeader(size_t n, ProgramHeader_t p[n], FILE *fp);
+
+#endif
diff --git a/makefile b/makefile
index 389b5c5..04b267f 100755
--- a/makefile
+++ b/makefile
@@ -1,7 +1,7 @@
CC=gcc
CFLAGS=-Wall -Werror -pedantic --std=c17
-OBJS=qdme.o
-SRCS=qdme.c
+OBJS=qdme.o elf.o
+SRCS=qdme.c elf.c
TARGET=qdme
%.o: %.c %.h
diff --git a/qdme.c b/qdme.c
index 7ddd1ce..0198e66 100755
--- a/qdme.c
+++ b/qdme.c
@@ -3,11 +3,15 @@
#include <string.h>
#include <arpa/inet.h>
#include "qdme.h"
+#include "elf.h"
-uint8_t memory[MEM_SIZE * WORD_SIZE] = {0};
+uint8_t *memory = NULL;
+size_t memsize;
uint32_t pc = 0, hi = 0, lo = 0;
uint32_t regFile[32] = {0};
+int LoadProgramHeader(ProgramHeader_t p, FILE *fp);
+
/* InstFetch: Fetch the next instruction from memory into the given
* instruction */
void InstFetch(inst_t *inst) {
@@ -241,7 +245,7 @@ void CycleCpu(void) {
inst_t instFetch, instExec;
memset(&instFetch, 0, sizeof(inst_t));
memset(&instExec, 0, sizeof(inst_t));
- while (pc < MEM_SIZE) {
+ while (pc < memsize) {
InstFetch(&instFetch);
InstExec(instExec);
instExec = instFetch;
@@ -255,31 +259,69 @@ int LoadBinary(const char * const path) {
return -1;
}
- uint8_t *freeMem = memory;
- size_t i = 0, offset = 0;
- while ((i = fread(freeMem + offset, sizeof(memory[0]), (MEM_SIZE * WORD_SIZE) - offset, fp)) != 0) {
- offset += i;
+ ElfHeader_t e = ReadElf(fp);
+ if (!ValidateElf(e)) {
+ return -1;
+ }
+
+ pc = e.e_entry;
+
+ const size_t n = e.e_phnum;
+ ProgramHeader_t *p = (ProgramHeader_t *)calloc(n, e.e_phentsize);
+ if (p == NULL) {
+ perror("calloc");
+ return -1;
}
+ ReadProgramHeader(n, p, fp);
- for (size_t i = 0; i < offset; i += 4) {
- uint32_t x;
- memcpy(&x, memory + i, sizeof(x));
- printf("%02lu: 0x%08x\n", i, x);
+ for (size_t i = 0; i < n; i++) {
+ memsize += p[i].memsz;
}
- if (ferror(fp) || !feof(fp)) {
- perror("fread");
+ if ((memory = (uint8_t *)calloc(memsize, sizeof(uint8_t))) == NULL) {
+ perror("calloc");
+ free((void *)p);
+ fclose(fp);
return -1;
}
+ for (size_t i = 0; i < n; i++) {
+ if (LoadProgramHeader(p[i], fp) == -1) {
+ free((void *)p);
+ fclose(fp);
+ return -1;
+ }
+ }
+
+ free((void *)p);
fclose(fp);
return 0;
}
+/* LoadProgramHeader: Load the program segment described by the given program
+ * header from file fp. Returns 0 on success and -1 on failure. */
+int LoadProgramHeader(ProgramHeader_t p, FILE *fp) {
+ uint8_t *memloc = memory + p.vaddr;
+ size_t s = p.filesz;
+ if (fseek(fp, p.offset, SEEK_SET) != 0) {
+ perror("fseek");
+ return -1;
+ }
+ fread(memloc, sizeof(uint8_t), s, fp);
+ if (ferror(fp)) {
+ return -1;
+ }
+ for (size_t j = p.vaddr; j < p.filesz; j++) {
+ printf("%lu: %08x\n", j, memory[j]);
+ }
+ return 0;
+}
+
int main(int argc, char *argv[]) {
if (LoadBinary(*++argv) == -1) {
return -1;
}
CycleCpu();
+ free((void *)memory);
}