diff --git a/generic-rt/src/lib.rs b/generic-rt/src/lib.rs
index 97e277a0453e5f179d88b335a64fbeb5d52c891a..2999115c36508d048c38ec8bfb850c8be96b59f3 100644
--- a/generic-rt/src/lib.rs
+++ b/generic-rt/src/lib.rs
@@ -1,4 +1,5 @@
 #![no_std]
+#![feature(core_intrinsics)]
 
 use core::arch::asm;
 use core::mem::{self, offset_of};
@@ -70,4 +71,42 @@ impl<Os> GenericTcb<Os> {
             Some(tcb_ptr)
         }
     }
+    pub unsafe fn current() -> Option<&'static mut Self> {
+        Some(&mut *Self::current_ptr()?)
+    }
+}
+pub fn panic_notls(msg: impl core::fmt::Display) -> ! {
+    //eprintln!("panicked in ld.so: {}", msg);
+
+    core::intrinsics::abort();
+}
+
+pub trait ExpectTlsFree {
+    type Unwrapped;
+
+    fn expect_notls(self, msg: &str) -> Self::Unwrapped;
 }
+impl<T, E: core::fmt::Debug> ExpectTlsFree for Result<T, E> {
+    type Unwrapped = T;
+
+    fn expect_notls(self, msg: &str) -> T {
+        match self {
+            Ok(t) => t,
+            Err(err) => panic_notls(format_args!(
+                "{}: expect failed for Result with err: {:?}",
+                msg, err
+            )),
+        }
+    }
+}
+impl<T> ExpectTlsFree for Option<T> {
+    type Unwrapped = T;
+
+    fn expect_notls(self, msg: &str) -> T {
+        match self {
+            Some(t) => t,
+            None => panic_notls(format_args!("{}: expect failed for Option", msg)),
+        }
+    }
+}
+
diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs
index de94685416ba6384020d1b245d737ffc14e9fb14..c1a11cd278e89760d09d9adef203c81e6c163372 100644
--- a/redox-rt/src/arch/x86_64.rs
+++ b/redox-rt/src/arch/x86_64.rs
@@ -16,6 +16,7 @@ pub struct SigArea {
     altstack_top: usize,
     altstack_bottom: usize,
     tmp: usize,
+    pub disable_signals_depth: u64,
 }
 
 /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
@@ -145,10 +146,10 @@ asmfunction!(__relibc_internal_sigentry: ["
     //
     // Now that we have a stack, we can finally start initializing the signal stack!
 
-    push ss
+    push 0 // SS
     push [rax + {tcb_sc_off} + {sc_saved_rsp}]
     push [rax + {tcb_sc_off} + {sc_saved_rflags}]
-    push cs
+    push 0 // CS
     push [rax + {tcb_sc_off} + {sc_saved_rip}]
 
     push rdi
@@ -176,7 +177,7 @@ asmfunction!(__relibc_internal_sigentry: ["
     rep stosb
 
     // TODO: self-modifying?
-    cmp byte ptr [{supports_xsave}], 0
+    cmp byte ptr [rip + {supports_xsave}], 0
     je 3f
 
     mov eax, 0xffffffff
@@ -208,11 +209,11 @@ asmfunction!(__relibc_internal_sigentry: ["
     pop rsi
     pop rdi
 
-    pop gs:[{tcb_sa_off} + {sa_tmp}]
+    pop qword ptr gs:[{tcb_sa_off} + {sa_tmp}]
     add rsp, 8
     popfq
     pop rsp
-    jmp gs:[{tcb_sa_off} + {sa_tmp}]
+    jmp qword ptr gs:[{tcb_sa_off} + {sa_tmp}]
 3:
     fxsave64 [rsp]
 
diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs
index 84c7eac9eb3ee8c6edf906dfaec9741e32218100..2d06cc8ec3300a0649174deb69f2488e2bd4b760 100644
--- a/redox-rt/src/lib.rs
+++ b/redox-rt/src/lib.rs
@@ -1,8 +1,8 @@
 #![no_std]
-#![feature(asm_const, array_chunks, int_roundings, let_chains, slice_ptr_get, sync_unsafe_cell, thread_local)]
+#![feature(asm_const, array_chunks, int_roundings, let_chains, slice_ptr_get, sync_unsafe_cell)]
 #![forbid(unreachable_patterns)]
 
-use generic_rt::GenericTcb;
+use generic_rt::{ExpectTlsFree, GenericTcb};
 
 use self::signal::RtSigarea;
 
@@ -39,3 +39,75 @@ pub mod sync;
 pub mod thread;
 
 pub type Tcb = GenericTcb<RtSigarea>;
+
+/// OS and architecture specific code to activate TLS - Redox aarch64
+#[cfg(target_arch = "aarch64")]
+pub unsafe fn tcb_activate(tls_end: usize, tls_len: usize) {
+    // Uses ABI page
+    let abi_ptr = tls_end - tls_len - 16;
+    ptr::write(abi_ptr as *mut usize, tls_end);
+    asm!(
+        "msr tpidr_el0, {}",
+        in(reg) abi_ptr,
+    );
+}
+
+/// OS and architecture specific code to activate TLS - Redox x86
+#[cfg(target_arch = "x86")]
+pub unsafe fn tcb_activate(tls_end: usize, _tls_len: usize) {
+    let mut env = syscall::EnvRegisters::default();
+
+    let file = syscall::open(
+        "thisproc:current/regs/env",
+        syscall::O_CLOEXEC | syscall::O_RDWR,
+    )
+    .expect_notls("failed to open handle for process registers");
+
+    let _ = syscall::read(file, &mut env).expect_notls("failed to read gsbase");
+
+    env.gsbase = tls_end as u32;
+
+    let _ = syscall::write(file, &env).expect_notls("failed to write gsbase");
+
+    let _ = syscall::close(file);
+}
+
+/// OS and architecture specific code to activate TLS - Redox x86_64
+#[cfg(target_arch = "x86_64")]
+pub unsafe fn tcb_activate(tls_end_and_tcb_start: usize, _tls_len: usize) {
+    let mut env = syscall::EnvRegisters::default();
+
+    let file = syscall::open(
+        "thisproc:current/regs/env",
+        syscall::O_CLOEXEC | syscall::O_RDWR,
+    )
+    .expect_notls("failed to open handle for process registers");
+
+    let _ = syscall::read(file, &mut env).expect_notls("failed to read fsbase");
+
+    env.fsbase = tls_end_and_tcb_start as u64;
+
+    let _ = syscall::write(file, &env).expect_notls("failed to write fsbase");
+
+    let _ = syscall::close(file);
+}
+
+/// Initialize redox-rt in situations where relibc is not used
+pub fn initialize_freestanding() {
+    // TODO: TLS
+    let page = unsafe {
+        &mut *(syscall::fmap(!0, &syscall::Map {
+            offset: 0,
+            size: syscall::PAGE_SIZE,
+            flags: syscall::MapFlags::PROT_READ | syscall::MapFlags::PROT_WRITE | syscall::MapFlags::MAP_PRIVATE,
+            address: 0,
+        }).unwrap() as *mut Tcb)
+    };
+    page.tcb_ptr = page;
+    page.tcb_len = syscall::PAGE_SIZE;
+    page.tls_end = (page as *mut Tcb).cast();
+
+    unsafe {
+        tcb_activate(page as *mut Tcb as usize, 0)
+    }
+}
diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs
index d805f4cf3efc39a69d0a24c424e6962ddd8101f7..f1dbf58baa700a76b0b7d29bbec37def1f0bb4fe 100644
--- a/redox-rt/src/signal.rs
+++ b/redox-rt/src/signal.rs
@@ -4,7 +4,7 @@ use core::sync::atomic::{AtomicU64, Ordering};
 
 use syscall::{Error, IntRegisters, Result, SigProcControl, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGW0_TSTP_IS_STOP_BIT, SIGW0_TTIN_IS_STOP_BIT, SIGW0_TTOU_IS_STOP_BIT, SIGWINCH};
 
-use crate::arch::*;
+use crate::{arch::*, Tcb};
 use crate::sync::Mutex;
 
 #[cfg(target_arch = "x86_64")]
@@ -160,24 +160,18 @@ pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction
     todo!()
 }
 
-extern "C" {
-    pub fn __relibc_internal_get_sigcontrol_addr() -> &'static Sigcontrol;
-}
 fn current_sigctl() -> &'static Sigcontrol {
-    unsafe { __relibc_internal_get_sigcontrol_addr() }
+    &unsafe { Tcb::current() }.unwrap().os_specific.control
 }
 
 pub struct TmpDisableSignalsGuard { _inner: () }
 
-#[thread_local]
-static TMP_DISABLE_SIGNALS_DEPTH: Cell<u64> = Cell::new(0);
-
 pub fn tmp_disable_signals() -> TmpDisableSignalsGuard {
     unsafe {
-        let ctl = __relibc_internal_get_sigcontrol_addr().control_flags.get();
+        let ctl = current_sigctl().control_flags.get();
         ctl.write_volatile(ctl.read_volatile() | syscall::flag::INHIBIT_DELIVERY);
         // TODO: fence?
-        TMP_DISABLE_SIGNALS_DEPTH.set(TMP_DISABLE_SIGNALS_DEPTH.get() + 1);
+        Tcb::current().unwrap().os_specific.arch.disable_signals_depth += 1;
     }
 
     TmpDisableSignalsGuard { _inner: () }
@@ -185,11 +179,11 @@ pub fn tmp_disable_signals() -> TmpDisableSignalsGuard {
 impl Drop for TmpDisableSignalsGuard {
     fn drop(&mut self) {
         unsafe {
-            let old = TMP_DISABLE_SIGNALS_DEPTH.get();
-            TMP_DISABLE_SIGNALS_DEPTH.set(old - 1);
+            let depth = &mut Tcb::current().unwrap().os_specific.arch.disable_signals_depth;
+            *depth -= 1;
 
-            if old == 1 {
-                let ctl = __relibc_internal_get_sigcontrol_addr().control_flags.get();
+            if *depth == 0 {
+                let ctl = current_sigctl().control_flags.get();
                 ctl.write_volatile(ctl.read_volatile() & !syscall::flag::INHIBIT_DELIVERY);
             }
         }
diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs
index 809dad7ebd4e5d18aed04d30792e6cfc3df944b8..db559cb886b0998f750e17b051bba5ca510c4dc3 100644
--- a/src/ld_so/mod.rs
+++ b/src/ld_so/mod.rs
@@ -22,47 +22,14 @@ pub mod linker;
 pub mod start;
 pub mod tcb;
 
+pub use generic_rt::{panic_notls, ExpectTlsFree};
+
 static mut STATIC_TCB_MASTER: Master = Master {
     ptr: ptr::null_mut(),
     len: 0,
     offset: 0,
 };
 
-fn panic_notls(msg: impl core::fmt::Display) -> ! {
-    eprintln!("panicked in ld.so: {}", msg);
-
-    core::intrinsics::abort();
-}
-
-pub trait ExpectTlsFree {
-    type Unwrapped;
-
-    fn expect_notls(self, msg: &str) -> Self::Unwrapped;
-}
-impl<T, E: core::fmt::Debug> ExpectTlsFree for Result<T, E> {
-    type Unwrapped = T;
-
-    fn expect_notls(self, msg: &str) -> T {
-        match self {
-            Ok(t) => t,
-            Err(err) => panic_notls(format_args!(
-                "{}: expect failed for Result with err: {:?}",
-                msg, err
-            )),
-        }
-    }
-}
-impl<T> ExpectTlsFree for Option<T> {
-    type Unwrapped = T;
-
-    fn expect_notls(self, msg: &str) -> T {
-        match self {
-            Some(t) => t,
-            None => panic_notls(format_args!("{}: expect failed for Option", msg)),
-        }
-    }
-}
-
 #[inline(never)]
 pub fn static_init(sp: &'static Stack) {
     let mut phdr_opt = None;
diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs
index b2176b69896edf194e2da6f7e90dc516ce3d95e6..ae1b9eaf4c025ed2484c6cbe0a064cc95f866521 100644
--- a/src/ld_so/tcb.rs
+++ b/src/ld_so/tcb.rs
@@ -223,56 +223,9 @@ impl Tcb {
         syscall!(ARCH_PRCTL, ARCH_SET_FS, tls_end);
     }
 
-    /// OS and architecture specific code to activate TLS - Redox aarch64
-    #[cfg(all(target_os = "redox", target_arch = "aarch64"))]
+    #[cfg(all(target_os = "redox"))]
     unsafe fn os_arch_activate(tls_end: usize, tls_len: usize) {
-        // Uses ABI page
-        let abi_ptr = tls_end - tls_len - 16;
-        ptr::write(abi_ptr as *mut usize, tls_end);
-        asm!(
-            "msr tpidr_el0, {}",
-            in(reg) abi_ptr,
-        );
-    }
-
-    /// OS and architecture specific code to activate TLS - Redox x86
-    #[cfg(all(target_os = "redox", target_arch = "x86"))]
-    unsafe fn os_arch_activate(tls_end: usize, _tls_len: usize) {
-        let mut env = syscall::EnvRegisters::default();
-
-        let file = syscall::open(
-            "thisproc:current/regs/env",
-            syscall::O_CLOEXEC | syscall::O_RDWR,
-        )
-        .expect_notls("failed to open handle for process registers");
-
-        let _ = syscall::read(file, &mut env).expect_notls("failed to read gsbase");
-
-        env.gsbase = tls_end as u32;
-
-        let _ = syscall::write(file, &env).expect_notls("failed to write gsbase");
-
-        let _ = syscall::close(file);
-    }
-
-    /// OS and architecture specific code to activate TLS - Redox x86_64
-    #[cfg(all(target_os = "redox", target_arch = "x86_64"))]
-    unsafe fn os_arch_activate(tls_end: usize, _tls_len: usize) {
-        let mut env = syscall::EnvRegisters::default();
-
-        let file = syscall::open(
-            "thisproc:current/regs/env",
-            syscall::O_CLOEXEC | syscall::O_RDWR,
-        )
-        .expect_notls("failed to open handle for process registers");
-
-        let _ = syscall::read(file, &mut env).expect_notls("failed to read fsbase");
-
-        env.fsbase = tls_end as u64;
-
-        let _ = syscall::write(file, &env).expect_notls("failed to write fsbase");
-
-        let _ = syscall::close(file);
+        redox_rt::tcb_activate(tls_end, tls_len)
     }
 }