[fiber] synchronization problems have been fixed for such a titles: Demon's Souls

[ampr] new exports
[memory] trampoline fixes
This commit is contained in:
ParantezTech
2026-06-23 15:48:45 +03:00
parent dad85b87c3
commit d134f9b9f6
11 changed files with 1074 additions and 242 deletions
@@ -19,7 +19,12 @@ public sealed partial class DirectExecutionBackend
{
if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_DISABLE_RAW_HANDLER"), "1", StringComparison.Ordinal))
{
_rawExceptionHandler = (nint)AddVectoredExceptionHandler(1u, RawVectoredHandlerPtrManaged);
_rawExceptionHandlerStub = CreateExceptionHandlerTrampoline(RawVectoredHandlerPtrManaged);
if (_rawExceptionHandlerStub == 0)
{
throw new InvalidOperationException("Failed to create raw exception handler trampoline");
}
_rawExceptionHandler = (nint)AddVectoredExceptionHandler(1u, _rawExceptionHandlerStub);
Console.Error.WriteLine($"[LOADER][INFO] Raw exception handler installed: 0x{_rawExceptionHandler:X16}");
}
else
@@ -29,12 +34,22 @@ public sealed partial class DirectExecutionBackend
_handlerDelegate = VectoredHandler;
_handlerHandle = GCHandle.Alloc(_handlerDelegate);
_exceptionHandler = (nint)AddVectoredExceptionHandler(1u, Marshal.GetFunctionPointerForDelegate(_handlerDelegate));
_exceptionHandlerStub = CreateExceptionHandlerTrampoline(Marshal.GetFunctionPointerForDelegate(_handlerDelegate));
if (_exceptionHandlerStub == 0)
{
throw new InvalidOperationException("Failed to create exception handler trampoline");
}
_exceptionHandler = (nint)AddVectoredExceptionHandler(1u, _exceptionHandlerStub);
Console.Error.WriteLine($"[LOADER][INFO] Exception handler installed: 0x{_exceptionHandler:X16}");
_unhandledFilterDelegate = UnhandledExceptionFilter;
_unhandledFilterHandle = GCHandle.Alloc(_unhandledFilterDelegate);
SetUnhandledExceptionFilter(Marshal.GetFunctionPointerForDelegate(_unhandledFilterDelegate));
_unhandledFilterStub = CreateExceptionHandlerTrampoline(Marshal.GetFunctionPointerForDelegate(_unhandledFilterDelegate));
if (_unhandledFilterStub == 0)
{
throw new InvalidOperationException("Failed to create unhandled exception filter trampoline");
}
SetUnhandledExceptionFilter(_unhandledFilterStub);
}
private unsafe int UnhandledExceptionFilter(void* exceptionInfo)
@@ -143,6 +143,8 @@ public sealed partial class DirectExecutionBackend
ProbeReturnRip(num7, num);
}
TrackStrlenPrelude(importStubEntry.Nid, num, num7);
TraceGuestContext(
$"import dispatch={num} nid={importStubEntry.Nid} ret=0x{num7:X16} managed={Environment.CurrentManagedThreadId} guest=0x{GuestThreadExecution.CurrentGuestThreadHandle:X16} fiber=0x{GuestThreadExecution.CurrentFiberAddress:X16} active={HasActiveExecutionThread}");
bool logBootstrap = string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_BOOTSTRAP"), "1", StringComparison.Ordinal);
if (logBootstrap && string.Equals(importStubEntry.Nid, RuntimeStubNids.BootstrapBridge, StringComparison.Ordinal))
{
@@ -279,13 +281,15 @@ public sealed partial class DirectExecutionBackend
catch
{
}
TryBypassStackChkFailTrap(num, num7);
}
try
{
OrbisGen2Result orbisGen2Result;
bool dispatchResolved = true;
var previousImportCallFrame = GuestThreadExecution.EnterImportCallFrame(num7, (ulong)argPackPtr + 104uL);
var previousImportCallFrame = GuestThreadExecution.EnterImportCallFrame(
num7,
(ulong)argPackPtr + 104uL,
ActiveGuestReturnSlotAddress);
try
{
if (string.Equals(importStubEntry.Nid, RuntimeStubNids.BootstrapBridge, StringComparison.Ordinal))
@@ -408,7 +412,7 @@ public sealed partial class DirectExecutionBackend
private unsafe bool TryForceGuestExitToHostStub(nint argPackPtr, long dispatchIndex, ulong returnRip, string nid)
{
ulong num = ActiveEntryReturnSentinelRip;
if (num < 65536)
if (num < 65536 || !TryPatchActiveGuestReturnSlot(num))
{
return false;
}
@@ -430,7 +434,7 @@ public sealed partial class DirectExecutionBackend
private unsafe bool TryCompleteGuestEntryToHostStub(nint argPackPtr, long dispatchIndex, ulong returnRip, string nid, string reason, int status)
{
ulong hostExit = ActiveEntryReturnSentinelRip;
if (hostExit < 65536)
if (hostExit < 65536 || !TryPatchActiveGuestReturnSlot(hostExit))
{
return false;
}
@@ -450,7 +454,7 @@ public sealed partial class DirectExecutionBackend
private unsafe bool TryYieldGuestThreadToHostStub(nint argPackPtr, long dispatchIndex, ulong returnRip, string nid, string reason)
{
ulong hostExit = ActiveEntryReturnSentinelRip;
if (hostExit < 65536)
if (hostExit < 65536 || !TryPatchActiveGuestReturnSlot(hostExit))
{
return false;
}
@@ -470,6 +474,14 @@ public sealed partial class DirectExecutionBackend
return true;
}
private bool TryPatchActiveGuestReturnSlot(ulong hostExit)
{
ulong returnSlotAddress = ActiveGuestReturnSlotAddress;
return returnSlotAddress != 0 &&
ActiveCpuContext is not null &&
ActiveCpuContext.TryWriteUInt64(returnSlotAddress, hostExit);
}
private bool ShouldForceGuestExitOnImportLoop(string nid, ulong returnRip, long dispatchIndex, ulong arg0, ulong arg1)
{
if (dispatchIndex < 1200)
@@ -480,6 +492,11 @@ public sealed partial class DirectExecutionBackend
{
return false;
}
if (IsImportLoopGuardBoundary(nid))
{
ResetImportLoopPattern();
return false;
}
if (!_importNidHashCache.TryGetValue(nid, out var value))
{
value = StableHash64(nid);
@@ -513,6 +530,17 @@ public sealed partial class DirectExecutionBackend
return elapsedTicks >= (long)(guardSeconds * Stopwatch.Frequency);
}
private static bool IsImportLoopGuardBoundary(string nid) =>
string.Equals(nid, "1jfXLRVzisc", StringComparison.Ordinal);
private void ResetImportLoopPattern()
{
_importLoopPatternHits = 0;
_importLoopPatternStartTimestamp = 0;
_importLoopSignatureCount = 0;
_importLoopSignatureWriteIndex = 0;
}
private static int GetImportLoopGuardSeconds()
{
if (int.TryParse(Environment.GetEnvironmentVariable("SHARPEMU_IMPORT_LOOP_GUARD_SECONDS"), out var seconds))
@@ -923,66 +951,6 @@ public sealed partial class DirectExecutionBackend
}
}
private void TryBypassStackChkFailTrap(long dispatchIndex, ulong returnRip)
{
var cpuContext = ActiveCpuContext;
if (cpuContext == null || returnRip < 32)
{
return;
}
try
{
byte[] array = new byte[19];
ulong num = returnRip - 23;
Marshal.Copy((nint)num, array, 0, array.Length);
if (array[0] != 117 || array[1] != 16 || array[2] != 72 || array[3] != 137 || array[4] != 216 || array[5] != 72 || array[6] != 131 || array[7] != 196 || array[9] != 91 || array[10] != 65 || array[11] != 92 || array[12] != 65 || array[13] != 94 || array[14] != 65 || array[15] != 95 || array[16] != 93 || array[17] != 195 || array[18] != 232)
{
return;
}
ulong value = returnRip - 21;
ulong address = cpuContext[CpuRegister.Rsp];
if (cpuContext.TryWriteUInt64(address, value))
{
if (_stackChkBypassSites.Add(num) && TryPatchStackChkFailBranch(num))
{
Console.Error.WriteLine($"[LOADER][WARNING] Import#{dispatchIndex}: patched stack_chk_fail tail branch at 0x{num:X16} -> NOP NOP");
}
Console.Error.WriteLine($"[LOADER][WARNING] Import#{dispatchIndex}: redirected __stack_chk_fail return to epilogue 0x{value:X16}");
}
}
catch
{
}
}
private unsafe static bool TryPatchStackChkFailBranch(ulong branchAddress)
{
uint flNewProtect = default(uint);
if (!VirtualProtect((void*)branchAddress, 2u, 64u, &flNewProtect))
{
return false;
}
try
{
if (Marshal.ReadByte((nint)branchAddress) != 117)
{
return false;
}
Marshal.WriteByte((nint)branchAddress, 144);
Marshal.WriteByte((nint)(branchAddress + 1), 144);
FlushInstructionCache(GetCurrentProcess(), (void*)branchAddress, 2u);
return true;
}
catch
{
return false;
}
finally
{
VirtualProtect((void*)branchAddress, 2u, flNewProtect, &flNewProtect);
}
}
private unsafe void TryPatchEa020eLookupCall(long dispatchIndex, ulong returnRip)
{
if (_patchedEa020eLookupCall || returnRip != 0x0000000800EA01A6uL)
@@ -136,10 +136,18 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
private nint _unresolvedReturnStub;
private nint _guestReturnStub;
private nint _rawExceptionHandler;
private nint _rawExceptionHandlerStub;
private nint _exceptionHandler;
private nint _exceptionHandlerStub;
private nint _unhandledFilterStub;
private nint _lowIndexedTableScratch;
private nint _stackGuardCompareScratch;
@@ -161,6 +169,9 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
[ThreadStatic]
private static ulong _activeEntryReturnSentinelRip;
[ThreadStatic]
private static ulong _activeGuestReturnSlotAddress;
[ThreadStatic]
private static bool _activeForcedGuestExit;
@@ -202,8 +213,6 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
private readonly HashSet<ulong> _fallbackTrapStubs = new HashSet<ulong>();
private readonly HashSet<ulong> _stackChkBypassSites = new HashSet<ulong>();
private readonly HashSet<ulong> _patchedResolverReturnSites = new HashSet<ulong>();
private readonly HashSet<ulong> _patchedTlsImmediateThunkTargets = new HashSet<ulong>();
@@ -539,6 +548,9 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
}
}
private ulong ActiveGuestReturnSlotAddress =>
HasActiveExecutionThread ? _activeGuestReturnSlotAddress : 0;
private bool ActiveForcedGuestExit
{
get => HasActiveExecutionThread ? _activeForcedGuestExit : _forcedGuestExit;
@@ -591,6 +603,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
DirectExecutionBackend? previousBackend,
CpuContext? previousContext,
ulong previousSentinel,
ulong previousReturnSlotAddress,
bool previousForcedExit,
bool previousYieldRequested,
string? previousYieldReason)
@@ -598,6 +611,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
_activeExecutionBackend = previousBackend;
_activeCpuContext = previousContext;
_activeEntryReturnSentinelRip = previousSentinel;
_activeGuestReturnSlotAddress = previousReturnSlotAddress;
_activeForcedGuestExit = previousForcedExit;
_activeGuestThreadYieldRequested = previousYieldRequested;
_activeGuestThreadYieldReason = previousYieldReason;
@@ -634,6 +648,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
throw new OutOfMemoryException("Failed to allocate host stack slot storage");
}
_unresolvedReturnStub = CreateUnresolvedReturnStub();
_guestReturnStub = CreateGuestReturnStub();
if (_guestReturnStub == 0)
{
throw new OutOfMemoryException("Failed to allocate guest return stub");
}
SetupExceptionHandler();
}
@@ -930,9 +949,24 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
yield return "_" + exportName;
}
private static bool IsDirectImportTargetUsable(ulong address)
private bool IsDirectImportTargetUsable(ulong address)
{
return address >= 65536 && !IsUnresolvedSentinel(address);
if (address < 65536 || IsUnresolvedSentinel(address) ||
_cpuContext is null || !TryGetVirtualMemory(_cpuContext, out var virtualMemory))
{
return false;
}
foreach (var region in virtualMemory.SnapshotRegions())
{
if ((region.Protection & ProgramHeaderFlags.Execute) != 0 &&
ContainsAddress(region.VirtualAddress, region.MemorySize, address))
{
return true;
}
}
return false;
}
private unsafe void BindTlsBase(CpuContext context)
@@ -1243,6 +1277,145 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
return (nint)ptr;
}
private unsafe nint CreateGuestReturnStub()
{
const uint stubSize = 256u;
void* ptr = VirtualAlloc(null, stubSize, 12288u, 64u);
if (ptr == null)
{
return 0;
}
byte* code = (byte*)ptr;
int offset = 0;
EmitByte(code, ref offset, 0x48); // sub rsp, 0x20
EmitByte(code, ref offset, 0x83);
EmitByte(code, ref offset, 0xEC);
EmitByte(code, ref offset, 0x20);
EmitByte(code, ref offset, 0xB9); // mov ecx, tlsIndex
EmitUInt32(code, ref offset, _hostRspSlotTlsIndex);
EmitByte(code, ref offset, 0x48); // mov rax, TlsGetValue
EmitByte(code, ref offset, 0xB8);
*(long*)(code + offset) = _tlsGetValueAddress;
offset += sizeof(ulong);
EmitByte(code, ref offset, 0xFF); // call rax
EmitByte(code, ref offset, 0xD0);
EmitByte(code, ref offset, 0x48); // add rsp, 0x20
EmitByte(code, ref offset, 0x83);
EmitByte(code, ref offset, 0xC4);
EmitByte(code, ref offset, 0x20);
EmitByte(code, ref offset, 0x48); // mov rsp, [rax]
EmitByte(code, ref offset, 0x8B);
EmitByte(code, ref offset, 0x20);
EmitHostNonvolatileXmmRestore(code, ref offset);
EmitByte(code, ref offset, 0x41); EmitByte(code, ref offset, 0x5F);
EmitByte(code, ref offset, 0x41); EmitByte(code, ref offset, 0x5E);
EmitByte(code, ref offset, 0x41); EmitByte(code, ref offset, 0x5D);
EmitByte(code, ref offset, 0x41); EmitByte(code, ref offset, 0x5C);
EmitByte(code, ref offset, 0x5E);
EmitByte(code, ref offset, 0x5F);
EmitByte(code, ref offset, 0x5D);
EmitByte(code, ref offset, 0x5B);
EmitByte(code, ref offset, 0xC3);
uint oldProtect = default;
VirtualProtect(ptr, stubSize, 32u, &oldProtect);
FlushInstructionCache(GetCurrentProcess(), ptr, (nuint)offset);
return (nint)ptr;
}
private unsafe nint CreateExceptionHandlerTrampoline(nint managedHandler)
{
const uint stubSize = 256u;
void* ptr = VirtualAlloc(null, stubSize, 12288u, 64u);
if (ptr == null)
{
return 0;
}
byte* code = (byte*)ptr;
int offset = 0;
EmitByte(code, ref offset, 0x41); EmitByte(code, ref offset, 0x54); // push r12
EmitByte(code, ref offset, 0x41); EmitByte(code, ref offset, 0x55); // push r13
EmitByte(code, ref offset, 0x49); EmitByte(code, ref offset, 0x89); EmitByte(code, ref offset, 0xE4); // mov r12, rsp
EmitByte(code, ref offset, 0x49); EmitByte(code, ref offset, 0x89); EmitByte(code, ref offset, 0xCD); // mov r13, rcx
EmitByte(code, ref offset, 0x65); EmitByte(code, ref offset, 0x48); // mov rax, gs:[8]
EmitByte(code, ref offset, 0x8B); EmitByte(code, ref offset, 0x04); EmitByte(code, ref offset, 0x25);
EmitUInt32(code, ref offset, 8u);
EmitByte(code, ref offset, 0x49); EmitByte(code, ref offset, 0x39); EmitByte(code, ref offset, 0xC4); // cmp r12, rax
EmitByte(code, ref offset, 0x0F); EmitByte(code, ref offset, 0x83); // jae guestStack
int aboveStackJump = offset;
EmitUInt32(code, ref offset, 0u);
EmitByte(code, ref offset, 0x65); EmitByte(code, ref offset, 0x48); // mov rax, gs:[0x10]
EmitByte(code, ref offset, 0x8B); EmitByte(code, ref offset, 0x04); EmitByte(code, ref offset, 0x25);
EmitUInt32(code, ref offset, 0x10u);
EmitByte(code, ref offset, 0x49); EmitByte(code, ref offset, 0x39); EmitByte(code, ref offset, 0xC4); // cmp r12, rax
EmitByte(code, ref offset, 0x0F); EmitByte(code, ref offset, 0x82); // jb guestStack
int belowStackJump = offset;
EmitUInt32(code, ref offset, 0u);
EmitByte(code, ref offset, 0x48); EmitByte(code, ref offset, 0x83); EmitByte(code, ref offset, 0xEC); EmitByte(code, ref offset, 0x28);
EmitByte(code, ref offset, 0x4C); EmitByte(code, ref offset, 0x89); EmitByte(code, ref offset, 0xE9); // mov rcx, r13
EmitByte(code, ref offset, 0x48); EmitByte(code, ref offset, 0xB8);
*(nint*)(code + offset) = managedHandler;
offset += sizeof(nint);
EmitByte(code, ref offset, 0xFF); EmitByte(code, ref offset, 0xD0);
EmitByte(code, ref offset, 0x48); EmitByte(code, ref offset, 0x83); EmitByte(code, ref offset, 0xC4); EmitByte(code, ref offset, 0x28);
EmitByte(code, ref offset, 0xE9);
int hostRestoreJump = offset;
EmitUInt32(code, ref offset, 0u);
int guestStackOffset = offset;
EmitByte(code, ref offset, 0x48); EmitByte(code, ref offset, 0x83); EmitByte(code, ref offset, 0xEC); EmitByte(code, ref offset, 0x28);
EmitByte(code, ref offset, 0xB9);
EmitUInt32(code, ref offset, _hostRspSlotTlsIndex);
EmitByte(code, ref offset, 0x48); EmitByte(code, ref offset, 0xB8);
*(nint*)(code + offset) = _tlsGetValueAddress;
offset += sizeof(nint);
EmitByte(code, ref offset, 0xFF); EmitByte(code, ref offset, 0xD0);
EmitByte(code, ref offset, 0x48); EmitByte(code, ref offset, 0x83); EmitByte(code, ref offset, 0xC4); EmitByte(code, ref offset, 0x28);
EmitByte(code, ref offset, 0x48); EmitByte(code, ref offset, 0x85); EmitByte(code, ref offset, 0xC0); // test rax, rax
EmitByte(code, ref offset, 0x0F); EmitByte(code, ref offset, 0x84);
int missingTlsJump = offset;
EmitUInt32(code, ref offset, 0u);
EmitByte(code, ref offset, 0x4C); EmitByte(code, ref offset, 0x8B); EmitByte(code, ref offset, 0x18); // mov r11, [rax]
EmitByte(code, ref offset, 0x4D); EmitByte(code, ref offset, 0x85); EmitByte(code, ref offset, 0xDB); // test r11, r11
EmitByte(code, ref offset, 0x0F); EmitByte(code, ref offset, 0x84);
int missingHostStackJump = offset;
EmitUInt32(code, ref offset, 0u);
EmitByte(code, ref offset, 0x4C); EmitByte(code, ref offset, 0x89); EmitByte(code, ref offset, 0xDC); // mov rsp, r11
EmitByte(code, ref offset, 0x48); EmitByte(code, ref offset, 0x83); EmitByte(code, ref offset, 0xEC); EmitByte(code, ref offset, 0x28);
EmitByte(code, ref offset, 0x4C); EmitByte(code, ref offset, 0x89); EmitByte(code, ref offset, 0xE9); // mov rcx, r13
EmitByte(code, ref offset, 0x48); EmitByte(code, ref offset, 0xB8);
*(nint*)(code + offset) = managedHandler;
offset += sizeof(nint);
EmitByte(code, ref offset, 0xFF); EmitByte(code, ref offset, 0xD0);
EmitByte(code, ref offset, 0x48); EmitByte(code, ref offset, 0x83); EmitByte(code, ref offset, 0xC4); EmitByte(code, ref offset, 0x28);
EmitByte(code, ref offset, 0xE9);
int guestRestoreJump = offset;
EmitUInt32(code, ref offset, 0u);
int passThroughOffset = offset;
EmitByte(code, ref offset, 0x31); EmitByte(code, ref offset, 0xC0); // xor eax, eax
int restoreOffset = offset;
EmitByte(code, ref offset, 0x4C); EmitByte(code, ref offset, 0x89); EmitByte(code, ref offset, 0xE4); // mov rsp, r12
EmitByte(code, ref offset, 0x41); EmitByte(code, ref offset, 0x5D);
EmitByte(code, ref offset, 0x41); EmitByte(code, ref offset, 0x5C);
EmitByte(code, ref offset, 0xC3);
*(int*)(code + aboveStackJump) = guestStackOffset - (aboveStackJump + sizeof(int));
*(int*)(code + belowStackJump) = guestStackOffset - (belowStackJump + sizeof(int));
*(int*)(code + hostRestoreJump) = restoreOffset - (hostRestoreJump + sizeof(int));
*(int*)(code + missingTlsJump) = passThroughOffset - (missingTlsJump + sizeof(int));
*(int*)(code + missingHostStackJump) = passThroughOffset - (missingHostStackJump + sizeof(int));
*(int*)(code + guestRestoreJump) = restoreOffset - (guestRestoreJump + sizeof(int));
uint oldProtect = default;
VirtualProtect(ptr, stubSize, 32u, &oldProtect);
FlushInstructionCache(GetCurrentProcess(), ptr, (nuint)offset);
return (nint)ptr;
}
private unsafe void* TryAllocateNearEntry(nuint size)
{
ulong entryPoint = _entryPoint;
@@ -1980,8 +2153,8 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
{
Rip = continuation.Rip,
Rflags = continuation.Rflags == 0 ? 0x202UL : continuation.Rflags,
FsBase = continuation.FsBase != 0 ? continuation.FsBase : (callerContext.FsBase != 0 ? callerContext.FsBase : fallbackTlsBase),
GsBase = continuation.GsBase != 0 ? continuation.GsBase : (callerContext.GsBase != 0 ? callerContext.GsBase : fallbackTlsBase),
FsBase = callerContext.FsBase != 0 ? callerContext.FsBase : (continuation.FsBase != 0 ? continuation.FsBase : fallbackTlsBase),
GsBase = callerContext.GsBase != 0 ? callerContext.GsBase : (continuation.GsBase != 0 ? continuation.GsBase : fallbackTlsBase),
};
context[CpuRegister.Rax] = continuation.Rax;
@@ -1997,21 +2170,39 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
context[CpuRegister.R13] = continuation.R13;
context[CpuRegister.R14] = continuation.R14;
context[CpuRegister.R15] = continuation.R15;
context[CpuRegister.Rsp] = continuation.Rsp + 16uL;
context[CpuRegister.Rsp] = continuation.Rsp;
var currentGuestThreadHandle = GuestThreadExecution.CurrentGuestThreadHandle;
var exitReason = GuestNativeCallExitReason.Exception;
string? callbackReason = null;
string? callbackLastError = null;
Exception? callbackException = null;
var currentGuestThreadHandle = GuestThreadExecution.CurrentGuestThreadHandle;
var currentFiberAddress = GuestThreadExecution.CurrentFiberAddress;
void RunContinuation()
{
var restoreGuestThread = currentGuestThreadHandle != 0 &&
GuestThreadExecution.CurrentGuestThreadHandle != currentGuestThreadHandle;
var previousGuestThreadHandle = restoreGuestThread
? GuestThreadExecution.EnterGuestThread(currentGuestThreadHandle)
: 0UL;
var restoreFiber = currentFiberAddress != 0 &&
GuestThreadExecution.CurrentFiberAddress != currentFiberAddress;
var previousFiberAddress = restoreFiber
? GuestThreadExecution.EnterFiber(currentFiberAddress)
: 0UL;
var previousLastError = LastError;
try
{
TraceGuestContext(
$"continuation-enter reason={reason} managed={Environment.CurrentManagedThreadId} guest=0x{GuestThreadExecution.CurrentGuestThreadHandle:X16} fiber=0x{GuestThreadExecution.CurrentFiberAddress:X16} captured_guest=0x{currentGuestThreadHandle:X16} captured_fiber=0x{currentFiberAddress:X16} restore_guest={restoreGuestThread} restore_fiber={restoreFiber}");
LastError = null;
exitReason = ExecuteGuestContinuationEntry(context, continuation.Rip, reason, out callbackReason);
exitReason = ExecuteGuestContinuationEntry(
context,
continuation.Rip,
continuation.ReturnSlotAddress,
reason,
out callbackReason);
callbackLastError = LastError;
}
catch (Exception ex)
@@ -2022,7 +2213,17 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
}
finally
{
TraceGuestContext(
$"continuation-exit reason={reason} managed={Environment.CurrentManagedThreadId} guest=0x{GuestThreadExecution.CurrentGuestThreadHandle:X16} fiber=0x{GuestThreadExecution.CurrentFiberAddress:X16} exit={exitReason}");
LastError = previousLastError;
if (restoreFiber)
{
GuestThreadExecution.RestoreFiber(previousFiberAddress);
}
if (restoreGuestThread)
{
GuestThreadExecution.RestoreGuestThread(previousGuestThreadHandle);
}
}
}
@@ -2045,6 +2246,12 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
{
runner.Run(RunContinuation);
}
else if (runner is not null)
{
TraceGuestContext(
$"continuation-inline reason={reason} managed={Environment.CurrentManagedThreadId} guest=0x{currentGuestThreadHandle:X16} fiber=0x{currentFiberAddress:X16}");
RunContinuation();
}
else
{
RunContinuationOnTemporaryThread(currentGuestThreadHandle, RunContinuation);
@@ -2070,6 +2277,14 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
return true;
}
private static void TraceGuestContext(string message)
{
if (string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_CONTEXT"), "1", StringComparison.Ordinal))
{
Console.Error.WriteLine($"[LOADER][TRACE] guest_context.{message}");
}
}
private static void RunContinuationOnTemporaryThread(ulong guestThreadHandle, Action continuation)
{
var continuationThread = new Thread(() =>
@@ -2351,6 +2566,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
var previousActiveBackend = _activeExecutionBackend;
var previousActiveContext = _activeCpuContext;
var previousSentinel = _activeEntryReturnSentinelRip;
var previousReturnSlotAddress = _activeGuestReturnSlotAddress;
var previousForcedExit = _activeForcedGuestExit;
var previousYieldRequested = _activeGuestThreadYieldRequested;
var previousYieldReason = _activeGuestThreadYieldReason;
@@ -2360,6 +2576,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
_activeExecutionBackend = this;
_activeCpuContext = context;
_activeEntryReturnSentinelRip = 0;
_activeGuestReturnSlotAddress = 0;
_activeForcedGuestExit = false;
_activeGuestThreadYieldRequested = false;
_activeGuestThreadYieldReason = null;
@@ -2463,7 +2680,8 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
ptr2[offset++] = 91;
ptr2[offset++] = 195;
ulong sentinel = (ulong)ptr + (ulong)sentinelOffset;
ActiveEntryReturnSentinelRip = sentinel;
ActiveEntryReturnSentinelRip = (ulong)_guestReturnStub;
_activeGuestReturnSlotAddress = context[CpuRegister.Rsp] - 16uL;
if (!context.TryWriteUInt64(context[CpuRegister.Rsp], sentinel))
{
reason = $"failed to patch guest thread return sentinel at 0x{context[CpuRegister.Rsp]:X16}";
@@ -2509,6 +2727,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
previousActiveBackend,
previousActiveContext,
previousSentinel,
previousReturnSlotAddress,
previousForcedExit,
previousYieldRequested,
previousYieldReason);
@@ -2516,7 +2735,12 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
}
}
private unsafe GuestNativeCallExitReason ExecuteGuestContinuationEntry(CpuContext context, ulong entryPoint, string name, out string? reason)
private unsafe GuestNativeCallExitReason ExecuteGuestContinuationEntry(
CpuContext context,
ulong entryPoint,
ulong returnSlotAddress,
string name,
out string? reason)
{
reason = null;
if (context[CpuRegister.Rsp] == 0)
@@ -2534,6 +2758,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
var previousActiveBackend = _activeExecutionBackend;
var previousActiveContext = _activeCpuContext;
var previousSentinel = _activeEntryReturnSentinelRip;
var previousReturnSlotAddress = _activeGuestReturnSlotAddress;
var previousForcedExit = _activeForcedGuestExit;
var previousYieldRequested = _activeGuestThreadYieldRequested;
var previousYieldReason = _activeGuestThreadYieldReason;
@@ -2543,6 +2768,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
_activeExecutionBackend = this;
_activeCpuContext = context;
_activeEntryReturnSentinelRip = 0;
_activeGuestReturnSlotAddress = returnSlotAddress;
_activeForcedGuestExit = false;
_activeGuestThreadYieldRequested = false;
_activeGuestThreadYieldReason = null;
@@ -2577,7 +2803,6 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
Emit(0x49); Emit(0x89); Emit(0x22); // mov [r10], rsp
EmitMovR64Imm(0x48, 0xB8, context[CpuRegister.Rsp]); // mov rax, guest rsp
Emit(0x48); Emit(0x89); Emit(0xC4); // mov rsp, rax
Emit(0x48); Emit(0x83); Emit(0xEC); Emit(0x08); // sub rsp, 8
EmitMovR64Imm(0x48, 0xBB, context[CpuRegister.Rbx]); // mov rbx, imm64
EmitMovR64Imm(0x48, 0xBD, context[CpuRegister.Rbp]); // mov rbp, imm64
EmitMovR64Imm(0x48, 0xBF, context[CpuRegister.Rdi]); // mov rdi, imm64
@@ -2592,29 +2817,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
EmitMovR64Imm(0x49, 0xBF, context[CpuRegister.R15]); // mov r15, imm64
EmitMovR64Imm(0x48, 0xB8, context[CpuRegister.Rax]); // mov rax, imm64
EmitMovR64Imm(0x49, 0xBB, entryPoint); // mov r11, entryPoint
Emit(0x41); Emit(0xFF); Emit(0xD3); // call r11
int sentinelOffset = offset + 4;
Emit(0x48); Emit(0x83); Emit(0xC4); Emit(0x08); // add rsp, 8
EmitMovR64Imm(0x49, 0xBA, hostRspSlot); // mov r10, hostRspSlot
Emit(0x49); Emit(0x8B); Emit(0x22); // mov rsp, [r10]
EmitHostNonvolatileXmmRestore(ptr2, ref offset);
Emit(0x41); Emit(0x5F); // pop r15
Emit(0x41); Emit(0x5E); // pop r14
Emit(0x41); Emit(0x5D); // pop r13
Emit(0x41); Emit(0x5C); // pop r12
Emit(0x5E); // pop rsi
Emit(0x5F); // pop rdi
Emit(0x5D); // pop rbp
Emit(0x5B); // pop rbx
Emit(0xC3); // ret
ulong sentinel = (ulong)ptr + (ulong)sentinelOffset;
ActiveEntryReturnSentinelRip = sentinel;
var sentinelStackAddress = context[CpuRegister.Rsp] >= 16uL
? context[CpuRegister.Rsp] - 16uL
: 0;
if (sentinelStackAddress == 0 || !context.TryWriteUInt64(sentinelStackAddress, sentinel))
Emit(0x41); Emit(0xFF); Emit(0xE3); // jmp r11
ActiveEntryReturnSentinelRip = (ulong)_guestReturnStub;
if (returnSlotAddress == 0 || !context.TryWriteUInt64(returnSlotAddress, (ulong)_guestReturnStub))
{
reason = $"failed to patch guest continuation return sentinel at 0x{sentinelStackAddress:X16}";
reason = $"failed to patch guest continuation return slot at 0x{returnSlotAddress:X16}";
return GuestNativeCallExitReason.Exception;
}
uint oldProtect = default(uint);
@@ -2657,6 +2864,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
previousActiveBackend,
previousActiveContext,
previousSentinel,
previousReturnSlotAddress,
previousForcedExit,
previousYieldRequested,
previousYieldReason);
@@ -2717,9 +2925,18 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
}
EmitByte(code, ref offset, 0x0F);
EmitByte(code, ref offset, store ? (byte)0x7F : (byte)0x6F);
EmitByte(code, ref offset, (byte)(0x44 | ((xmm & 7) << 3)));
EmitByte(code, ref offset, 0x24);
EmitByte(code, ref offset, displacement);
if (displacement < 0x80)
{
EmitByte(code, ref offset, (byte)(0x44 | ((xmm & 7) << 3)));
EmitByte(code, ref offset, 0x24);
EmitByte(code, ref offset, displacement);
}
else
{
EmitByte(code, ref offset, (byte)(0x84 | ((xmm & 7) << 3)));
EmitByte(code, ref offset, 0x24);
EmitUInt32(code, ref offset, displacement);
}
}
private unsafe bool ExecuteEntry(CpuContext context, ulong entryPoint, out OrbisGen2Result result)
@@ -2745,6 +2962,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
var previousActiveBackend = _activeExecutionBackend;
var previousActiveContext = _activeCpuContext;
var previousSentinel = _activeEntryReturnSentinelRip;
var previousReturnSlotAddress = _activeGuestReturnSlotAddress;
var previousForcedExit = _activeForcedGuestExit;
var previousYieldRequested = _activeGuestThreadYieldRequested;
var previousYieldReason = _activeGuestThreadYieldReason;
@@ -2754,6 +2972,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
_activeExecutionBackend = this;
_activeCpuContext = context;
_activeEntryReturnSentinelRip = 0;
_activeGuestReturnSlotAddress = 0;
_activeForcedGuestExit = false;
_activeGuestThreadYieldRequested = false;
_activeGuestThreadYieldReason = null;
@@ -2857,7 +3076,8 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
ptr2[num3++] = 91;
ptr2[num3++] = 195;
ulong value = (ulong)ptr + (ulong)num4;
ActiveEntryReturnSentinelRip = value;
ActiveEntryReturnSentinelRip = (ulong)_guestReturnStub;
_activeGuestReturnSlotAddress = context[CpuRegister.Rsp] - 16uL;
if (!context.TryWriteUInt64(context[CpuRegister.Rsp], value))
{
LastError = $"Failed to patch native return sentinel at 0x{context[CpuRegister.Rsp]:X16}";
@@ -2939,6 +3159,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
previousActiveBackend,
previousActiveContext,
previousSentinel,
previousReturnSlotAddress,
previousForcedExit,
previousYieldRequested,
previousYieldReason);
@@ -3116,6 +3337,22 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
RemoveVectoredExceptionHandler((void*)_rawExceptionHandler);
_rawExceptionHandler = 0;
}
if (_rawExceptionHandlerStub != 0)
{
VirtualFree((void*)_rawExceptionHandlerStub, 0u, 32768u);
_rawExceptionHandlerStub = 0;
}
if (_exceptionHandlerStub != 0)
{
VirtualFree((void*)_exceptionHandlerStub, 0u, 32768u);
_exceptionHandlerStub = 0;
}
if (_unhandledFilterStub != 0)
{
SetUnhandledExceptionFilter(0);
VirtualFree((void*)_unhandledFilterStub, 0u, 32768u);
_unhandledFilterStub = 0;
}
if (_handlerHandle.IsAllocated)
{
_handlerHandle.Free();
@@ -3172,6 +3409,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
VirtualFree((void*)_unresolvedReturnStub, 0u, 32768u);
_unresolvedReturnStub = 0;
}
if (_guestReturnStub != 0)
{
VirtualFree((void*)_guestReturnStub, 0u, 32768u);
_guestReturnStub = 0;
}
if (_lowIndexedTableScratch != 0)
{
VirtualFree((void*)_lowIndexedTableScratch, 0u, 32768u);