From fc00c656c96528112d05cf0edf8631bd5eaea446 Mon Sep 17 00:00:00 2001 From: Kacper Date: Sun, 7 Dec 2025 20:10:31 +0100 Subject: Add build system scaffolding and libc headers --- lib/libc/arch/Kbuild | 1 + lib/libc/arch/x86_64/Kbuild | 7 +++ lib/libc/arch/x86_64/clock_gettime.c | 13 +++++ lib/libc/arch/x86_64/crt0.c | 59 ++++++++++++++++++++++ lib/libc/arch/x86_64/fenv.s | 97 ++++++++++++++++++++++++++++++++++++ lib/libc/arch/x86_64/longjmp.c | 18 +++++++ lib/libc/arch/x86_64/setjmp.c | 17 +++++++ lib/libc/arch/x86_64/sigsetjmp.c | 33 ++++++++++++ lib/libc/arch/x86_64/vdso_setup.c | 62 +++++++++++++++++++++++ 9 files changed, 307 insertions(+) create mode 100644 lib/libc/arch/Kbuild create mode 100644 lib/libc/arch/x86_64/Kbuild create mode 100644 lib/libc/arch/x86_64/clock_gettime.c create mode 100644 lib/libc/arch/x86_64/crt0.c create mode 100644 lib/libc/arch/x86_64/fenv.s create mode 100644 lib/libc/arch/x86_64/longjmp.c create mode 100644 lib/libc/arch/x86_64/setjmp.c create mode 100644 lib/libc/arch/x86_64/sigsetjmp.c create mode 100644 lib/libc/arch/x86_64/vdso_setup.c (limited to 'lib/libc/arch') diff --git a/lib/libc/arch/Kbuild b/lib/libc/arch/Kbuild new file mode 100644 index 00000000..ad3a7486 --- /dev/null +++ b/lib/libc/arch/Kbuild @@ -0,0 +1 @@ +obj-y += $(ARCH)/ diff --git a/lib/libc/arch/x86_64/Kbuild b/lib/libc/arch/x86_64/Kbuild new file mode 100644 index 00000000..fc8a2d3f --- /dev/null +++ b/lib/libc/arch/x86_64/Kbuild @@ -0,0 +1,7 @@ +obj-y += clock_gettime.o +obj-y += crt0.o +obj-y += fenv.o +obj-y += longjmp.o +obj-y += setjmp.o +obj-y += sigsetjmp.o +obj-y += vdso_setup.o diff --git a/lib/libc/arch/x86_64/clock_gettime.c b/lib/libc/arch/x86_64/clock_gettime.c new file mode 100644 index 00000000..6a7a3874 --- /dev/null +++ b/lib/libc/arch/x86_64/clock_gettime.c @@ -0,0 +1,13 @@ +#include +#include +#include + +int clock_gettime(clockid_t clock_id, struct timespec *tp) +{ +#if defined(__x86_64__) + if (__vdso_clock_gettime) + return __vdso_clock_gettime(clock_id, tp); +#endif + + return syscall(clock_gettime, clock_id, tp); +} diff --git a/lib/libc/arch/x86_64/crt0.c b/lib/libc/arch/x86_64/crt0.c new file mode 100644 index 00000000..2c7943ff --- /dev/null +++ b/lib/libc/arch/x86_64/crt0.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include +#include + +#define weak_reference(old, new) \ + extern __typeof(old) new __attribute__((__weak__, __alias__(#old))) + +extern int main(int, char *[]); +char **environ; + +static struct __thread_self thread = { .tid = 0, ._errno = 0 }; + +struct __attribute__((packed)) auxv_t { + uintptr_t a_type; + uintptr_t a_val; +} *__auxv; + +static void __vdso_setup(Elf64_Ehdr *vdso_addr __attribute__((unused))) +{ +} + +weak_reference(__vdso_setup, vdso_setup); + +__attribute__((used)) void __libc_start(uintptr_t *sp) +{ + char **argv; + int argc; + + argc = (int)(*sp); + argv = (char **)(++sp); + sp += argc; + environ = (char **)(++sp); + + while (*sp) + sp++; + + __auxv = (struct auxv_t *)(++sp); + while (__auxv->a_type != AT_NULL) { + if (__auxv->a_type == AT_SYSINFO_EHDR) { + vdso_setup((Elf64_Ehdr *)__auxv->a_val); + } + + __auxv++; + } + + __asm__ volatile("wrfsbase %0" ::"r"(thread)); + + exit(main(argc, argv)); +} + +__attribute__((noreturn, naked)) void _start(void) +{ + __asm__ __volatile__("mov %rsp, %rdi\n" + "call __libc_start\n"); +} diff --git a/lib/libc/arch/x86_64/fenv.s b/lib/libc/arch/x86_64/fenv.s new file mode 100644 index 00000000..b9a46581 --- /dev/null +++ b/lib/libc/arch/x86_64/fenv.s @@ -0,0 +1,97 @@ +.global feclearexcept +.type feclearexcept,@function +feclearexcept: + mov %edi,%ecx + and $0x3f,%ecx + fnstsw %ax + test %eax,%ecx + jz 1f + fnclex +1: stmxcsr -8(%rsp) + and $0x3f,%eax + or %eax,-8(%rsp) + test %ecx,-8(%rsp) + jz 1f + not %ecx + and %ecx,-8(%rsp) + ldmxcsr -8(%rsp) +1: xor %eax,%eax + ret + +.global feraiseexcept +.type feraiseexcept,@function +feraiseexcept: + and $0x3f,%edi + stmxcsr -8(%rsp) + or %edi,-8(%rsp) + ldmxcsr -8(%rsp) + xor %eax,%eax + ret + +.global __fesetround +.hidden __fesetround +.type __fesetround,@function +__fesetround: + push %rax + xor %eax,%eax + mov %edi,%ecx + fnstcw (%rsp) + andb $0xf3,1(%rsp) + or %ch,1(%rsp) + fldcw (%rsp) + stmxcsr (%rsp) + shl $3,%ch + andb $0x9f,1(%rsp) + or %ch,1(%rsp) + ldmxcsr (%rsp) + pop %rcx + ret + +.global fegetround +.type fegetround,@function +fegetround: + push %rax + stmxcsr (%rsp) + pop %rax + shr $3,%eax + and $0xc00,%eax + ret + +.global fegetenv +.type fegetenv,@function +fegetenv: + xor %eax,%eax + fnstenv (%rdi) + stmxcsr 28(%rdi) + ret + +.global fesetenv +.type fesetenv,@function +fesetenv: + xor %eax,%eax + inc %rdi + jz 1f + fldenv -1(%rdi) + ldmxcsr 27(%rdi) + ret +1: push %rax + push %rax + pushq $0xffff + pushq $0x37f + fldenv (%rsp) + pushq $0x1f80 + ldmxcsr (%rsp) + add $40,%rsp + ret + +.global fetestexcept +.type fetestexcept,@function +fetestexcept: + and $0x3f,%edi + push %rax + stmxcsr (%rsp) + pop %rsi + fnstsw %ax + or %esi,%eax + and %edi,%eax + ret diff --git a/lib/libc/arch/x86_64/longjmp.c b/lib/libc/arch/x86_64/longjmp.c new file mode 100644 index 00000000..6aed69a5 --- /dev/null +++ b/lib/libc/arch/x86_64/longjmp.c @@ -0,0 +1,18 @@ +#include + +__attribute__((noreturn, naked, returns_twice)) void longjmp(jmp_buf env, + int val) +{ + __asm__ __volatile__("mov 0(%rdi), %rbx\n" + "mov 8(%rdi), %rbp\n" + "mov 16(%rdi), %r12\n" + "mov 24(%rdi), %r13\n" + "mov 32(%rdi), %r14\n" + "mov 40(%rdi), %r15\n" + "mov 48(%rdi), %rsp\n" + "xor %rax, %rax\n" + "cmp $0, %esi\n" + "setne %al\n" + "mov %eax, %eax\n" + "jmp *56(%rdi)\n"); +} diff --git a/lib/libc/arch/x86_64/setjmp.c b/lib/libc/arch/x86_64/setjmp.c new file mode 100644 index 00000000..d268ae25 --- /dev/null +++ b/lib/libc/arch/x86_64/setjmp.c @@ -0,0 +1,17 @@ +#include + +__attribute__((naked, returns_twice)) int setjmp(jmp_buf env) +{ + __asm__ __volatile__("mov %rbx,(%rdi)\n" + "mov %rbp,8(%rdi)\n" + "mov %r12,16(%rdi)\n" + "mov %r13,24(%rdi)\n" + "mov %r14,32(%rdi)\n" + "mov %r15,40(%rdi)\n" + "lea 8(%rsp),%rdx\n" + "mov %rdx,48(%rdi)\n" + "mov (%rsp),%rdx\n" + "mov %rdx,56(%rdi)\n" + "xor %eax,%eax\n" + "ret\n"); +} diff --git a/lib/libc/arch/x86_64/sigsetjmp.c b/lib/libc/arch/x86_64/sigsetjmp.c new file mode 100644 index 00000000..d4c0a4db --- /dev/null +++ b/lib/libc/arch/x86_64/sigsetjmp.c @@ -0,0 +1,33 @@ +#include + +int sigsetjmp(sigjmp_buf env, int savemask) +{ + __asm__ __volatile__("movq %%rbx, 0(%0)\n" + "movq %%rbp, 8(%0)\n" + "movq %%r12, 16(%0)\n" + "movq %%r13, 24(%0)\n" + "movq %%r14, 32(%0)\n" + "movq %%r15, 40(%0)\n" + + "leaq 8(%%rsp), %%rax\n" + "movq %%rax, 48(%0)\n" + "movq (%%rsp), %%rax\n" + "movq %%rax, 56(%0)\n" + + "testl %%esi, %%esi\n" + "jz 1f\n" + "movq $2, %%rdi\n" + "movq $0, %%rsi\n" + "leaq 64(%0), %%rdx\n" + "movq $128, %%r10\n" + "movq $14, %%rax\n" + "syscall\n" + + "1:\n" + "xor %%eax, %%eax\n" + : + : "r"(env), "S"(savemask) + : "rax", "rdi", "rdx", "r10", "memory"); + + return 0; +} diff --git a/lib/libc/arch/x86_64/vdso_setup.c b/lib/libc/arch/x86_64/vdso_setup.c new file mode 100644 index 00000000..c410995d --- /dev/null +++ b/lib/libc/arch/x86_64/vdso_setup.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +int (*__vdso_clock_gettime)(int, struct timespec *) = NULL; +int (*__vdso_getcpu)(unsigned *, unsigned *, void *) = NULL; +int (*__vdso_time)(long *) = NULL; + +static __inline __attribute__((used)) void vdso_setup(Elf64_Ehdr *vdso_addr) +{ + Elf64_Phdr *phdr = + (Elf64_Phdr *)((char *)vdso_addr + vdso_addr->e_phoff); + + for (int i = 0; i < vdso_addr->e_phnum; i++) { + if (phdr[i].p_type == PT_DYNAMIC) { + Elf64_Dyn *dyn = (Elf64_Dyn *)((char *)vdso_addr + + phdr[i].p_offset); + const char *strtab = NULL; + Elf64_Sym *symtab = NULL; + for (; dyn->d_tag != DT_NULL; dyn++) { + if (dyn->d_tag == DT_STRTAB) { + strtab = (const char *)vdso_addr + + dyn->d_un.d_ptr; + } else if (dyn->d_tag == DT_SYMTAB) { + symtab = + (Elf64_Sym *)((char *)vdso_addr + + dyn->d_un.d_ptr); + } + } + + if (strtab == NULL || symtab == NULL) { + return; + } + + Elf64_Sym *sym = symtab; + while ((char *)sym < (char *)strtab) { + if (sym->st_name != 0 && sym->st_value != 0) { + const char *name = + strtab + sym->st_name; + if (strcmp(name, + "__vdso_clock_gettime") == 0) + __vdso_clock_gettime = + (void *)(vdso_addr + + sym->st_value); + else if (strcmp(name, + "__vdso_getcpu") == 0) + __vdso_getcpu = + (void *)(vdso_addr + + sym->st_value); + else if (strcmp(name, "__vdso_time") == + 0) + __vdso_time = + (void *)(vdso_addr + + sym->st_value); + } + sym = (Elf64_Sym *)((char *)sym + + sizeof(Elf64_Sym)); + } + } + } +} -- cgit v1.2.3