summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/elf/elf.h1
-rw-r--r--api/lib/elf.h2
-rw-r--r--api/libc/string.h1
-rw-r--r--kc/defaults.mk1
-rw-r--r--kjarna/efi/image.c2
-rw-r--r--kjarna/efi/start.c3
-rw-r--r--kjarna_runtime/Makefile36
-rw-r--r--kjarna_runtime/dynamic_x86_64.c81
-rw-r--r--kjarna_runtime/kc.h45
-rw-r--r--kjarna_runtime/kc.ld97
-rw-r--r--kjarna_runtime/kc_main.c26
-rw-r--r--kjarna_runtime/reloc_x86_64.c42
-rw-r--r--kjarna_runtime/start_x86_64.S57
-rw-r--r--lib/elf64.c67
-rw-r--r--lib/string.c10
15 files changed, 452 insertions, 19 deletions
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 <kc.h>
+
+#include <libc/string.h>
+#include <lib/elf.h>
+
+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 <elf/elf64.h>
+
+#include <stddef.h>
+
+#include <kjarna/interface.h>
+
+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 <kjarna/interface.h>
+
+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 <kc.h>
+
+#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 <kc.h>
+
+.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 <libc/string.h>
+#include <libc/string.h>
#include <stdbool.h>
+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;