From 817a927e317bea83f363d7686d9462a06bb737e3 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 7 Jan 2026 12:03:19 -0800 Subject: [PATCH 1/2] FEXCore: Fixes circular dependency with thunk callback Fixes crash in thunks that use callbacks, introduced in #5148. The dispatcher would call the syscallhandler to get the VDSO thunk callback. But due to reordering initialization, the VDSO thunk would have not been loaded at that point. This would cause thunks that use callbacks to crash with a nullptr exception. Instead, defer the thunk callback pointer loading until the thread starts executing, and load the pointer in to our thread state's pointer struct instead. Didn't get caught in my initial test sweep since I didn't run a Wine game with thunks. --- FEXCore/Source/Interface/Core/Core.cpp | 3 +++ FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp | 2 +- FEXCore/include/FEXCore/Core/CoreState.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/FEXCore/Source/Interface/Core/Core.cpp b/FEXCore/Source/Interface/Core/Core.cpp index d5b8dd390b..21fdc83efc 100644 --- a/FEXCore/Source/Interface/Core/Core.cpp +++ b/FEXCore/Source/Interface/Core/Core.cpp @@ -363,6 +363,9 @@ void ContextImpl::HandleCallback(FEXCore::Core::InternalThreadState* Thread, uin } void ContextImpl::ExecuteThread(FEXCore::Core::InternalThreadState* Thread) { + // Update the thread pointer for Thunk return to the latest. + Thread->CurrentFrame->Pointers.AArch64.ThunkCallbackRet = SignalDelegation->GetThunkCallbackRET(); + Dispatcher->ExecuteDispatch(Thread->CurrentFrame); // If it is the parent thread that died then just leave diff --git a/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp b/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp index 41bd494914..e67fdd64dd 100644 --- a/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp +++ b/FEXCore/Source/Interface/Core/Dispatcher/Dispatcher.cpp @@ -488,7 +488,7 @@ void Dispatcher::EmitDispatcher() { // Now push the callback return trampoline to the guest stack // Guest will be misaligned because calling a thunk won't correct the guest's stack once we call the callback from the host - LoadConstant(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r0, CTX->SignalDelegation->GetThunkCallbackRET()); + ldr(ARMEmitter::XReg::x0, STATE_PTR(CpuStateFrame, Pointers.AArch64.ThunkCallbackRet)); ldr(ARMEmitter::XReg::x2, STATE_PTR(CpuStateFrame, State.gregs[X86State::REG_RSP])); sub(ARMEmitter::Size::i64Bit, ARMEmitter::Reg::r2, ARMEmitter::Reg::r2, CTX->Config.Is64BitMode ? 16 : 12); diff --git a/FEXCore/include/FEXCore/Core/CoreState.h b/FEXCore/include/FEXCore/Core/CoreState.h index 80203c13b1..144ea9e1c0 100644 --- a/FEXCore/include/FEXCore/Core/CoreState.h +++ b/FEXCore/include/FEXCore/Core/CoreState.h @@ -370,6 +370,7 @@ struct JITPointers { // Process specific uint64_t LUDIV {}; uint64_t LDIV {}; + uint64_t ThunkCallbackRet {}; // Thread Specific From 291e261a6597461a3d055eabb7b6542e2daf5670 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Wed, 7 Jan 2026 12:19:22 -0800 Subject: [PATCH 2/2] InstcountCI: Update --- unittests/InstructionCountCI/PrimaryGroup.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unittests/InstructionCountCI/PrimaryGroup.json b/unittests/InstructionCountCI/PrimaryGroup.json index ff965d85cc..94ab6ab86a 100644 --- a/unittests/InstructionCountCI/PrimaryGroup.json +++ b/unittests/InstructionCountCI/PrimaryGroup.json @@ -2786,7 +2786,7 @@ "mov x0, x5", "mov x1, x4", "mov x2, x6", - "ldr x3, [x28, #3568]", + "ldr x3, [x28, #3576]", "str x30, [sp, #-16]!", "blr x3", "ldr x30, [sp], #16", @@ -2837,7 +2837,7 @@ "mov x0, x5", "mov x1, x4", "mov x2, x6", - "ldr x3, [x28, #3576]", + "ldr x3, [x28, #3584]", "str x30, [sp, #-16]!", "blr x3", "ldr x30, [sp], #16",