diff options
| author | Ada Christine <adachristine18@gmail.com> | 2021-12-17 16:06:06 +0000 |
|---|---|---|
| committer | Ada Christine <adachristine18@gmail.com> | 2021-12-17 16:06:06 +0000 |
| commit | d5f485a4f6801f58cbb2bc9d8e80c955c79ff044 (patch) | |
| tree | e49757ff0b076fe9f0088de92e5691d362e769a0 | |
| parent | ec1233b4fcd61a8d1eccbf030cede36e9848e06c (diff) | |
R_AMD64_RELATIVE relocations implemented for EFI shim
| -rw-r--r-- | api/elf/elf64.h | 22 | ||||
| -rw-r--r-- | api/loader/efi/shim.h | 2 | ||||
| -rwxr-xr-x | debug.sh | 1 | ||||
| -rw-r--r-- | efi.mk | 2 | ||||
| -rwxr-xr-x | image.sh | 4 | ||||
| -rw-r--r-- | lib/elf.c | 106 | ||||
| -rw-r--r-- | lib/elf.h | 17 | ||||
| -rw-r--r-- | loader/main_efi.c | 3 | ||||
| -rw-r--r-- | shim/Makefile | 6 | ||||
| -rw-r--r-- | shim/entry.c | 6 |
10 files changed, 160 insertions, 9 deletions
diff --git a/api/elf/elf64.h b/api/elf/elf64.h index 4473d15..d975c35 100644 --- a/api/elf/elf64.h +++ b/api/elf/elf64.h @@ -18,6 +18,9 @@ typedef struct Elf64_Shdr Elf64_Shdr; typedef struct Elf64_Sym Elf64_Sym; typedef struct Elf64_Dyn Elf64_Dyn; +typedef struct Elf64_Rel Elf64_Rel; +typedef struct Elf64_Rela Elf64_Rela; + #define EM_X86_64 62 struct Elf64_Ehdr @@ -84,3 +87,22 @@ struct Elf64_Dyn }; }; +#define ELF64_R_SYM(info) ((info)>>32) +#define ELF64_R_TYPE(info) ((Elf64_Word)(info)) +#define ELF64_R_INFO(sym, type) (((Elf64_Xword)(sym)<<32)+(Elf64_Xword)(type)) + +#define R_AMD64_RELATIVE 8 + +struct Elf64_Rel +{ + Elf64_Addr r_offset; + Elf64_Xword r_info; +}; + +struct Elf64_Rela +{ + Elf64_Addr r_offset; + Elf64_Xword r_info; + Elf64_Sxword r_addend; +}; + diff --git a/api/loader/efi/shim.h b/api/loader/efi/shim.h index 3486c34..9421cc3 100644 --- a/api/loader/efi/shim.h +++ b/api/loader/efi/shim.h @@ -13,8 +13,6 @@ #define OsVendorMemoryType(t) ((EFI_MEMORY_TYPE)(0x80000000|t)) #define SystemMemoryType OsVendorMemoryType(1) -struct efi_loader_image; - struct efi_loader_image { CHAR16 *path; @@ -1,6 +1,7 @@ #!/usr/bin/env bash make -C loader && +make -C shim && make -C kernel && ./image.sh && @@ -22,7 +22,7 @@ CPPFLAGS += -I$(EFIAPIDIR) -I$(EFIAPIDIR)/protocol -I$(EFIAPIDIR)/$(GNUEFIARCH) -DGNU_EFI_USE_MS_ABI -DEFI_CALL_WRAPPER -DEFI_DEBUG CFLAGS += -fPIC -fshort-wchar -maccumulate-outgoing-args -mno-avx -mno-sse \ - -mno-mmx + -mno-mmx -funsigned-char -Wno-pointer-sign OBJCOPY.efi = $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic \ -j .dynsm -j .rel -j .rela -j .reloc \ @@ -2,6 +2,7 @@ imagefile=uefi.img loaderfile=loader/loader.efi +shimfile=shim/efi.os kernelfile=kernel/kernel.os if [[ ! -f ${imagefile} ]]; then @@ -14,5 +15,6 @@ mmd -i ${imagefile} -Do ::EFI/BOOT mcopy -i ${imagefile} -Do ${loaderfile} ::EFI/BOOT/BOOTX64.EFI mmd -i ${imagefile} -Do ::adasoft mmd -i ${imagefile} -Do ::adasoft/sophia -mcopy -i ${imagefile} ${kernelfile} -Do ::adasoft/sophia +mcopy -i ${imagefile} -Do ${shimfile} -Do ::adasoft/sophia +mcopy -i ${imagefile} -Do ${kernelfile} -Do ::adasoft/sophia 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); + diff --git a/loader/main_efi.c b/loader/main_efi.c index 7edb44d..4c9c9a0 100644 --- a/loader/main_efi.c +++ b/loader/main_efi.c @@ -145,7 +145,8 @@ EFI_STATUS open_image(struct efi_loader_image *image) &ehdr_size, &ehdr)))) { - if (elf_validate(&ehdr, ET_EXEC, EM_X86_64)) + if (elf_validate(&ehdr, ET_EXEC, EM_X86_64) || + elf_validate(&ehdr, ET_DYN, EM_X86_64)) { phdrs_size = ehdr.e_phentsize * ehdr.e_phnum; phdrs = AllocatePool(phdrs_size); diff --git a/shim/Makefile b/shim/Makefile index 51ec96c..42007b8 100644 --- a/shim/Makefile +++ b/shim/Makefile @@ -15,11 +15,11 @@ CFLAGS += -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden \ LIBDIRS += -L$(dir $(shell $(CC) -print-libgcc-file-name)) LDSCRIPT := shim.ld -LDFLAGS += -z max-page-size=4096 --export-dynamic +LDFLAGS += -z max-page-size=4096 --export-dynamic -pic --no-dynamic-linker LOADLIBES := -lgcc -OBJS := entry.o memcmp.o memcpy.o memmove.o memset.o -$(OBJS): CFLAGS += -fPIC -fPIE +OBJS := entry.o elf.o memcmp.o memcpy.o memmove.o memset.o +$(OBJS): CFLAGS += -fPIC DEPS := $(patsubst %.o,%.d,$(OBJS)) diff --git a/shim/entry.c b/shim/entry.c index 303f582..a4d00c7 100644 --- a/shim/entry.c +++ b/shim/entry.c @@ -49,7 +49,11 @@ EFI_STATUS efi_shim_entry(struct efi_loader_image *image, * 3. exit boot services * 5. ??????????? */ - + + void *image_base = (void *)image->buffer_base; + + elf_reloc(image_base); + EFI_STATUS status; if (!image) |
