summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAda Christine <adachristine18@gmail.com>2022-03-15 16:29:24 +0000
committerAda Christine <adachristine18@gmail.com>2022-03-15 16:29:24 +0000
commitec4aee35de3446713c6754641cdad82adc011204 (patch)
treefb40b7b153da4bbb47ec46b40144a18fbfbcf74b
parent97fcd7d1fc4574753d91e6767a8d8a7653a7f7fe (diff)
infrastructure for dynamic symbol resolution
-rw-r--r--api/elf/elf.h1
-rw-r--r--api/elf/elf64.h3
-rw-r--r--kc/api/kc.h33
-rw-r--r--kc/boot/Makefile3
-rw-r--r--kc/boot/kc_main.c2
-rw-r--r--kc/core/Makefile10
-rw-r--r--kc/defaults.mk4
-rw-r--r--kc/dynamic_x86_64.c53
-rw-r--r--kc/entry_x86_64.S27
-rw-r--r--kc/kc.ld29
-rw-r--r--kc/reloc_x86_64.c45
-rw-r--r--loader/main_efi.c2
12 files changed, 149 insertions, 63 deletions
diff --git a/api/elf/elf.h b/api/elf/elf.h
index 3d82bc0..209c219 100644
--- a/api/elf/elf.h
+++ b/api/elf/elf.h
@@ -80,4 +80,5 @@ typedef uint8_t Elf_Byte;
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
+#define DT_JMPREL 0x17
diff --git a/api/elf/elf64.h b/api/elf/elf64.h
index d975c35..9ea3031 100644
--- a/api/elf/elf64.h
+++ b/api/elf/elf64.h
@@ -91,7 +91,8 @@ struct Elf64_Dyn
#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
+#define R_X86_64_JUMP_SLOT 7
+#define R_X86_64_RELATIVE 8
struct Elf64_Rel
{
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 <elf/elf64.h>
+
+#include <stddef.h>
+
+#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 <kc.h>
+
+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 <kc.h>
+
.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 <kc.h>
-#include <elf/elf64.h>
-
-#include <stddef.h>
-
#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]);
}
}
diff --git a/loader/main_efi.c b/loader/main_efi.c
index a6cd7b4..907cedb 100644
--- a/loader/main_efi.c
+++ b/loader/main_efi.c
@@ -134,7 +134,7 @@ EFI_STATUS open_image(struct efi_loader_image *image)
}
else
{
- Print(L"failed opening image: %r\r\n", status);
+ Print(L"failed opening image %s: %r\r\n", image->path, status);
return status;
}