From ec4aee35de3446713c6754641cdad82adc011204 Mon Sep 17 00:00:00 2001 From: Ada Christine Date: Tue, 15 Mar 2022 16:29:24 +0000 Subject: infrastructure for dynamic symbol resolution --- kc/api/kc.h | 33 ++++++++++++++++++++++++++++++++- kc/boot/Makefile | 3 ++- kc/boot/kc_main.c | 2 ++ kc/core/Makefile | 10 +++++----- kc/defaults.mk | 4 ++-- kc/dynamic_x86_64.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ kc/entry_x86_64.S | 27 +++++++++++++++++++-------- kc/kc.ld | 29 +++++++++++++++++++++-------- kc/reloc_x86_64.c | 45 +++++++++------------------------------------ 9 files changed, 145 insertions(+), 61 deletions(-) create mode 100644 kc/dynamic_x86_64.c (limited to 'kc') diff --git a/kc/api/kc.h b/kc/api/kc.h index b4a6682..2e3b43c 100644 --- a/kc/api/kc.h +++ b/kc/api/kc.h @@ -1,5 +1,13 @@ #pragma once +#ifndef __ASSEMBLER__ + +#include + +#include + +#define KC_EXPORT __attribute__((visibility("default"))) + extern unsigned char kc_image_base; extern unsigned char kc_text_begin; extern unsigned char kc_text_end; @@ -8,5 +16,28 @@ extern unsigned char kc_data_begin; extern unsigned char kc_data_end; extern unsigned char kc_image_end; -#define KC_EXPORT __attribute__((visibility("default"))) +extern void kc_dynamic_init(void *base, Elf64_Dyn *dyn); +extern void kc_reloc( + void *base, + Elf64_Rela *entries, + size_t size, + size_t entsize); + +extern void kc_resolve_symbol(void); + +#else + +.extern kc_image_base +.extern kc_text_begin +.extern kc_text_end +.extern kc_rodata_begin +.extern kc_rodata_end +.extern kc_data_begin +.extern kc_data_end +.extern kc_image_end +.extern _DYNAMIC + +.extern kc_dynamic_init + +#endif // __ASSEMBLER__ diff --git a/kc/boot/Makefile b/kc/boot/Makefile index 159fec1..44ae161 100644 --- a/kc/boot/Makefile +++ b/kc/boot/Makefile @@ -8,7 +8,8 @@ TARGET := efi.os .DEFAULT: $(TARGET) CPPFLAGS += -I../../api -I ../api -OBJS := entry_x86_64.o reloc_x86_64.o kc_main.o elf64.o memcmp.o memcpy.o \ +OBJS := entry_x86_64.o reloc_x86_64.o dynamic_x86_64.o \ + kc_main.o elf64.o memcmp.o memcpy.o \ memmove.o memset.o loader_paging.o DEPS := $(patsubst %.o,%.d,$(OBJS)) diff --git a/kc/boot/kc_main.c b/kc/boot/kc_main.c index 5b32ee6..cb8eb7a 100644 --- a/kc/boot/kc_main.c +++ b/kc/boot/kc_main.c @@ -452,6 +452,8 @@ EFI_STATUS kc_main(struct efi_loader_interface *interface) e_bs = loader_interface->system_table->BootServices; eto = loader_interface->system_table->ConOut; + plog(L"opening kernel image\r\n"); + if (!EFI_ERROR((status = interface->image_open(&kernel_image))) && !EFI_ERROR((status = interface->image_alloc(&kernel_image))) && !EFI_ERROR((status = interface->image_load(&kernel_image)))) diff --git a/kc/core/Makefile b/kc/core/Makefile index 2c7303e..dede157 100644 --- a/kc/core/Makefile +++ b/kc/core/Makefile @@ -10,11 +10,11 @@ CPPFLAGS += -I../../api -I../api -I. CFLAGS += -Wno-unused-const-variable -Wno-unused-function -fvisibility=hidden -g SOBJS := -GOBJS := entry_x86_64.o reloc_x86_64.o kprint.o serial.o port.o mmu.o \ - kc_main.o memory.o memset.o memcpy.o memmove.o memcmp.o cpu.o \ - vm_tree.o exceptions.o panic.o msr.o task.o cpu_task.o irq.o \ - kcc_memory.o string.o pic8259.o pic8259_isr.o pit8253.o \ - page_early.o page_stack.o strtoull.o +GOBJS := entry_x86_64.o reloc_x86_64.o dynamic_x86_64.o \ + kprint.o serial.o port.o mmu.o kc_main.o memory.o memset.o memcpy.o \ + memmove.o memcmp.o cpu.o vm_tree.o exceptions.o panic.o msr.o task.o \ + cpu_task.o irq.o kcc_memory.o string.o pic8259.o pic8259_isr.o \ + pit8253.o page_early.o page_stack.o strtoull.o IOBJS := # __attribute__((interrupt)) requires -mgeneral-regs-only diff --git a/kc/defaults.mk b/kc/defaults.mk index 588b9b0..0b6c4ba 100644 --- a/kc/defaults.mk +++ b/kc/defaults.mk @@ -1,7 +1,7 @@ LIBDIRS += -L$(dir $(shell $(CC) -print-libgcc-file-name)) LDSCRIPT := ../kc.ld -LDFLAGS += -z max-page-size=4096 --export-dynamic -pic --no-dynamic-linker \ - -z separate-code +LDFLAGS += -z max-page-size=4096 --export-dynamic -pic \ + -z separate-code -pie -Bsymbolic -shared LOADLIBES := -lgcc diff --git a/kc/dynamic_x86_64.c b/kc/dynamic_x86_64.c new file mode 100644 index 0000000..22300d6 --- /dev/null +++ b/kc/dynamic_x86_64.c @@ -0,0 +1,53 @@ +#include + +void kc_dynamic_init(void *base, Elf64_Dyn *dyn) +{ + struct rela + { + Elf64_Rela *entries; + size_t size; + size_t entsize; + }; + + struct rela reladyn = {NULL,}; + struct rela relaplt = {NULL,}; + + Elf64_Addr *gotplt; + + while (dyn && dyn->d_tag != DT_NULL) + { + switch(dyn->d_tag) + { + // check for basic relocations first + case DT_RELA: + reladyn.entries = (Elf64_Rela *)(dyn->d_ptr + (uintptr_t)base); + break; + case DT_RELASZ: + reladyn.size = dyn->d_val; + break; + // might be combined with JMPRELs so check those too + case DT_JMPREL: + relaplt.entries = (Elf64_Rela *)(dyn->d_ptr + (uintptr_t)base); + break; + case DT_PLTRELSZ: + relaplt.size = dyn->d_val; + break; + case DT_RELAENT: + reladyn.entsize = dyn->d_val; + relaplt.entsize = dyn->d_val; + break; + case DT_PLTGOT: + gotplt = (uintptr_t *)(dyn->d_ptr + (uintptr_t)base); + break; + } + dyn++; + } + + // peform relocations + // + gotplt[1] = (uintptr_t)NULL; + gotplt[2] = (uintptr_t)kc_resolve_symbol; + kc_reloc(base, relaplt.entries, relaplt.size, relaplt.entsize); + kc_reloc(base, reladyn.entries, reladyn.size, reladyn.entsize); +} + diff --git a/kc/entry_x86_64.S b/kc/entry_x86_64.S index abea8ac..8431044 100644 --- a/kc/entry_x86_64.S +++ b/kc/entry_x86_64.S @@ -1,19 +1,30 @@ +#include + .section .text.start -.extern kc_reloc -.extern kc_main -.extern _DYNAMIC -.extern kc_image_base .hidden kc_entry .global kc_entry .type kc_entry, @function kc_entry: push %rdi - lea _DYNAMIC(%rip), %rdi - lea kc_image_base(%rip), %rsi - call kc_reloc + push %rsi + lea kc_image_base(%rip), %rdi + lea _DYNAMIC(%rip), %rsi + call kc_dynamic_init + pop %rsi pop %rdi call kc_main ret .size kc_entry, . - kc_entry - + +.section .text + +.hidden kc_resolve_symbol +.global kc_resolve_symbol +.type kc_resolve_symbol, @function +kc_resolve_symbol: + cli + hlt + jmp kc_resolve_symbol +.size kc_resolve_symbol, . - kc_resolve_symbol + diff --git a/kc/kc.ld b/kc/kc.ld index 76e096a..22ee6be 100644 --- a/kc/kc.ld +++ b/kc/kc.ld @@ -6,16 +6,14 @@ SECTIONS . = sizeof_headers; - .rel : + .rela.plt : { - *(.rel) - *(.rel.*) + *(.rela.plt) } - .rela : + .rela.dyn : { - *(.rel) - *(.rela.*) + *(.rela.dyn) } .hash : @@ -38,18 +36,33 @@ SECTIONS PROVIDE_HIDDEN(kc_text_begin = .); *(.text.start) *(.text) + } + + .plt : + { + *(.plt) . = ALIGN(4K); PROVIDE_HIDDEN(kc_text_end = .); } =0xcc - + .dynamic : ALIGN(4K) { + PROVIDE_HIDDEN(kc_data_begin = .); *(.dynamic) } + .got : + { + *(.got) + } + + .got.plt : + { + *(.got.plt) + } + .data : { - PROVIDE_HIDDEN(kc_data_begin = .); *(.rodata) *(.data) } diff --git a/kc/reloc_x86_64.c b/kc/reloc_x86_64.c index c70027f..63dc6e7 100644 --- a/kc/reloc_x86_64.c +++ b/kc/reloc_x86_64.c @@ -1,13 +1,9 @@ #include -#include - -#include - #define STARTCODE __attribute__((section(".text.start"))) STARTCODE -static void do_rela(Elf64_Rela *rela, void *base) +static void do_rela(void *base, Elf64_Rela *rela) { union { @@ -20,7 +16,11 @@ static void do_rela(Elf64_Rela *rela, void *base) switch (ELF64_R_TYPE(rela->r_info)) { - case R_AMD64_RELATIVE: + case R_X86_64_JUMP_SLOT: + fixup = (void *)(rela->r_offset + (uintptr_t)base); + fixup->word64 += (uintptr_t)base; + break; + case R_X86_64_RELATIVE: fixup = (void *)(rela->r_offset + (uintptr_t)base); fixup->word64 = (rela->r_addend + (uintptr_t)base); break; @@ -30,40 +30,13 @@ static void do_rela(Elf64_Rela *rela, void *base) } STARTCODE -void kc_reloc(Elf64_Dyn *dyn, void *base) +void kc_reloc(void *base, Elf64_Rela *entries, size_t size, size_t entsize) { - struct - { - Elf64_Rela *entries; - size_t *size; - size_t *entsize; - } - rela = {NULL, NULL, NULL}; - - // parse the dynamic segment - while (dyn && dyn++->d_tag != DT_NULL) - { - switch (dyn->d_tag) - { - case DT_RELA: - rela.entries = (Elf64_Rela *)(dyn->d_ptr + (uintptr_t)base); - break; - case DT_RELASZ: - rela.size = &dyn->d_val; - break; - case DT_RELAENT: - rela.entsize = &dyn->d_val; - break; - default: - break; - } - } - // perform the actual relocation - for (size_t i = 0; rela.entries && (i < *rela.size / *rela.entsize); i++) + for (size_t i = 0; entries && (i < size / entsize); i++) { - do_rela(&rela.entries[i], base); + do_rela(base, &entries[i]); } } -- cgit v1.3.1-1-g115d