commit 764c56209e6f7ec63ac1a15059bd6a40fcae272d from: Benjamin Stürz date: Fri Jul 05 19:00:14 2024 UTC use destruct(1) for parsing ELF headers commit - cd0438ce5c0e5285e02b003de77438a71492de5d commit + 764c56209e6f7ec63ac1a15059bd6a40fcae272d blob - 4124e1203a82d28f1fc7418e37d6e6d3c628c626 blob + b245057f1e7392bdab164569fe3ae073316b2922 --- Makefile +++ Makefile @@ -47,6 +47,7 @@ install: linurv linurv: ${OBJ} ${CC} -o $@ ${OBJ} ${LDFLAGS} +${OBJ}: src/linurv.h src/data.h src/ecall.o: src/syscalls.h src/cpu.o: src/signal-bootstrap-code.h blob - c2f091bc7b9f67ffb6c76e1b9e89e6b274ba28d1 blob + ad3b92558169ad5a4f69fdba5a972d750e48c16f --- src/data.dst +++ src/data.dst @@ -4,6 +4,7 @@ struct elf64_ehdr { type: u16, machine: u16, version: u32, + entry: u64, phoff: u64, shoff: u64, flags: u32, blob - cb238ae4659091f4c53a5e07cf31b2bb9ecc5897 blob + 0fdb8431581673d815c4611a6f56838ddaf0b614 --- src/exec.c +++ src/exec.c @@ -5,23 +5,31 @@ #include #include #include "linurv.h" +#include "data.h" - -int is_executable (const Elf64_Ehdr *ehdr) +int is_executable (const struct elf64_ehdr *ehdr) { - return ehdr->e_ident[EI_MAG0] == ELFMAG0 - && ehdr->e_ident[EI_MAG1] == ELFMAG1 - && ehdr->e_ident[EI_MAG2] == ELFMAG2 - && ehdr->e_ident[EI_MAG3] == ELFMAG3 - && ehdr->e_ident[EI_CLASS] == ELFCLASS64 - && ehdr->e_ident[EI_DATA] == ELFDATA2LSB - && ehdr->e_machine == EM_RISCV + return ehdr->ident[EI_MAG0] == ELFMAG0 + && ehdr->ident[EI_MAG1] == ELFMAG1 + && ehdr->ident[EI_MAG2] == ELFMAG2 + && ehdr->ident[EI_MAG3] == ELFMAG3 + && ehdr->ident[EI_CLASS] == ELFCLASS64 + && ehdr->ident[EI_DATA] == ELFDATA2LSB + && ehdr->machine == EM_RISCV ; } +void read_elf_ehdr (int fd, struct elf64_ehdr *ehdr) +{ + char buffer[sizeof (*ehdr)]; + if (read (fd, buffer, sizeof (buffer)) != sizeof (buffer)) + err (1, "read_elf_ehdr()"); + decode_elf64_ehdr (ehdr, buffer); +} + int my_execve (const char *path, char **argv, char **envp) { - Elf64_Ehdr ehdr; + struct elf64_ehdr ehdr; char buffer[256], *nl, *s; int fd; @@ -52,9 +60,9 @@ int my_execve (const char *path, char **argv, char **e return my_execve (s, argv, envp); } - memset (&ehdr, 0, sizeof (ehdr)); + memset (buffer, 0, sizeof (ehdr)); lseek (fd, 0, SEEK_SET); - read (fd, &ehdr, sizeof (ehdr)); + read_elf_ehdr (fd, &ehdr); close (fd); if (is_executable (&ehdr)) { blob - aba351c137c52352baa240f38588b05c79aec9b1 blob + 4c367bd11bfe114032fcf6f6573f29b1054327f4 --- src/linurv.c +++ src/linurv.c @@ -22,19 +22,19 @@ const char *levelstr[] = { enum log_level curlevel; u64 brkval = 0; -static void load_segment (int fd, Elf64_Phdr phdr) +static void load_segment (int fd, const struct elf64_phdr *phdr) { size_t end, len, ps; int prot = 0; void *addr, *ptr; - if (phdr.p_filesz > phdr.p_memsz) - errx (1, "invalid program header: p_filesz > p_memsz"); + if (phdr->filesz > phdr->memsz) + errx (1, "invalid program header: filesz > memsz"); ps = getpagesize (); - addr = (void *)(phdr.p_vaddr & ~(ps - 1)); - len = phdr.p_memsz + phdr.p_vaddr - (size_t)addr; + addr = (void *)(phdr->vaddr & ~(ps - 1)); + len = phdr->memsz + phdr->vaddr - (size_t)addr; ptr = mmap ( addr, @@ -49,52 +49,54 @@ static void load_segment (int fd, Elf64_Phdr phdr) if (ptr == NULL) err (1, "mmap()"); - if (phdr.p_filesz > 0) { - lseek (fd, phdr.p_offset, SEEK_SET); - read (fd, (void *)phdr.p_vaddr, phdr.p_filesz); + if (phdr->filesz > 0) { + lseek (fd, phdr->offset, SEEK_SET); + read (fd, (void *)phdr->vaddr, phdr->filesz); } - if (phdr.p_flags & (PF_R | PF_X)) + if (phdr->flags & (PF_R | PF_X)) prot |= PROT_READ; - if (phdr.p_flags & PF_W) + if (phdr->flags & PF_W) prot |= PROT_WRITE; if (mprotect (addr, len, prot) != 0) err (1, "mprotect()"); - end = (phdr.p_vaddr + phdr.p_memsz + ps - 1) & ~(ps - 1); + end = (phdr->vaddr + phdr->memsz + ps - 1) & ~(ps - 1); if (end > brkval) brkval = end; } static void load_image (const char *filename) { - Elf64_Ehdr ehdr; + struct elf64_ehdr ehdr; int fd; fd = open (filename, O_RDONLY); if (fd < 0) err (1, "open('%s')", filename); - if (read (fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr)) - err (1, "read('%s')", filename); + read_elf_ehdr (fd, &ehdr); if (!is_executable (&ehdr)) errx (1, "Invalid argument"); - pc = ehdr.e_entry; + pc = ehdr.entry; - for (unsigned i = 0; i < ehdr.e_phnum; ++i) { - Elf64_Phdr phdr; + for (unsigned i = 0; i < ehdr.phnum; ++i) { + struct elf64_phdr phdr; + char buffer[sizeof (phdr)]; - lseek (fd, ehdr.e_phoff + i * ehdr.e_phentsize, SEEK_SET); - if (read (fd, &phdr, ehdr.e_phentsize) != ehdr.e_phentsize) + lseek (fd, ehdr.phoff + i * ehdr.phentsize, SEEK_SET); + if (read (fd, buffer, ehdr.phentsize) != sizeof (buffer)) err (1, "failed to read program header %u", i); - switch (phdr.p_type) { + decode_elf64_phdr (&phdr, buffer); + + switch (phdr.type) { case PT_NULL: break; case PT_LOAD: - load_segment (fd, phdr); + load_segment (fd, &phdr); break; case PT_INTERP: case PT_DYNAMIC: blob - d565fc7a8b030875463a30066c3c5a63ca5fe009 blob + 9474a14e270beffd34ffdb1cb058ab2a21253438 --- src/linurv.h +++ src/linurv.h @@ -3,6 +3,7 @@ #include #include #include +#include "data.h" enum log_level { LOG_SILENT, // don't print anything @@ -74,7 +75,8 @@ void cpu_set (size_t reg, u64 val); void cpu_exec (u32 instr); void ecall (void); int my_execve (const char *path, char **argv, char **envp); -int is_executable (const Elf64_Ehdr *); +int is_executable (const struct elf64_ehdr *); +void read_elf_ehdr (int fd, struct elf64_ehdr *); void logger (enum log_level, const char *, int, const char *, ...); void cpu_enter_signal (int sig, u64 handler);