diff --git a/src/ARMeilleure/Memory/IJitMemoryAllocator.cs b/src/ARMeilleure/Memory/IJitMemoryAllocator.cs
index 171bfd2f14..ff64bf13ea 100644
--- a/src/ARMeilleure/Memory/IJitMemoryAllocator.cs
+++ b/src/ARMeilleure/Memory/IJitMemoryAllocator.cs
@@ -4,7 +4,5 @@ namespace ARMeilleure.Memory
     {
         IJitMemoryBlock Allocate(ulong size);
         IJitMemoryBlock Reserve(ulong size);
-
-        ulong GetPageSize();
     }
 }
diff --git a/src/ARMeilleure/Memory/MemoryManagerType.cs b/src/ARMeilleure/Memory/MemoryManagerType.cs
index 1e656ba273..b1cdbb069a 100644
--- a/src/ARMeilleure/Memory/MemoryManagerType.cs
+++ b/src/ARMeilleure/Memory/MemoryManagerType.cs
@@ -31,7 +31,7 @@ namespace ARMeilleure.Memory
         HostMappedUnsafe,
     }
 
-    static class MemoryManagerTypeExtensions
+    public static class MemoryManagerTypeExtensions
     {
         public static bool IsHostMapped(this MemoryManagerType type)
         {
diff --git a/src/ARMeilleure/Signal/NativeSignalHandler.cs b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs
similarity index 62%
rename from src/ARMeilleure/Signal/NativeSignalHandler.cs
rename to src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs
index 31ec16cb14..c5e708e169 100644
--- a/src/ARMeilleure/Signal/NativeSignalHandler.cs
+++ b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs
@@ -1,63 +1,14 @@
 using ARMeilleure.IntermediateRepresentation;
-using ARMeilleure.Memory;
 using ARMeilleure.Translation;
-using ARMeilleure.Translation.Cache;
 using System;
-using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 
 namespace ARMeilleure.Signal
 {
-    [StructLayout(LayoutKind.Sequential, Pack = 1)]
-    struct SignalHandlerRange
+    public static class NativeSignalHandlerGenerator
     {
-        public int IsActive;
-        public nuint RangeAddress;
-        public nuint RangeEndAddress;
-        public IntPtr ActionPointer;
-    }
-
-    [StructLayout(LayoutKind.Sequential, Pack = 1)]
-    struct SignalHandlerConfig
-    {
-        /// <summary>
-        /// The byte offset of the faulting address in the SigInfo or ExceptionRecord struct.
-        /// </summary>
-        public int StructAddressOffset;
-
-        /// <summary>
-        /// The byte offset of the write flag in the SigInfo or ExceptionRecord struct.
-        /// </summary>
-        public int StructWriteOffset;
-
-        /// <summary>
-        /// The sigaction handler that was registered before this one. (unix only)
-        /// </summary>
-        public nuint UnixOldSigaction;
-
-        /// <summary>
-        /// The type of the previous sigaction. True for the 3 argument variant. (unix only)
-        /// </summary>
-        public int UnixOldSigaction3Arg;
-
-        public SignalHandlerRange Range0;
-        public SignalHandlerRange Range1;
-        public SignalHandlerRange Range2;
-        public SignalHandlerRange Range3;
-        public SignalHandlerRange Range4;
-        public SignalHandlerRange Range5;
-        public SignalHandlerRange Range6;
-        public SignalHandlerRange Range7;
-    }
-
-    public static class NativeSignalHandler
-    {
-        private delegate void UnixExceptionHandler(int sig, IntPtr info, IntPtr ucontext);
-        [UnmanagedFunctionPointer(CallingConvention.Winapi)]
-        private delegate int VectoredExceptionHandler(IntPtr exceptionInfo);
-
-        private const int MaxTrackedRanges = 8;
+        public const int MaxTrackedRanges = 8;
 
         private const int StructAddressOffset = 0;
         private const int StructWriteOffset = 4;
@@ -70,125 +21,10 @@ namespace ARMeilleure.Signal
 
         private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005;
 
-        private static ulong _pageSize;
-        private static ulong _pageMask;
-
-        private static readonly IntPtr _handlerConfig;
-        private static IntPtr _signalHandlerPtr;
-        private static IntPtr _signalHandlerHandle;
-
-        private static readonly object _lock = new();
-        private static bool _initialized;
-
-        static NativeSignalHandler()
+        private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize, ulong pageSize)
         {
-            _handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf<SignalHandlerConfig>());
-            ref SignalHandlerConfig config = ref GetConfigRef();
+            ulong pageMask = pageSize - 1;
 
-            config = new SignalHandlerConfig();
-        }
-
-        public static void Initialize(IJitMemoryAllocator allocator)
-        {
-            JitCache.Initialize(allocator);
-        }
-
-        public static void InitializeSignalHandler(ulong pageSize, Func<IntPtr, IntPtr, IntPtr> customSignalHandlerFactory = null)
-        {
-            if (_initialized)
-            {
-                return;
-            }
-
-            lock (_lock)
-            {
-                if (_initialized)
-                {
-                    return;
-                }
-
-                _pageSize = pageSize;
-                _pageMask = pageSize - 1;
-
-                ref SignalHandlerConfig config = ref GetConfigRef();
-
-                if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
-                {
-                    _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig));
-
-                    if (customSignalHandlerFactory != null)
-                    {
-                        _signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr);
-                    }
-
-                    var old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
-
-                    config.UnixOldSigaction = (nuint)(ulong)old.sa_handler;
-                    config.UnixOldSigaction3Arg = old.sa_flags & 4;
-                }
-                else
-                {
-                    config.StructAddressOffset = 40; // ExceptionInformation1
-                    config.StructWriteOffset = 32; // ExceptionInformation0
-
-                    _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateWindowsSignalHandler(_handlerConfig));
-
-                    if (customSignalHandlerFactory != null)
-                    {
-                        _signalHandlerPtr = customSignalHandlerFactory(IntPtr.Zero, _signalHandlerPtr);
-                    }
-
-                    _signalHandlerHandle = WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
-                }
-
-                _initialized = true;
-            }
-        }
-
-        private static unsafe ref SignalHandlerConfig GetConfigRef()
-        {
-            return ref Unsafe.AsRef<SignalHandlerConfig>((void*)_handlerConfig);
-        }
-
-        public static unsafe bool AddTrackedRegion(nuint address, nuint endAddress, IntPtr action)
-        {
-            var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0;
-
-            for (int i = 0; i < MaxTrackedRanges; i++)
-            {
-                if (ranges[i].IsActive == 0)
-                {
-                    ranges[i].RangeAddress = address;
-                    ranges[i].RangeEndAddress = endAddress;
-                    ranges[i].ActionPointer = action;
-                    ranges[i].IsActive = 1;
-
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-        public static unsafe bool RemoveTrackedRegion(nuint address)
-        {
-            var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0;
-
-            for (int i = 0; i < MaxTrackedRanges; i++)
-            {
-                if (ranges[i].IsActive == 1 && ranges[i].RangeAddress == address)
-                {
-                    ranges[i].IsActive = 0;
-
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-        private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite)
-        {
             Operand inRegionLocal = context.AllocateLocal(OperandType.I32);
             context.Copy(inRegionLocal, Const(0));
 
@@ -196,7 +32,7 @@ namespace ARMeilleure.Signal
 
             for (int i = 0; i < MaxTrackedRanges; i++)
             {
-                ulong rangeBaseOffset = (ulong)(RangeOffset + i * Unsafe.SizeOf<SignalHandlerRange>());
+                ulong rangeBaseOffset = (ulong)(RangeOffset + i * rangeStructSize);
 
                 Operand nextLabel = Label();
 
@@ -210,13 +46,12 @@ namespace ARMeilleure.Signal
                 // Is the fault address within this tracked region?
                 Operand inRange = context.BitwiseAnd(
                     context.ICompare(faultAddress, rangeAddress, Comparison.GreaterOrEqualUI),
-                    context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI)
-                    );
+                    context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI));
 
                 // Only call tracking if in range.
                 context.BranchIfFalse(nextLabel, inRange, BasicBlockFrequency.Cold);
 
-                Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~_pageMask));
+                Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~pageMask));
 
                 // Call the tracking action, with the pointer's relative offset to the base address.
                 Operand trackingActionPtr = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 20));
@@ -227,7 +62,7 @@ namespace ARMeilleure.Signal
 
                 // Tracking action should be non-null to call it, otherwise assume false return.
                 context.BranchIfFalse(skipActionLabel, trackingActionPtr);
-                Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(_pageSize), isWrite);
+                Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(pageSize), isWrite);
                 context.Copy(inRegionLocal, result);
 
                 context.MarkLabel(skipActionLabel);
@@ -269,8 +104,7 @@ namespace ARMeilleure.Signal
                     Operand esr = context.Load(OperandType.I64, context.Add(ctxPtr, Const(EsrOffset)));
                     return context.BitwiseAnd(esr, Const(0x40ul));
                 }
-
-                if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
+                else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
                 {
                     const ulong ErrOffset = 4; // __es.__err
                     Operand err = context.Load(OperandType.I64, context.Add(ctxPtr, Const(ErrOffset)));
@@ -310,8 +144,7 @@ namespace ARMeilleure.Signal
                     Operand esr = context.Load(OperandType.I64, context.Add(auxPtr, Const(8ul)));
                     return context.BitwiseAnd(esr, Const(0x40ul));
                 }
-
-                if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
+                else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
                 {
                     const int ErrOffset = 192; // uc_mcontext.gregs[REG_ERR]
                     Operand err = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(ErrOffset)));
@@ -322,7 +155,7 @@ namespace ARMeilleure.Signal
             throw new PlatformNotSupportedException();
         }
 
-        private static UnixExceptionHandler GenerateUnixSignalHandler(IntPtr signalStructPtr)
+        public static byte[] GenerateUnixSignalHandler(IntPtr signalStructPtr, int rangeStructSize, ulong pageSize)
         {
             EmitterContext context = new();
 
@@ -335,7 +168,7 @@ namespace ARMeilleure.Signal
 
             Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1.
 
-            Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite);
+            Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize, pageSize);
 
             Operand endLabel = Label();
 
@@ -367,10 +200,10 @@ namespace ARMeilleure.Signal
 
             OperandType[] argTypes = new OperandType[] { OperandType.I32, OperandType.I64, OperandType.I64 };
 
-            return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<UnixExceptionHandler>();
+            return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
         }
 
-        private static VectoredExceptionHandler GenerateWindowsSignalHandler(IntPtr signalStructPtr)
+        public static byte[] GenerateWindowsSignalHandler(IntPtr signalStructPtr, int rangeStructSize, ulong pageSize)
         {
             EmitterContext context = new();
 
@@ -399,7 +232,7 @@ namespace ARMeilleure.Signal
 
             Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1.
 
-            Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite);
+            Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize, pageSize);
 
             Operand endLabel = Label();
 
@@ -421,7 +254,7 @@ namespace ARMeilleure.Signal
 
             OperandType[] argTypes = new OperandType[] { OperandType.I64 };
 
-            return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<VectoredExceptionHandler>();
+            return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code;
         }
     }
 }
diff --git a/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs b/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs
index 27a9ea83c7..3bf6a44983 100644
--- a/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs
+++ b/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs
@@ -2,7 +2,7 @@ using ARMeilleure.IntermediateRepresentation;
 using ARMeilleure.Translation;
 using Ryujinx.Common.Memory.PartialUnmaps;
 using System;
-
+using System.Runtime.InteropServices;
 using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 
 namespace ARMeilleure.Signal
@@ -10,8 +10,28 @@ namespace ARMeilleure.Signal
     /// <summary>
     /// Methods to handle signals caused by partial unmaps. See the structs for C# implementations of the methods.
     /// </summary>
-    internal static class WindowsPartialUnmapHandler
+    internal static partial class WindowsPartialUnmapHandler
     {
+        [LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")]
+        private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
+
+        [LibraryImport("kernel32.dll", SetLastError = true)]
+        private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
+
+        private static IntPtr _getCurrentThreadIdPtr;
+
+        public static IntPtr GetCurrentThreadIdFunc()
+        {
+            if (_getCurrentThreadIdPtr == IntPtr.Zero)
+            {
+                IntPtr handle = LoadLibrary("kernel32.dll");
+
+                _getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId");
+            }
+
+            return _getCurrentThreadIdPtr;
+        }
+
         public static Operand EmitRetryFromAccessViolation(EmitterContext context)
         {
             IntPtr partialRemapStatePtr = PartialUnmapState.GlobalState;
@@ -20,7 +40,7 @@ namespace ARMeilleure.Signal
             // Get the lock first.
             EmitNativeReaderLockAcquire(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
 
-            IntPtr getCurrentThreadId = WindowsSignalHandlerRegistration.GetCurrentThreadIdFunc();
+            IntPtr getCurrentThreadId = GetCurrentThreadIdFunc();
             Operand threadId = context.Call(Const((ulong)getCurrentThreadId), OperandType.I32);
             Operand threadIndex = EmitThreadLocalMapIntGetOrReserve(context, localCountsPtr, threadId, Const(0));
 
@@ -137,17 +157,6 @@ namespace ARMeilleure.Signal
             return context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset));
         }
 
-#pragma warning disable IDE0051 // Remove unused private member
-        private static void EmitThreadLocalMapIntRelease(EmitterContext context, IntPtr threadLocalMapPtr, Operand threadId, Operand index)
-        {
-            Operand offset = context.Multiply(index, Const(sizeof(int)));
-            Operand idsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap<int>.ThreadIdsOffset));
-            Operand idPtr = context.Add(idsPtr, context.SignExtend32(OperandType.I64, offset));
-
-            context.CompareAndSwap(idPtr, threadId, Const(0));
-        }
-#pragma warning restore IDE0051
-
         private static void EmitAtomicAddI32(EmitterContext context, Operand ptr, Operand additive)
         {
             Operand loop = Label();
diff --git a/src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs b/src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs
deleted file mode 100644
index 5444da0ca1..0000000000
--- a/src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace ARMeilleure.Signal
-{
-    unsafe partial class WindowsSignalHandlerRegistration
-    {
-        [LibraryImport("kernel32.dll")]
-        private static partial IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler);
-
-        [LibraryImport("kernel32.dll")]
-        private static partial ulong RemoveVectoredExceptionHandler(IntPtr handle);
-
-        [LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")]
-        private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
-
-        [LibraryImport("kernel32.dll", SetLastError = true)]
-        private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
-
-        private static IntPtr _getCurrentThreadIdPtr;
-
-        public static IntPtr RegisterExceptionHandler(IntPtr action)
-        {
-            return AddVectoredExceptionHandler(1, action);
-        }
-
-        public static bool RemoveExceptionHandler(IntPtr handle)
-        {
-            return RemoveVectoredExceptionHandler(handle) != 0;
-        }
-
-        public static IntPtr GetCurrentThreadIdFunc()
-        {
-            if (_getCurrentThreadIdPtr == IntPtr.Zero)
-            {
-                IntPtr handle = LoadLibrary("kernel32.dll");
-
-                _getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId");
-            }
-
-            return _getCurrentThreadIdPtr;
-        }
-    }
-}
diff --git a/src/ARMeilleure/Translation/Translator.cs b/src/ARMeilleure/Translation/Translator.cs
index dc18038ba6..7f6a25b07e 100644
--- a/src/ARMeilleure/Translation/Translator.cs
+++ b/src/ARMeilleure/Translation/Translator.cs
@@ -79,11 +79,6 @@ namespace ARMeilleure.Translation
             Stubs = new TranslatorStubs(this);
 
             FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
-
-            if (memory.Type.IsHostMapped())
-            {
-                NativeSignalHandler.InitializeSignalHandler(allocator.GetPageSize());
-            }
         }
 
         public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
diff --git a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs
index 24bc1e5950..5876346a0c 100644
--- a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs
+++ b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs
@@ -1,5 +1,7 @@
 using ARMeilleure.Memory;
 using ARMeilleure.Translation;
+using Ryujinx.Cpu.Signal;
+using Ryujinx.Memory;
 
 namespace Ryujinx.Cpu.Jit
 {
@@ -12,6 +14,12 @@ namespace Ryujinx.Cpu.Jit
         {
             _tickSource = tickSource;
             _translator = new Translator(new JitMemoryAllocator(), memory, for64Bit);
+
+            if (memory.Type.IsHostMapped())
+            {
+                NativeSignalHandler.InitializeSignalHandler(MemoryBlock.GetPageSize());
+            }
+
             memory.UnmapEvent += UnmapHandler;
         }
 
diff --git a/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs b/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs
index 529a1a8086..eb665c2dfd 100644
--- a/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs
+++ b/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs
@@ -7,7 +7,5 @@ namespace Ryujinx.Cpu.Jit
     {
         public IJitMemoryBlock Allocate(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.None);
         public IJitMemoryBlock Reserve(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.Jit);
-
-        public ulong GetPageSize() => MemoryBlock.GetPageSize();
     }
 }
diff --git a/src/Ryujinx.Cpu/MemoryEhMeilleure.cs b/src/Ryujinx.Cpu/MemoryEhMeilleure.cs
index 54e232d9c7..f3a5b056bc 100644
--- a/src/Ryujinx.Cpu/MemoryEhMeilleure.cs
+++ b/src/Ryujinx.Cpu/MemoryEhMeilleure.cs
@@ -1,4 +1,4 @@
-using ARMeilleure.Signal;
+using Ryujinx.Cpu.Signal;
 using Ryujinx.Memory;
 using Ryujinx.Memory.Tracking;
 using System;
diff --git a/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs b/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs
new file mode 100644
index 0000000000..5a9d92cc4f
--- /dev/null
+++ b/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs
@@ -0,0 +1,179 @@
+using ARMeilleure.Signal;
+using Ryujinx.Common;
+using Ryujinx.Memory;
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Cpu.Signal
+{
+    [StructLayout(LayoutKind.Sequential, Pack = 1)]
+    struct SignalHandlerRange
+    {
+        public int IsActive;
+        public nuint RangeAddress;
+        public nuint RangeEndAddress;
+        public IntPtr ActionPointer;
+    }
+
+    [InlineArray(NativeSignalHandlerGenerator.MaxTrackedRanges)]
+    struct SignalHandlerRangeArray
+    {
+        public SignalHandlerRange Range0;
+    }
+
+    [StructLayout(LayoutKind.Sequential, Pack = 1)]
+    struct SignalHandlerConfig
+    {
+        /// <summary>
+        /// The byte offset of the faulting address in the SigInfo or ExceptionRecord struct.
+        /// </summary>
+        public int StructAddressOffset;
+
+        /// <summary>
+        /// The byte offset of the write flag in the SigInfo or ExceptionRecord struct.
+        /// </summary>
+        public int StructWriteOffset;
+
+        /// <summary>
+        /// The sigaction handler that was registered before this one. (unix only)
+        /// </summary>
+        public nuint UnixOldSigaction;
+
+        /// <summary>
+        /// The type of the previous sigaction. True for the 3 argument variant. (unix only)
+        /// </summary>
+        public int UnixOldSigaction3Arg;
+
+        /// <summary>
+        /// Fixed size array of tracked ranges.
+        /// </summary>
+        public SignalHandlerRangeArray Ranges;
+    }
+
+    static class NativeSignalHandler
+    {
+        private static readonly IntPtr _handlerConfig;
+        private static IntPtr _signalHandlerPtr;
+
+        private static MemoryBlock _codeBlock;
+
+        private static readonly object _lock = new();
+        private static bool _initialized;
+
+        static NativeSignalHandler()
+        {
+            _handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf<SignalHandlerConfig>());
+            ref SignalHandlerConfig config = ref GetConfigRef();
+
+            config = new SignalHandlerConfig();
+        }
+
+        public static void InitializeSignalHandler(ulong pageSize, Func<IntPtr, IntPtr, IntPtr> customSignalHandlerFactory = null)
+        {
+            if (_initialized)
+            {
+                return;
+            }
+
+            lock (_lock)
+            {
+                if (_initialized)
+                {
+                    return;
+                }
+
+                int rangeStructSize = Unsafe.SizeOf<SignalHandlerRange>();
+
+                ref SignalHandlerConfig config = ref GetConfigRef();
+
+                if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
+                {
+                    _signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateUnixSignalHandler(_handlerConfig, rangeStructSize, pageSize));
+
+                    if (customSignalHandlerFactory != null)
+                    {
+                        _signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr);
+                    }
+
+                    var old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
+
+                    config.UnixOldSigaction = (nuint)(ulong)old.sa_handler;
+                    config.UnixOldSigaction3Arg = old.sa_flags & 4;
+                }
+                else
+                {
+                    config.StructAddressOffset = 40; // ExceptionInformation1
+                    config.StructWriteOffset = 32; // ExceptionInformation0
+
+                    _signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateWindowsSignalHandler(_handlerConfig, rangeStructSize, pageSize));
+
+                    if (customSignalHandlerFactory != null)
+                    {
+                        _signalHandlerPtr = customSignalHandlerFactory(IntPtr.Zero, _signalHandlerPtr);
+                    }
+
+                    WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
+                }
+
+                _initialized = true;
+            }
+        }
+
+        private static IntPtr MapCode(ReadOnlySpan<byte> code)
+        {
+            Debug.Assert(_codeBlock == null);
+
+            ulong codeSizeAligned = BitUtils.AlignUp((ulong)code.Length, MemoryBlock.GetPageSize());
+
+            _codeBlock = new MemoryBlock(codeSizeAligned);
+            _codeBlock.Write(0, code);
+            _codeBlock.Reprotect(0, codeSizeAligned, MemoryPermission.ReadAndExecute);
+
+            return _codeBlock.Pointer;
+        }
+
+        private static unsafe ref SignalHandlerConfig GetConfigRef()
+        {
+            return ref Unsafe.AsRef<SignalHandlerConfig>((void*)_handlerConfig);
+        }
+
+        public static bool AddTrackedRegion(nuint address, nuint endAddress, IntPtr action)
+        {
+            Span<SignalHandlerRange> ranges = GetConfigRef().Ranges;
+
+            for (int i = 0; i < NativeSignalHandlerGenerator.MaxTrackedRanges; i++)
+            {
+                if (ranges[i].IsActive == 0)
+                {
+                    ranges[i].RangeAddress = address;
+                    ranges[i].RangeEndAddress = endAddress;
+                    ranges[i].ActionPointer = action;
+                    ranges[i].IsActive = 1;
+
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        public static bool RemoveTrackedRegion(nuint address)
+        {
+            Span<SignalHandlerRange> ranges = GetConfigRef().Ranges;
+
+            for (int i = 0; i < NativeSignalHandlerGenerator.MaxTrackedRanges; i++)
+            {
+                if (ranges[i].IsActive == 1 && ranges[i].RangeAddress == address)
+                {
+                    ranges[i].IsActive = 0;
+
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    }
+}
diff --git a/src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs b/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs
similarity index 98%
rename from src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs
rename to src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs
index 70e9f22042..e88a6c0f60 100644
--- a/src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs
+++ b/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs
@@ -1,7 +1,7 @@
 using System;
 using System.Runtime.InteropServices;
 
-namespace ARMeilleure.Signal
+namespace Ryujinx.Cpu.Signal
 {
     static partial class UnixSignalHandlerRegistration
     {
diff --git a/src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs b/src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs
new file mode 100644
index 0000000000..1fbce0f72f
--- /dev/null
+++ b/src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Cpu.Signal
+{
+    static partial class WindowsSignalHandlerRegistration
+    {
+        [LibraryImport("kernel32.dll")]
+        private static partial IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler);
+
+        [LibraryImport("kernel32.dll")]
+        private static partial ulong RemoveVectoredExceptionHandler(IntPtr handle);
+
+        public static IntPtr RegisterExceptionHandler(IntPtr action)
+        {
+            return AddVectoredExceptionHandler(1, action);
+        }
+
+        public static bool RemoveExceptionHandler(IntPtr handle)
+        {
+            return RemoveVectoredExceptionHandler(handle) != 0;
+        }
+    }
+}