From 7642349be93be4a1acf62e9c5ca831f918ba1c3c Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Sun, 12 May 2024 00:33:10 +0200 Subject: [PATCH] Load ELF into emulator --- .gitignore | 1 + build.bat | 6 +- main.c => emulator/main.c | 157 ++++++++++++++++++++++++++++++++++++++ main.asm | 9 +++ 4 files changed, 172 insertions(+), 1 deletion(-) rename main.c => emulator/main.c (78%) create mode 100644 main.asm diff --git a/.gitignore b/.gitignore index 1feae78..871d882 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.exe +*.bin diff --git a/build.bat b/build.bat index 593aa28..f115f95 100644 --- a/build.bat +++ b/build.bat @@ -1,2 +1,6 @@ -clang main.c -o riscv.exe -std=c11 +clang emulator/main.c -o emulator.exe -std=c11 -D_CRT_SECURE_NO_WARNINGS +REM clang linker/main.c -o linker.exe -std=c11 -D_CRT_SECURE_NO_WARNINGS + +clang --target=riscv32 -march=rv32i -e _main -nostdlib main.asm -o main.bin + diff --git a/main.c b/emulator/main.c similarity index 78% rename from main.c rename to emulator/main.c index 223403a..d48c049 100644 --- a/main.c +++ b/emulator/main.c @@ -3,6 +3,134 @@ #include #include #include +#include + +#define ET_NONE 0x00 +#define ET_REL 0x01 +#define ET_EXEC 0x02 +#define ET_DYN 0x03 +#define ET_CORE 0x04 + +struct Elf32Header +{ + uint8_t ident[16]; + uint16_t type; + uint16_t machine; + uint32_t version; + uint32_t entry; + uint32_t phoff; + uint32_t shoff; + uint32_t flags; + uint16_t ehsize; + uint16_t phentsize; + uint16_t phnum; + uint16_t shentsize; + uint16_t shnum; + uint16_t shstrndx; +}; + +#define PT_NULL 0x00000000 +#define PT_LOAD 0x00000001 +#define PT_DYNAMIC 0x00000002 +#define PT_INTERP 0x00000003 +#define PT_NOTE 0x00000004 +#define PT_SHLIB 0x00000005 +#define PT_PHDR 0x00000006 +#define PT_TLS 0x00000007 + +#define PF_X 0x1 +#define PF_W 0x2 +#define PF_R 0x4 + +struct Elf32ProgramHeader +{ + uint32_t type; + uint32_t offset; + uint32_t vaddr; + uint32_t paddr; + uint32_t filesz; + uint32_t memsz; + uint32_t flags; + uint32_t align; +}; + +bool load_elf(const char* file, char* mem, uint32_t mem_size, uint32_t* start_address) +{ + FILE* fp = fopen(file, "rb"); + if (fp == NULL) + { + printf("Couldn't open input file\n"); + return false; + } + + struct Elf32Header header; + size_t read = fread(&header, sizeof(struct Elf32Header), 1, fp); + if (read != 1) + { + printf("ELF header too small\n"); + return false; + } + + static uint8_t kValidIdent[7] = { + 0x7f, 0x45, 0x4c, 0x46, + 1, 1, 1 + }; + if (memcmp(kValidIdent, header.ident, 7) != 0) + { + printf("Invalid ELF header\n"); + return false; + } + + if (header.type != ET_EXEC) + { + printf("Can only link EXEC ELF files\n"); + return false; + } + + memset(mem, 0, mem_size); + + assert(header.phnum == 0 || header.phentsize == sizeof(struct Elf32ProgramHeader)); + for (uint32_t i = 0; i < header.phnum; ++i) + { + struct Elf32ProgramHeader pheader; + + fseek(fp, header.phoff + i * header.phentsize, SEEK_SET); + read = fread(&pheader, sizeof(struct Elf32ProgramHeader), 1, fp); + if (read != 1) + { + printf("Error reading program header at index %u\n", i); + return false; + } + + if (pheader.type == PT_LOAD) + { + if (pheader.paddr + pheader.memsz > mem_size) + { + printf("Memory not large enough for ELF file\n"); + return false; + } + + fseek(fp, pheader.offset, SEEK_SET); + read = fread(mem + pheader.paddr, pheader.filesz, 1, fp); + if (read != 1) + { + printf("Error when copying ELF segment\n"); + return false; + } + } + } + + if (header.entry > mem_size) + { + printf("Entry address out of bounds\n"); + return false; + } + + *start_address = header.entry; + fclose(fp); + + return true; +} inline uint32_t sign_extend(uint32_t word, uint32_t size) { @@ -639,5 +767,34 @@ void test() int main(int argc, char* argv[]) { test(); + + if (argc < 2) + { + printf("Usage: %s \n", argv[0]); + return EXIT_FAILURE; + } + + uint32_t mem_size = 16 * 1024 * 1024; + char* mem = (char*)malloc(mem_size); + uint32_t start_address = 0; + + if (!load_elf(argv[1], mem, mem_size, &start_address)) + { + printf("Error loading ELF into memory\n"); + return EXIT_FAILURE; + } + + struct Hart hart = {0}; + hart.pc = start_address; + + while (true) + { + uint32_t instruction = *(uint32_t*)(mem + hart.pc); + execute(&hart, instruction); + printf("pc=%x x1=%d x2=%d x3=%d x4=%d\n", + hart.pc, hart.regs[1], hart.regs[2], hart.regs[3], hart.regs[4]); + fgetc(stdout); + } + return EXIT_SUCCESS; } diff --git a/main.asm b/main.asm new file mode 100644 index 0000000..e90d6a2 --- /dev/null +++ b/main.asm @@ -0,0 +1,9 @@ +.section .text +.global _main +_main: + li x1, 5 + addi x2, x1, 45 + +loop: + addi x2, x2, 1 + j loop