diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/elf.c | 106 | ||||
| -rw-r--r-- | lib/elf.h | 17 |
2 files changed, 123 insertions, 0 deletions
diff --git a/lib/elf.c b/lib/elf.c new file mode 100644 index 0000000..551a5a5 --- /dev/null +++ b/lib/elf.c @@ -0,0 +1,106 @@ +#include "elf.h" + +bool elf64_validate(Elf64_Ehdr *ehdr, unsigned type, unsigned machine) +{ + if (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_ident[EI_VERSION] != EV_CURRENT || + ehdr->e_machine != machine || + ehdr->e_type != type) + { + return false; + } + + return true; +} + +size_t elf64_size(Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs) +{ + size_t size = 0; + + for (int i = 0; i < ehdr->e_phnum; i++) + { + if (phdrs[i].p_type != PT_LOAD) + { + continue; + } + + if (phdrs[i].p_paddr + phdrs[i].p_memsz > size) + { + size = phdrs[i].p_paddr + phdrs[i].p_memsz; + if (phdrs[i].p_align > 1) + { + size = (size + phdrs[i].p_align - 1) & + ~(phdrs[i].p_align - 1); + } + } + } + + return size; +} + +void elf64_reloc(Elf64_Ehdr *ehdr) +{ + // locate the dynamic segment + Elf64_Phdr *phdrs = (Elf64_Phdr *)(ehdr->e_phoff + (uintptr_t)ehdr); + Elf64_Dyn *dyn = NULL; + Elf64_Rela *rela = NULL; + size_t rela_size; + int rela_count; + + for (int i = 0; i < ehdr->e_phnum; i++) + { + if (phdrs[i].p_type != PT_DYNAMIC) continue; + + dyn = (Elf64_Dyn *)(phdrs[i].p_offset + (uintptr_t)ehdr); + } + + // parse the dynamic segment + while (dyn->d_tag != DT_NULL) + { + switch (dyn->d_tag) + { + case DT_RELA: + rela = (Elf64_Rela *)(dyn->d_ptr + (uintptr_t)ehdr); + break; + case DT_RELASZ: + rela_size = dyn->d_val; + break; + case DT_RELAENT: + rela_count = rela_size / dyn->d_val; + break; + default: + break; + } + dyn++; + } + + // perform the actual relocations + + for (int i; i < rela_count; i++) + { + union + { + Elf_Byte word8; + Elf64_Half word16; + Elf64_Word word32; + Elf64_Xword word64; + } + *reloc_ptr = NULL; + + switch (ELF64_R_TYPE(rela[i].r_info)) + { + case R_AMD64_RELATIVE: + reloc_ptr = (void *)(rela[i].r_offset + (uintptr_t)ehdr); + reloc_ptr->word64 = (rela[i].r_addend + (uintptr_t)ehdr); + break; + default: + break; + } + } +} + diff --git a/lib/elf.h b/lib/elf.h new file mode 100644 index 0000000..3edb0a1 --- /dev/null +++ b/lib/elf.h @@ -0,0 +1,17 @@ +#pragma once + +#include <elf/elf64.h> + +#include <stdbool.h> +#include <stddef.h> + +#ifdef __x86_64__ +# define elf_validate elf64_validate +# define elf_size elf64_size +# define elf_reloc elf64_reloc +#endif + +bool elf64_validate(Elf64_Ehdr *ehdr, unsigned type, unsigned machine); +size_t elf64_size(Elf64_Ehdr *ehdr, Elf64_Phdr *phdr); +void elf64_reloc(Elf64_Ehdr *ehdr); + |
