summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/component.ld75
-rw-r--r--lib/elf.c106
-rw-r--r--lib/elf64.c45
-rw-r--r--lib/entry_x86_64.S18
-rw-r--r--lib/reloc_x86_64.c69
5 files changed, 207 insertions, 106 deletions
diff --git a/lib/component.ld b/lib/component.ld
new file mode 100644
index 0000000..3a48ae8
--- /dev/null
+++ b/lib/component.ld
@@ -0,0 +1,75 @@
+ENTRY(kc_entry)
+
+SECTIONS
+{
+ PROVIDE(kc_image_base = .);
+
+ . = sizeof_headers;
+
+ .rel :
+ {
+ *(.rel)
+ *(.rel.*)
+ }
+
+ .rela :
+ {
+ *(.rel)
+ *(.rela.*)
+ }
+
+ .hash :
+ {
+ *(.hash)
+ }
+
+ .dynsym :
+ {
+ *(.dynsym)
+ }
+
+ .dynstr :
+ {
+ *(.dynstr)
+ }
+
+ .text : ALIGN(4K)
+ {
+ PROVIDE(kc_text_begin = .);
+ *(.text.start)
+ *(.text)
+ . = ALIGN(4K);
+ PROVIDE(kc_text_end = .);
+ } =0xcc
+
+ .dynamic : ALIGN(4K)
+ {
+ *(.dynamic)
+ }
+
+ .data :
+ {
+ PROVIDE(kc_data_begin = .);
+ *(.rodata)
+ *(.data)
+ }
+
+ .data.rel :
+ {
+ *(.data.rel)
+ *(.data.rel.*)
+ }
+
+ .bss :
+ {
+ *(.bss)
+ PROVIDE(kc_data_end = .);
+ }
+
+ /DISCARD/ :
+ {
+ *(.eh_frame)
+ *(.comment)
+ }
+}
+
diff --git a/lib/elf.c b/lib/elf.c
deleted file mode 100644
index 551a5a5..0000000
--- a/lib/elf.c
+++ /dev/null
@@ -1,106 +0,0 @@
-#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/elf64.c b/lib/elf64.c
new file mode 100644
index 0000000..2dee395
--- /dev/null
+++ b/lib/elf64.c
@@ -0,0 +1,45 @@
+#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_offset + phdrs[i].p_memsz > size)
+ {
+ size = phdrs[i].p_offset + phdrs[i].p_memsz;
+ if (phdrs[i].p_align > 1)
+ {
+ size = (size + phdrs[i].p_align - 1) &
+ ~(phdrs[i].p_align - 1);
+ }
+ }
+ }
+
+ return size;
+}
+
diff --git a/lib/entry_x86_64.S b/lib/entry_x86_64.S
new file mode 100644
index 0000000..231953a
--- /dev/null
+++ b/lib/entry_x86_64.S
@@ -0,0 +1,18 @@
+.section .text.start
+.extern kc_reloc
+.extern kc_main
+.extern _DYNAMIC
+.extern kc_image_base
+
+.global kc_entry
+.type kc_entry, @function
+kc_entry:
+ push %rdi
+ lea _DYNAMIC(%rip), %rdi
+ lea kc_image_base(%rip), %rsi
+ call kc_reloc
+ pop %rdi
+ call kc_main
+ ret
+.size kc_entry, . - kc_entry
+
diff --git a/lib/reloc_x86_64.c b/lib/reloc_x86_64.c
new file mode 100644
index 0000000..0204700
--- /dev/null
+++ b/lib/reloc_x86_64.c
@@ -0,0 +1,69 @@
+#include <kernel/component.h>
+
+#include <elf/elf64.h>
+
+#include <stddef.h>
+
+#define STARTCODE __attribute__((section(".text.start")))
+
+STARTCODE
+static void do_rela(Elf64_Rela *rela, void *base)
+{
+ union
+ {
+ Elf_Byte word8;
+ Elf64_Half word16;
+ Elf64_Word word32;
+ Elf64_Xword word64;
+ }
+ *fixup;
+
+ switch (ELF64_R_TYPE(rela->r_info))
+ {
+ case R_AMD64_RELATIVE:
+ fixup = (void *)(rela->r_offset + (uintptr_t)base);
+ fixup->word64 = (rela->r_addend + (uintptr_t)base);
+ break;
+ default:
+ break;
+ }
+}
+
+STARTCODE
+void kc_reloc(Elf64_Dyn *dyn, void *base)
+{
+ 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++)
+ {
+ do_rela(&rela.entries[i], base);
+ }
+}
+