diff --git a/src/relf/relf.c b/src/relf/relf.c index ff3427f..c074793 100644 --- a/src/relf/relf.c +++ b/src/relf/relf.c @@ -1 +1,61 @@ #include "relf/relf.h" +#include "blackjack/debug.h" +#include +#include +#include +#include +#include + +relf_value_t relf_open(relf_t* relf, const char* path) +{ + // reset struct + memset(relf, '\0', sizeof(relf_t)); + + // try stat file + struct stat st = {0}; + if (stat(path, &stat)) + return RELF_ERROR(RELF_FAILED_OPEN); + + // open file and read ELF header + relf->fd = open(path, O_RDONLY); + if (relf->fd < 0) + return RELF_ERROR(RELF_FAILED_OPEN); + + union { + Elf64_Ehdr hdr64; + Elf32_Ehdr hdr32; + } e; + + // read biggest value by default + if (read(relf->fd, &e.hdr64, sizeof(e.hdr64)) < sizeof(e.hdr64)) + { + close(relf->fd); + return RELF_ERROR(RELF_FAILED_OPEN); + } + + // check magic and decide ELF type + // we operate here ELF64 variant since it same as in ELF32 + if (!memcmp(e.hdr64.e_ident, ELFMAG, sizeof(ELFMAG))) + { + // not an ELF file at all + close(relf->fd); + return RELF_ERROR(RELF_NOT_AN_ELF); + } + + // 32 bit or 64 bit + switch (e.hdr64.e_ident[EI_CLASS]) + { + case ELFCLASS32: relf->type = RELF_32BIT; break; + case ELFCLASS64: relf->type = RELF_64BIT; break; + default: + close(relf->fd); + return RELF_ERROR(RELF_UNSUPPORTED); + } + + if (e.hdr64.e_ident[EI_DATA] != ELFDATA2LSB) + { + // not little endian, we can't work with that + close(relf->fd); + return RELF_ERROR(RELF_UNSUPPORTED); + } +} diff --git a/src/relf/relf.h b/src/relf/relf.h index c5643ba..e21ae9e 100644 --- a/src/relf/relf.h +++ b/src/relf/relf.h @@ -1,4 +1,46 @@ #ifndef __RELF_H #define __RELF_H +#include + +// composite error type +typedef enum { + RELF_MMAP_FAILED = -4, // file memory mapping failed + RELF_UNSUPPORTED = -3, // big endian or not x86/x86-64 architecture + RELF_NOT_AN_ELF = -2, // wrong magic + RELF_FAILED_OPEN = -1, // failed to stat or open file + RELF_OK = 0, +} relf_error_t; + +typedef union { + relf_error_t error; + + uintptr_t value; +} relf_value_t; + +// supply relf_value_t type here +#define RELF_IS_ERROR(v) (v.error < 0) +#define RELF_ERROR(e) ((relf_value_t) {.error = e}) + +typedef enum { + RELF_64BIT, + RELF_32BIT +} relf_type_t; + +// relf instance +typedef struct { + int fd; + void* image; + + // is it 64 or 32 bit mode + relf_type_t type; +} relf_t; + +// opens ELF file, checks ELF magic and maps it into memory +// may load additional info like string table +relf_value_t relf_open(relf_t* relf, const char* path); + +// closes mapping and file, frees any allocated memory in relf instance +void relf_close(relf_t* relf); + #endif \ No newline at end of file