diff --git a/redox-rt/src/arch/aarch64.rs b/redox-rt/src/arch/aarch64.rs
index be9afcc0ccb51b91f5a891efcb60d1f6f9175e46..fc69eec092d449b647eeb66b867019daeaa509dc 100644
--- a/redox-rt/src/arch/aarch64.rs
+++ b/redox-rt/src/arch/aarch64.rs
@@ -1,19 +1,68 @@
+use core::mem::offset_of;
+
+use syscall::data::*;
 use syscall::error::*;
 
 use crate::proc::{fork_inner, FdGuard};
-use crate::signal::inner_c;
+use crate::signal::SigStack;
+use crate::signal::{inner_c, RtSigarea, PROC_CONTROL_STRUCT};
+use crate::Tcb;
 
 // Setup a stack starting from the very end of the address space, and then growing downwards.
 pub(crate) const STACK_TOP: usize = 1 << 47;
 pub(crate) const STACK_SIZE: usize = 1024 * 1024;
 
 #[derive(Debug, Default)]
+#[repr(C)]
 pub struct SigArea {
     pub altstack_top: usize,
     pub altstack_bottom: usize,
-    pub tmp: usize,
+    pub tmp_x1_x2: [usize; 2],
+    pub tmp_x3_x4: [usize; 2],
+    pub tmp_sp: usize,
     pub onstack: u64,
     pub disable_signals_depth: u64,
+    pub pctl: usize, // TODO: remove
+}
+#[repr(C)]
+#[derive(Debug, Default)]
+pub struct ArchIntRegs {
+    pub x30: usize,
+    pub x29: usize,
+    pub x28: usize,
+    pub x27: usize,
+    pub x26: usize,
+    pub x25: usize,
+    pub x24: usize,
+    pub x23: usize,
+    pub x22: usize,
+    pub x21: usize,
+    pub x20: usize,
+    pub x19: usize,
+    pub x18: usize,
+    pub x17: usize,
+    pub x16: usize,
+    pub x15: usize,
+    pub x14: usize,
+    pub x13: usize,
+    pub x12: usize,
+    pub x11: usize,
+    pub x10: usize,
+    pub x9: usize,
+    pub x8: usize,
+    pub x7: usize,
+    pub x6: usize,
+    pub x5: usize,
+    pub x4: usize,
+    pub x3: usize,
+    pub x2: usize,
+    pub x1: usize,
+
+    pub sp: usize,
+    pub nzcv: usize, // user-accessible PSTATE bits
+
+    pub pc: usize,
+    pub x0: usize,
 }
 
 /// Deactive TLS, used before exec() on Redox to not trick target executable into thinking TLS
@@ -91,12 +140,112 @@ asmfunction!(__relibc_internal_fork_ret: ["
 "] <= [child_hook = sym child_hook]);
 
 asmfunction!(__relibc_internal_sigentry: ["
+    // old pc and x0 are saved in the sigcontrol struct
+    mrs x0, tpidr_el0 // ABI ptr
+    ldr x0, [x0] // TCB ptr
+
+    // save x1-x3 and sp
+    stp x1, x2, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}]
+    stp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}]
+    mov x1, sp
+    str x1, [x0, #{tcb_sa_off} + {sa_tmp_sp}]
+
+    sub x1, x1, 128
+    and x1, x1, -16
+    mov sp, x1
+
+    ldr x3, [x0, #{tcb_sa_off} + {sa_pctl}]
+
+    // load x1 and x2 with each word (tearing between x1 and x2 can occur)
+    // acquire ordering
+    add x2, x0, #{tcb_sc_off} + {sc_word}
+    ldaxp x1, x2, [x2]
+
+    // reduce them by ANDing the upper and lower 32 bits
+    and x1, x1, x1, lsr #32 // put result in lo half
+    and x2, x2, x2, lsl #32 // put result in hi half
+    orr x1, x1, x2 // combine them into the set of pending unblocked
+
+    // count trailing zeroes, to find signal bit
+    rbit x1, x1
+    clz x1, x1
+    mov x2, #32
+    sub x1, x2, x1
+
+    // TODO: NOT ATOMIC!
+    add x2, x3, w1, uxtb #4 // actions_base + sig_idx * sizeof Action
+    ldxp x2, x3, [x2]
+
+    // skip sigaltstack step if SA_ONSTACK is clear
+    // tbz x2, #57, 2f
+2:
+    ldr x2, [x0, #{tcb_sc_off} + {sc_saved_pc}]
+    ldr x3, [x0, #{tcb_sc_off} + {sc_saved_x0}]
+    stp x2, x3, [sp], #-16
+
+    ldr x2, [x0, #{tcb_sa_off} + {sa_tmp_sp}]
+    mrs x3, nzcv
+    stp x2, x3, [sp], #-16
+
+    ldp x2, x3, [x0, #{tcb_sa_off} + {sa_tmp_x1_x2}]
+    stp x2, x3, [sp], #-16
+    ldp x3, x4, [x0, #{tcb_sa_off} + {sa_tmp_x3_x4}]
+    stp x4, x3, [sp], #-16
+    stp x6, x5, [sp], #-16
+    stp x8, x7, [sp], #-16
+    stp x10, x9, [sp], #-16
+    stp x12, x11, [sp], #-16
+    stp x14, x13, [sp], #-16
+    stp x16, x15, [sp], #-16
+    stp x18, x17, [sp], #-16
+    stp x20, x19, [sp], #-16
+    stp x22, x21, [sp], #-16
+    stp x24, x23, [sp], #-16
+    stp x26, x25, [sp], #-16
+    stp x28, x27, [sp], #-16
+    stp x30, x29, [sp], #-16
+
     mov x0, sp
     bl {inner}
 
-    // FIXME
-    b .
-"] <= [inner = sym inner_c]);
+    ldp x30, x29, [sp], #16
+    ldp x28, x27, [sp], #16
+    ldp x26, x25, [sp], #16
+    ldp x24, x23, [sp], #16
+    ldp x22, x21, [sp], #16
+    ldp x20, x19, [sp], #16
+    ldp x18, x17, [sp], #16
+    ldp x16, x15, [sp], #16
+    ldp x14, x13, [sp], #16
+    ldp x12, x11, [sp], #16
+    ldp x10, x9, [sp], #16
+    ldp x8, x7, [sp], #16
+    ldp x6, x5, [sp], #16
+    ldp x4, x3, [sp], #16
+    ldp x2, x1, [sp], #16
+    ldr x0, [sp, #8]
+    msr nzcv, x0
+
+    // x18 is reserved by ABI as 'platform register', so clobbering it should be safe.
+    mov x18, sp
+    ldr x0, [sp], #16
+    mov sp, x0
+    mov x0, x18
+
+    ldp x18, x0, [x0]
+    br x18
+"] <= [
+    tcb_sc_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, control)),
+    tcb_sa_off = const (offset_of!(crate::Tcb, os_specific) + offset_of!(RtSigarea, arch)),
+    sa_tmp_x1_x2 = const offset_of!(SigArea, tmp_x1_x2),
+    sa_tmp_x3_x4 = const offset_of!(SigArea, tmp_x3_x4),
+    sa_tmp_sp = const offset_of!(SigArea, tmp_sp),
+    sa_pctl = const offset_of!(SigArea, pctl),
+    sc_saved_pc = const offset_of!(Sigcontrol, saved_ip),
+    sc_saved_x0 = const offset_of!(Sigcontrol, saved_archdep_reg),
+    sc_word = const offset_of!(Sigcontrol, word),
+    inner = sym inner_c,
+]);
 
 asmfunction!(__relibc_internal_rlct_clone_ret: ["
     # Load registers
@@ -109,3 +258,29 @@ asmfunction!(__relibc_internal_rlct_clone_ret: ["
 
     ret
 "] <= []);
+
+pub fn current_sp() -> usize {
+    let sp: usize;
+    unsafe {
+        core::arch::asm!("mov {}, sp", out(reg) sp);
+    }
+    sp
+}
+
+pub unsafe fn manually_enter_trampoline() {
+    let ctl = &Tcb::current().unwrap().os_specific.control;
+
+    ctl.saved_archdep_reg.set(0);
+    let ip_location = &ctl.saved_ip as *const _ as usize;
+
+    core::arch::asm!("
+        bl 2f
+        b 3f
+    2:
+        ldr lr, [x0]
+        b __relibc_internal_sigentry
+    3:
+    ", inout("x0") ip_location => _, out("lr") _);
+}
+
+pub unsafe fn arch_pre(stack: &mut SigStack, os: &mut SigArea) {}