summaryrefslogtreecommitdiff
path: root/lib/libc/internal/arch/x86_64
diff options
context:
space:
mode:
authorKacper <kacper@mail.openlinux.dev>2025-12-16 17:02:05 +0100
committerKacper <kacper@mail.openlinux.dev>2025-12-16 17:02:05 +0100
commit90dad97fc07f049383903a166631e2c257f9b8c1 (patch)
tree096cd247ecfda9e46598215a4f32aecedeedda90 /lib/libc/internal/arch/x86_64
parent0e832a9329cc4d4647e1ce529846073f21e66991 (diff)
Add support for TLS in the libc
Diffstat (limited to 'lib/libc/internal/arch/x86_64')
-rw-r--r--lib/libc/internal/arch/x86_64/Kbuild5
-rw-r--r--lib/libc/internal/arch/x86_64/_start.c8
-rw-r--r--lib/libc/internal/arch/x86_64/fenv.s97
-rw-r--r--lib/libc/internal/arch/x86_64/longjmp.c20
-rw-r--r--lib/libc/internal/arch/x86_64/setjmp.c19
-rw-r--r--lib/libc/internal/arch/x86_64/sigsetjmp.c33
6 files changed, 182 insertions, 0 deletions
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 <libc.h>
+#include <sys/cdefs.h>
+
+__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 <setjmp.h> // 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 <setjmp.h> // 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 <setjmp.h> // 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;
+}