From 83b0b878db0bcb29f7fb70a9fbcab30d793f7b1e Mon Sep 17 00:00:00 2001 From: Jacob McDonnell Date: Tue, 28 May 2024 00:33:52 -0400 Subject: Initial Implementation of ELF --- elf.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ elf.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++ makefile | 4 ++-- qdme.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++------------ 4 files changed, 178 insertions(+), 14 deletions(-) create mode 100755 elf.c create mode 100755 elf.h 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 +#include +#include +#include + +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 +#include +#include + +#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 #include #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); } -- cgit v1.2.3