From 90dad97fc07f049383903a166631e2c257f9b8c1 Mon Sep 17 00:00:00 2001 From: Kacper Date: Tue, 16 Dec 2025 17:02:05 +0100 Subject: Add support for TLS in the libc --- lib/libc/internal/arch/x86_64/Kbuild | 5 ++ lib/libc/internal/arch/x86_64/_start.c | 8 +++ lib/libc/internal/arch/x86_64/fenv.s | 97 +++++++++++++++++++++++++++++++ lib/libc/internal/arch/x86_64/longjmp.c | 20 +++++++ lib/libc/internal/arch/x86_64/setjmp.c | 19 ++++++ lib/libc/internal/arch/x86_64/sigsetjmp.c | 33 +++++++++++ 6 files changed, 182 insertions(+) create mode 100644 lib/libc/internal/arch/x86_64/Kbuild create mode 100644 lib/libc/internal/arch/x86_64/_start.c create mode 100644 lib/libc/internal/arch/x86_64/fenv.s create mode 100644 lib/libc/internal/arch/x86_64/longjmp.c create mode 100644 lib/libc/internal/arch/x86_64/setjmp.c create mode 100644 lib/libc/internal/arch/x86_64/sigsetjmp.c (limited to 'lib/libc/internal/arch/x86_64') diff --git a/lib/libc/internal/arch/x86_64/Kbuild b/lib/libc/internal/arch/x86_64/Kbuild new file mode 100644 index 00000000..830a1c5b --- /dev/null +++ b/lib/libc/internal/arch/x86_64/Kbuild @@ -0,0 +1,5 @@ +obj-y += _start.o +obj-y += fenv.o +obj-y += longjmp.o +obj-y += setjmp.o +obj-y += sigsetjmp.o diff --git a/lib/libc/internal/arch/x86_64/_start.c b/lib/libc/internal/arch/x86_64/_start.c new file mode 100644 index 00000000..f3f4fef2 --- /dev/null +++ b/lib/libc/internal/arch/x86_64/_start.c @@ -0,0 +1,8 @@ +#include +#include + +__dead __naked void _start(void) +{ + __asm__ __volatile__("mov %rsp, %rdi\n" + "call __init\n"); +} diff --git a/lib/libc/internal/arch/x86_64/fenv.s b/lib/libc/internal/arch/x86_64/fenv.s new file mode 100644 index 00000000..b9a46581 --- /dev/null +++ b/lib/libc/internal/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/internal/arch/x86_64/longjmp.c b/lib/libc/internal/arch/x86_64/longjmp.c new file mode 100644 index 00000000..dbd18632 --- /dev/null +++ b/lib/libc/internal/arch/x86_64/longjmp.c @@ -0,0 +1,20 @@ +#include "bits/setjmp.h" // for jmp_buf + +#include // for longjmp + +__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/internal/arch/x86_64/setjmp.c b/lib/libc/internal/arch/x86_64/setjmp.c new file mode 100644 index 00000000..ea205e16 --- /dev/null +++ b/lib/libc/internal/arch/x86_64/setjmp.c @@ -0,0 +1,19 @@ +#include "bits/setjmp.h" // for jmp_buf + +#include // for setjmp + +__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/internal/arch/x86_64/sigsetjmp.c b/lib/libc/internal/arch/x86_64/sigsetjmp.c new file mode 100644 index 00000000..2d900ce7 --- /dev/null +++ b/lib/libc/internal/arch/x86_64/sigsetjmp.c @@ -0,0 +1,33 @@ +#include // for sigsetjmp, sigjmp_buf + +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; +} -- cgit v1.2.3