From aec58be40927ec0b2a0e6742396f880d52ce38b5 Mon Sep 17 00:00:00 2001 From: Ada Christine Date: Thu, 22 Feb 2024 20:05:51 +0000 Subject: kjarna runtime --- api/elf/elf.h | 1 + api/lib/elf.h | 2 + api/libc/string.h | 1 + kc/defaults.mk | 1 - kjarna/efi/image.c | 2 +- kjarna/efi/start.c | 3 ++ kjarna_runtime/Makefile | 36 +++++++++++++++ kjarna_runtime/dynamic_x86_64.c | 81 ++++++++++++++++++++++++++++++++++ kjarna_runtime/kc.h | 45 +++++++++++++++++++ kjarna_runtime/kc.ld | 97 +++++++++++++++++++++++++++++++++++++++++ kjarna_runtime/kc_main.c | 26 +++++++++++ kjarna_runtime/reloc_x86_64.c | 42 ++++++++++++++++++ kjarna_runtime/start_x86_64.S | 57 ++++++++++++++++++++++++ lib/elf64.c | 67 +++++++++++++++++++++------- lib/string.c | 10 ++++- 15 files changed, 452 insertions(+), 19 deletions(-) create mode 100644 kjarna_runtime/Makefile create mode 100644 kjarna_runtime/dynamic_x86_64.c create mode 100644 kjarna_runtime/kc.h create mode 100644 kjarna_runtime/kc.ld create mode 100644 kjarna_runtime/kc_main.c create mode 100644 kjarna_runtime/reloc_x86_64.c create mode 100644 kjarna_runtime/start_x86_64.S diff --git a/api/elf/elf.h b/api/elf/elf.h index 209c219..b5a136a 100644 --- a/api/elf/elf.h +++ b/api/elf/elf.h @@ -81,4 +81,5 @@ typedef uint8_t Elf_Byte; #define DT_STRSZ 10 #define DT_SYMENT 11 #define DT_JMPREL 0x17 +#define DT_PLTREL 20 diff --git a/api/lib/elf.h b/api/lib/elf.h index 05d25bc..951fc25 100644 --- a/api/lib/elf.h +++ b/api/lib/elf.h @@ -12,4 +12,6 @@ bool elf64_validate(Elf64_Ehdr *ehdr, unsigned type, unsigned machine); size_t elf64_size(Elf64_Ehdr *ehdr, Elf64_Phdr *phdr); +void *elf64_dt_ptr(void *base, Elf64_Dyn *dyntab, unsigned long dt_type); +uintptr_t elf64_dt_val(Elf64_Dyn *dyntab, unsigned long dt_type); diff --git a/api/libc/string.h b/api/libc/string.h index d1d45d5..849275d 100644 --- a/api/libc/string.h +++ b/api/libc/string.h @@ -7,5 +7,6 @@ void *memmove(void *dest, const void *src, size_t size); void *memset(void *dest, int val, size_t size); int memcmp(const void *str1, const void *str2, size_t count); size_t strlen(const char *s); +int strcmp(const char *s1, const char *s2); unsigned long long strtoull(const char *restrict begin, char **restrict end, int base); diff --git a/kc/defaults.mk b/kc/defaults.mk index db0d18c..e44781b 100644 --- a/kc/defaults.mk +++ b/kc/defaults.mk @@ -1,5 +1,4 @@ -LDSCRIPT := ../kc.ld CFLAGS += -fPIC -fvisibility=hidden -mgeneral-regs-only diff --git a/kjarna/efi/image.c b/kjarna/efi/image.c index 8af9cfd..c26b588 100644 --- a/kjarna/efi/image.c +++ b/kjarna/efi/image.c @@ -89,7 +89,7 @@ static ssize_t load_segments(int fd, Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs, char * static struct image_buffer load_image(void) { - const char *image_entry_path = "\\adasoft\\sophia\\efi.os"; + const char *image_entry_path = "\\adasoft\\sophia\\kjarna.os"; int image_fd; diff --git a/kjarna/efi/start.c b/kjarna/efi/start.c index 4a10541..ebeb67d 100644 --- a/kjarna/efi/start.c +++ b/kjarna/efi/start.c @@ -19,11 +19,14 @@ EFI_STATUS _start(EFI_HANDLE handle, EFI_SYSTEM_TABLE *system_table) struct efi_context app_context = { handle, system_table }; efi_context = &app_context; + efi_write(1, "hello, efi world!\r\n", -1); + if (main(0, nullptr) != 0) { efi_errno = EFI_ABORTED; } + return _exit(efi_errno); } diff --git a/kjarna_runtime/Makefile b/kjarna_runtime/Makefile new file mode 100644 index 0000000..568beba --- /dev/null +++ b/kjarna_runtime/Makefile @@ -0,0 +1,36 @@ +include ../defaults.mk + +LDFLAGS += -z max-page-size=4096 --export-dynamic -pic \ + -z separate-code -pie -Bsymbolic -shared \ + -z noexecstack -g + +VPATH := ../lib + +TARGET := kjarna.os +.DEFAULT: $(TARGET) + +CPPFLAGS += -I../api -I. + +CFLAGS += -fPIC -fvisibility=hidden -mgeneral-regs-only + +LDSCRIPT := kc.ld + +CRT_OBJS := start_x86_64.o reloc_x86_64.o dynamic_x86_64.o elf64.o +LIB_OBJS := memcmp.o memcpy.o memmove.o memset.o string.o +APP_OBJS := kc_main.o + +OBJS := $(CRT_OBJS) $(LIB_OBJS) $(APP_OBJS) + +DEPS := $(patsubst %.o,%.d,$(OBJS)) + +$(TARGET): $(LDSCRIPT) $(MAKEFILE_LIST) +$(TARGET): $(OBJS) + +CLEANLIST := $(wildcard $(OBJS) $(TARGET)) +DCLEANLIST := $(wildcard $(DEPS)) + +include ../rules.mk +-include $(DEPS) + +.DEFAULT: $(TARGET) + diff --git a/kjarna_runtime/dynamic_x86_64.c b/kjarna_runtime/dynamic_x86_64.c new file mode 100644 index 0000000..e49f13d --- /dev/null +++ b/kjarna_runtime/dynamic_x86_64.c @@ -0,0 +1,81 @@ +#include + +#include +#include + +extern void _rtld_link(void); + +struct elf64_relatab +{ + Elf64_Rela *entries; + size_t size; + size_t entsize; +}; + +struct elf64_symtab +{ + Elf64_Sym *entries; + const char *strings; + size_t strsize; +}; + +struct elf64_dso_info +{ + char *base; + struct elf64_relatab jmprel; + struct elf64_relatab reladyn; + struct elf64_symtab dynsym; + Elf64_Addr *pltgot; +}; + +static struct elf64_dso_info dso_info; + +void kc_dynamic_init(char *base, Elf64_Dyn *dyn) +{ + dso_info = (struct elf64_dso_info) + { + base, + { + elf64_dt_ptr(base, dyn, DT_JMPREL), + elf64_dt_val(dyn, DT_PLTRELSZ), + elf64_dt_val(dyn, DT_PLTREL) == DT_RELA ? sizeof(Elf64_Rela) : -1 + }, + { + elf64_dt_ptr(base, dyn, DT_RELA), + elf64_dt_val(dyn, DT_RELASZ), + elf64_dt_val(dyn, DT_RELAENT) + }, + { + elf64_dt_ptr(base, dyn, DT_SYMTAB), + elf64_dt_ptr(base, dyn, DT_STRTAB), + elf64_dt_val(dyn, DT_STRSZ) + }, + elf64_dt_ptr(base, dyn, DT_PLTGOT) + }; + + if (dso_info.pltgot != nullptr) + { + dso_info.pltgot[1] = (uintptr_t)&dso_info; + dso_info.pltgot[2] = (uintptr_t)_rtld_link; + } + + kc_reloc(dso_info.base, dso_info.reladyn.entries, dso_info.reladyn.size, dso_info.reladyn.entsize); + kc_reloc(dso_info.base, dso_info.jmprel.entries, dso_info.jmprel.size, dso_info.jmprel.entsize); +} + +void *kc_dynamic_link(struct elf64_dso_info *dso, int index) +{ + int symindex = ELF64_R_SYM(dso->jmprel.entries[index].r_info); + int strindex = dso->dynsym.entries[symindex].st_name; + const char *name = &dso->dynsym.strings[strindex]; + uintptr_t *fixup = (uintptr_t *)dso->base + dso->jmprel.entries[index].r_offset; + + if (strcmp(name, "write") == 0) + { + *fixup = (uintptr_t)*entry_params->interface->write; + return fixup; + } + + return nullptr; +} + diff --git a/kjarna_runtime/kc.h b/kjarna_runtime/kc.h new file mode 100644 index 0000000..842d7be --- /dev/null +++ b/kjarna_runtime/kc.h @@ -0,0 +1,45 @@ +#pragma once + +#ifndef __ASSEMBLER__ + +#include + +#include + +#include + +extern struct kjarna_entry_params *entry_params; + +#define KC_EXPORT __attribute__((visibility("default"))) + +extern unsigned char kc_image_base; +extern unsigned char kc_text_begin; +extern unsigned char kc_text_end; +extern unsigned char kc_rodata_begin; +extern unsigned char kc_data_begin; +extern unsigned char kc_data_end; +extern unsigned char kc_image_end; + +struct elf64_dso_info; + +extern void kc_dynamic_init(char *base, Elf64_Dyn *dyn); +extern void *kc_dynamic_link(struct elf64_dso_info *dso, int index); +extern void kc_reloc(void *base, Elf64_Rela *entries, size_t size, size_t entsize); + +#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 +.extern kc_dynamic_link + +#endif // __ASSEMBLER__ + diff --git a/kjarna_runtime/kc.ld b/kjarna_runtime/kc.ld new file mode 100644 index 0000000..f7b0339 --- /dev/null +++ b/kjarna_runtime/kc.ld @@ -0,0 +1,97 @@ +ENTRY(_start) + +SECTIONS +{ + PROVIDE_HIDDEN(kc_image_base = .); + + . = SIZEOF_HEADERS; + + .rela.plt : + { + *(.rela.plt) + } + + .rela.dyn : + { + *(.rela.dyn) + } + + .hash : + { + *(.hash) + } + + .dynsym : + { + *(.dynsym) + } + + .dynstr : + { + *(.dynstr) + } + + .rodata : + { + *(.rodata) + *(.rodata.*) + } + + .text : ALIGN(4K) + { + 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 : + { + *(.data) + } + + .data.rel : + { + *(.data.rel) + *(.data.rel.*) + } + + .bss : + { + *(.bss) + *(.dynbss) + . = ALIGN(4K); + PROVIDE_HIDDEN(kc_data_end = .); + } + + PROVIDE_HIDDEN(kc_image_end = .); + + /DISCARD/ : + { + *(.eh_frame) + *(.comment) + } +} + diff --git a/kjarna_runtime/kc_main.c b/kjarna_runtime/kc_main.c new file mode 100644 index 0000000..acfcdc1 --- /dev/null +++ b/kjarna_runtime/kc_main.c @@ -0,0 +1,26 @@ +#include + +extern int write(int, void *, size_t); + +int main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + write(1, "hello, runtime world!\r\n", -1); + + while (1); + + return 0; +} + +struct kjarna_entry_params *entry_params; + +int kjarna_entry(struct kjarna_entry_params *params) +{ + entry_params = params; + entry_params->interface->write(1, "hello, entry world\r\n", -1); + + return main(params->argc, params->argv); +} + diff --git a/kjarna_runtime/reloc_x86_64.c b/kjarna_runtime/reloc_x86_64.c new file mode 100644 index 0000000..63dc6e7 --- /dev/null +++ b/kjarna_runtime/reloc_x86_64.c @@ -0,0 +1,42 @@ +#include + +#define STARTCODE __attribute__((section(".text.start"))) + +STARTCODE +static void do_rela(void *base, Elf64_Rela *rela) +{ + union + { + Elf_Byte word8; + Elf64_Half word16; + Elf64_Word word32; + Elf64_Xword word64; + } + *fixup; + + switch (ELF64_R_TYPE(rela->r_info)) + { + 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; + default: + break; + } +} + +STARTCODE +void kc_reloc(void *base, Elf64_Rela *entries, size_t size, size_t entsize) +{ + // perform the actual relocation + + for (size_t i = 0; entries && (i < size / entsize); i++) + { + do_rela(base, &entries[i]); + } +} + diff --git a/kjarna_runtime/start_x86_64.S b/kjarna_runtime/start_x86_64.S new file mode 100644 index 0000000..f7725c6 --- /dev/null +++ b/kjarna_runtime/start_x86_64.S @@ -0,0 +1,57 @@ +#include + +.section .text.start + +.extern kjarna_entry + +.hidden _start +.global _start +.type _start, @function +_start: + push %rbp + push %rdi + push %rsi + mov %rsp, %rbp + and $-0x10, %rsp + lea kc_image_base(%rip), %rdi + lea _DYNAMIC(%rip), %rsi + call kc_dynamic_init + mov %rbp, %rsp + pop %rsi + pop %rdi + mov %rsp, %rbp + and $-0x10, %rsp + call kjarna_entry + mov %rbp, %rsp + pop %rbp + ret +.size _start, . - _start + +.section .text + +.hidden _rtld_link +.global _rtld_link +.type _rtld_link, @function +_rtld_link: + push %rbp + mov %rsp, %rbp + push %rdx + push %rsi + push %rdi + mov 8(%rbp), %rdi + mov 16(%rbp), %rsi + push %rbp + mov %rsp, %rbp + and $-0x10, %rsp + call kc_dynamic_link + mov %rbp, %rsp + pop %rbp + pop %rdi + pop %rsi + pop %rdx + mov %rbp, %rsp + pop %rbp + add $0x10, %rsp + jmp *(%rax) +.size _rtld_link, . - _rtld_link + diff --git a/lib/elf64.c b/lib/elf64.c index bae408a..e880179 100644 --- a/lib/elf64.c +++ b/lib/elf64.c @@ -3,15 +3,15 @@ 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) + 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; } @@ -30,17 +30,52 @@ size_t elf64_size(Elf64_Ehdr *ehdr, Elf64_Phdr *phdrs) 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 = 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); - } + size = (size + phdrs[i].p_align - 1) & ~(phdrs[i].p_align - 1); } } return size; } +static Elf64_Dyn *get_dynent(Elf64_Dyn *dyntab, unsigned long dt_type) +{ + while (dyntab && dyntab->d_tag != DT_NULL) + { + if (dyntab->d_tag == dt_type) + { + return dyntab; + } + + dyntab++; + } + + return nullptr; +} + +void *elf64_dt_ptr(void *base, Elf64_Dyn *dyntab, unsigned long dt_type) +{ + Elf64_Dyn *dynent = get_dynent(dyntab, dt_type); + + if (dynent == nullptr) + { + return nullptr; + } + + return dynent->d_ptr + (char *)base; +} + +uintptr_t elf64_dt_val(Elf64_Dyn *dyntab, unsigned long dt_type) +{ + Elf64_Dyn *dynent = get_dynent(dyntab, dt_type); + + if (dynent == nullptr) + { + return (uintptr_t)-1; + } + + return dynent->d_val; +} + diff --git a/lib/string.c b/lib/string.c index 315fa1e..2da2070 100644 --- a/lib/string.c +++ b/lib/string.c @@ -1,6 +1,14 @@ -#include +#include #include +int strcmp(const char *s1, const char *s2) +{ + size_t s1len = strlen(s1); + size_t s2len = strlen(s2); + + return memcmp(s1, s2, s1len < s2len ? s1len : s2len); +} + size_t strlen(const char *s) { size_t l = 0; -- cgit v1.3.1-1-g115d