mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-23 08:00:39 +02:00
Merge pull request #4075 from Sonicadvance1/move_thunkhandler
Thunks: Move to the frontend
This commit is contained in:
23 files changed
+382
-345
No files matched your search
@@ -127,7 +127,6 @@ set (SRCS
|
||||
Interface/Core/X86Tables/VEXTables.cpp
|
||||
Interface/Core/X86Tables/X87Tables.cpp
|
||||
Interface/Core/X86Tables/XOPTables.cpp
|
||||
Interface/HLE/Thunks/Thunks.cpp
|
||||
Interface/GDBJIT/GDBJIT.cpp
|
||||
Interface/IR/AOTIR.cpp
|
||||
Interface/IR/IRDumper.cpp
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <FEXCore/Core/CPUID.h>
|
||||
#include <FEXCore/Core/HostFeatures.h>
|
||||
#include <FEXCore/Core/SignalDelegator.h>
|
||||
#include <FEXCore/Core/Thunks.h>
|
||||
#include "FEXCore/Debug/InternalThreadState.h"
|
||||
|
||||
#include <string.h>
|
||||
@@ -48,6 +49,10 @@ void FEXCore::Context::ContextImpl::SetSyscallHandler(FEXCore::HLE::SyscallHandl
|
||||
SourcecodeResolver = Handler->GetSourcecodeResolver();
|
||||
}
|
||||
|
||||
void FEXCore::Context::ContextImpl::SetThunkHandler(FEXCore::ThunkHandler* Handler) {
|
||||
ThunkHandler = Handler;
|
||||
}
|
||||
|
||||
FEXCore::CPUID::FunctionResults FEXCore::Context::ContextImpl::RunCPUIDFunction(uint32_t Function, uint32_t Leaf) {
|
||||
return CPUID.RunFunction(Function, Leaf);
|
||||
}
|
||||
|
||||
@@ -68,17 +68,9 @@ struct CustomIRResult {
|
||||
void* Creator;
|
||||
void* Data;
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return !lock;
|
||||
}
|
||||
|
||||
CustomIRResult(std::unique_lock<std::shared_mutex>&& lock, void* Creator, void* Data)
|
||||
CustomIRResult(void* Creator, void* Data)
|
||||
: Creator(Creator)
|
||||
, Data(Data)
|
||||
, lock(std::move(lock)) {}
|
||||
|
||||
private:
|
||||
std::unique_lock<std::shared_mutex> lock;
|
||||
, Data(Data) {}
|
||||
};
|
||||
|
||||
using BlockDelinkerFunc = void (*)(FEXCore::Core::CpuStateFrame* Frame, FEXCore::Context::ExitFunctionLinkData* Record);
|
||||
@@ -155,6 +147,7 @@ public:
|
||||
#endif
|
||||
void SetSignalDelegator(FEXCore::SignalDelegator* SignalDelegation) override;
|
||||
void SetSyscallHandler(FEXCore::HLE::SyscallHandler* Handler) override;
|
||||
void SetThunkHandler(FEXCore::ThunkHandler* Handler) override;
|
||||
|
||||
FEXCore::CPUID::FunctionResults RunCPUIDFunction(uint32_t Function, uint32_t Leaf) override;
|
||||
FEXCore::CPUID::XCRResults RunXCRFunction(uint32_t Function) override;
|
||||
@@ -194,9 +187,10 @@ public:
|
||||
bool IsAddressInCodeBuffer(FEXCore::Core::InternalThreadState* Thread, uintptr_t Address) const override;
|
||||
|
||||
// returns false if a handler was already registered
|
||||
CustomIRResult AddCustomIREntrypoint(uintptr_t Entrypoint, CustomIREntrypointHandler Handler, void* Creator = nullptr, void* Data = nullptr);
|
||||
std::optional<CustomIRResult>
|
||||
AddCustomIREntrypoint(uintptr_t Entrypoint, CustomIREntrypointHandler Handler, void* Creator = nullptr, void* Data = nullptr);
|
||||
|
||||
void AppendThunkDefinitions(std::span<const FEXCore::IR::ThunkDefinition> Definitions) override;
|
||||
void AddThunkTrampolineIRHandler(uintptr_t Entrypoint, uintptr_t GuestThunkEntrypoint) override;
|
||||
|
||||
public:
|
||||
friend class FEXCore::HLE::SyscallHandler;
|
||||
@@ -228,9 +222,6 @@ public:
|
||||
FEX_CONFIG_OPT(SMCChecks, SMCCHECKS);
|
||||
FEX_CONFIG_OPT(MaxInstPerBlock, MAXINST);
|
||||
FEX_CONFIG_OPT(RootFSPath, ROOTFS);
|
||||
FEX_CONFIG_OPT(ThunkHostLibsPath, THUNKHOSTLIBS);
|
||||
FEX_CONFIG_OPT(ThunkHostLibsPath32, THUNKHOSTLIBS32);
|
||||
FEX_CONFIG_OPT(ThunkConfigFile, THUNKCONFIG);
|
||||
FEX_CONFIG_OPT(GlobalJITNaming, GLOBALJITNAMING);
|
||||
FEX_CONFIG_OPT(LibraryJITNaming, LIBRARYJITNAMING);
|
||||
FEX_CONFIG_OPT(BlockJITNaming, BLOCKJITNAMING);
|
||||
@@ -255,7 +246,7 @@ public:
|
||||
FEXCore::CPUIDEmu CPUID;
|
||||
FEXCore::HLE::SyscallHandler* SyscallHandler {};
|
||||
FEXCore::HLE::SourcecodeResolver* SourcecodeResolver {};
|
||||
fextl::unique_ptr<FEXCore::ThunkHandler> ThunkHandler;
|
||||
FEXCore::ThunkHandler* ThunkHandler {};
|
||||
fextl::unique_ptr<FEXCore::CPU::Dispatcher> Dispatcher;
|
||||
|
||||
FEXCore::Context::ExitHandler CustomExitHandler;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "FEXCore/Utils/AllocatorHooks.h"
|
||||
#include "Interface/Core/Dispatcher/Dispatcher.h"
|
||||
#include "Interface/Context/Context.h"
|
||||
#include "Interface/HLE/Thunks/Thunks.h"
|
||||
|
||||
#include <FEXCore/Core/CoreState.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
|
||||
@@ -19,7 +19,6 @@ $end_info$
|
||||
#include "Interface/Core/JIT/JITCore.h"
|
||||
#include "Interface/Core/Dispatcher/Dispatcher.h"
|
||||
#include "Interface/Core/X86Tables/X86Tables.h"
|
||||
#include "Interface/HLE/Thunks/Thunks.h"
|
||||
#include "Interface/IR/IR.h"
|
||||
#include "Interface/IR/IREmitter.h"
|
||||
#include "Interface/IR/Passes/RegisterAllocationPass.h"
|
||||
@@ -34,6 +33,7 @@ $end_info$
|
||||
#include <FEXCore/Core/Context.h>
|
||||
#include <FEXCore/Core/CoreState.h>
|
||||
#include <FEXCore/Core/SignalDelegator.h>
|
||||
#include <FEXCore/Core/Thunks.h>
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
#include <FEXCore/Debug/InternalThreadState.h>
|
||||
#include <FEXCore/HLE/SyscallHandler.h>
|
||||
@@ -346,7 +346,6 @@ bool ContextImpl::InitCore() {
|
||||
SignalDelegation->SetConfig(SignalConfig);
|
||||
|
||||
#ifndef _WIN32
|
||||
ThunkHandler = FEXCore::ThunkHandler::Create();
|
||||
#elif !defined(_M_ARM64EC)
|
||||
// WOW64 always needs the interrupt fault check to be enabled.
|
||||
Config.NeedsPendingInterruptFaultCheck = true;
|
||||
@@ -386,9 +385,6 @@ void ContextImpl::ExecuteThread(FEXCore::Core::InternalThreadState* Thread) {
|
||||
|
||||
void ContextImpl::InitializeThreadTLSData(FEXCore::Core::InternalThreadState* Thread) {
|
||||
// Let's do some initial bookkeeping here
|
||||
if (ThunkHandler) {
|
||||
ThunkHandler->RegisterTLSState(Thread);
|
||||
}
|
||||
#ifndef _WIN32
|
||||
Alloc::OSAllocator::RegisterTLSData(Thread);
|
||||
#endif
|
||||
@@ -982,7 +978,8 @@ void ContextImpl::ThreadRemoveCodeEntry(FEXCore::Core::InternalThreadState* Thre
|
||||
Thread->LookupCache->Erase(Thread->CurrentFrame, GuestRIP);
|
||||
}
|
||||
|
||||
CustomIRResult ContextImpl::AddCustomIREntrypoint(uintptr_t Entrypoint, CustomIREntrypointHandler Handler, void* Creator, void* Data) {
|
||||
std::optional<CustomIRResult>
|
||||
ContextImpl::AddCustomIREntrypoint(uintptr_t Entrypoint, CustomIREntrypointHandler Handler, void* Creator, void* Data) {
|
||||
LOGMAN_THROW_A_FMT(Config.Is64BitMode || !(Entrypoint >> 32), "64-bit Entrypoint in 32-bit mode {:x}", Entrypoint);
|
||||
|
||||
std::unique_lock lk(CustomIRMutex);
|
||||
@@ -992,10 +989,50 @@ CustomIRResult ContextImpl::AddCustomIREntrypoint(uintptr_t Entrypoint, CustomIR
|
||||
|
||||
if (!InsertedIterator.second) {
|
||||
const auto& [fn, Creator, Data] = InsertedIterator.first->second;
|
||||
return CustomIRResult(std::move(lk), Creator, Data);
|
||||
} else {
|
||||
lk.unlock();
|
||||
return CustomIRResult(std::move(lk), 0, 0);
|
||||
return CustomIRResult(Creator, Data);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void ContextImpl::AddThunkTrampolineIRHandler(uintptr_t Entrypoint, uintptr_t GuestThunkEntrypoint) {
|
||||
LOGMAN_THROW_AA_FMT(Entrypoint, "Tried to link null pointer address to guest function");
|
||||
LOGMAN_THROW_AA_FMT(GuestThunkEntrypoint, "Tried to link address to null pointer guest function");
|
||||
if (!Config.Is64BitMode) {
|
||||
LOGMAN_THROW_AA_FMT((Entrypoint >> 32) == 0, "Tried to link 64-bit address in 32-bit mode");
|
||||
LOGMAN_THROW_AA_FMT((GuestThunkEntrypoint >> 32) == 0, "Tried to link 64-bit address in 32-bit mode");
|
||||
}
|
||||
|
||||
LogMan::Msg::DFmt("Thunks: Adding guest trampoline from address {:#x} to guest function {:#x}", Entrypoint, GuestThunkEntrypoint);
|
||||
|
||||
auto Result = AddCustomIREntrypoint(
|
||||
Entrypoint,
|
||||
[this, GuestThunkEntrypoint](uintptr_t Entrypoint, FEXCore::IR::IREmitter* emit) {
|
||||
auto IRHeader = emit->_IRHeader(emit->Invalid(), Entrypoint, 0, 0);
|
||||
auto Block = emit->CreateCodeNode();
|
||||
IRHeader.first->Blocks = emit->WrapNode(Block);
|
||||
emit->SetCurrentCodeBlock(Block);
|
||||
|
||||
const uint8_t GPRSize = GetGPRSize();
|
||||
|
||||
if (GPRSize == 8) {
|
||||
emit->_StoreRegister(emit->_Constant(Entrypoint), X86State::REG_R11, IR::GPRClass, GPRSize);
|
||||
} else {
|
||||
emit->_StoreContext(GPRSize, IR::FPRClass, emit->_VCastFromGPR(8, 8, emit->_Constant(Entrypoint)), offsetof(Core::CPUState, mm[0][0]));
|
||||
}
|
||||
emit->_ExitFunction(emit->_Constant(GuestThunkEntrypoint));
|
||||
},
|
||||
ThunkHandler, (void*)GuestThunkEntrypoint);
|
||||
|
||||
if (Result.has_value()) {
|
||||
if (Result->Creator != ThunkHandler) {
|
||||
ERROR_AND_DIE_FMT("Input address for AddThunkTrampoline is already linked by another module");
|
||||
}
|
||||
if (Result->Data != (void*)GuestThunkEntrypoint) {
|
||||
// NOTE: This may happen in Vulkan thunks if the Vulkan driver resolves two different symbols
|
||||
// to the same function (e.g. vkGetPhysicalDeviceFeatures2/vkGetPhysicalDeviceFeatures2KHR)
|
||||
LogMan::Msg::EFmt("Input address for AddThunkTrampoline is already linked elsewhere");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1018,12 +1055,6 @@ void ContextImpl::UnloadAOTIRCacheEntry(IR::AOTIRCacheEntry* Entry) {
|
||||
IRCaptureCache.UnloadAOTIRCacheEntry(Entry);
|
||||
}
|
||||
|
||||
void ContextImpl::AppendThunkDefinitions(std::span<const FEXCore::IR::ThunkDefinition> Definitions) {
|
||||
if (ThunkHandler) {
|
||||
ThunkHandler->AppendThunkDefinitions(Definitions);
|
||||
}
|
||||
}
|
||||
|
||||
void ContextImpl::ConfigureAOTGen(FEXCore::Core::InternalThreadState* Thread, fextl::set<uint64_t>* ExternalBranches, uint64_t SectionMaxAddress) {
|
||||
Thread->FrontendDecoder->SetExternalBranches(ExternalBranches);
|
||||
Thread->FrontendDecoder->SetSectionMaxAddress(SectionMaxAddress);
|
||||
|
||||
@@ -7,7 +7,8 @@ $end_info$
|
||||
*/
|
||||
#include "Interface/Context/Context.h"
|
||||
#include "Interface/Core/JIT/Arm64/JITClass.h"
|
||||
#include "Interface/HLE/Thunks/Thunks.h"
|
||||
|
||||
#include <FEXCore/Core/Thunks.h>
|
||||
|
||||
namespace FEXCore::CPU {
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@ $end_info$
|
||||
|
||||
#include "Interface/Core/JIT/Arm64/JITClass.h"
|
||||
|
||||
#include <FEXCore/Core/Thunks.h>
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
#include <FEXCore/Debug/InternalThreadState.h>
|
||||
#include <FEXCore/HLE/SyscallHandler.h>
|
||||
#include <FEXCore/Utils/MathUtils.h>
|
||||
#include <Interface/HLE/Thunks/Thunks.h>
|
||||
|
||||
namespace FEXCore::CPU {
|
||||
#define DEF_OP(x) void Arm64JITCore::Op_##x(IR::IROp_Header const* IROp, IR::NodeID Node)
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace FEXCore {
|
||||
class CodeLoader;
|
||||
struct HostFeatures;
|
||||
class ForkableSharedMutex;
|
||||
class ThunkHandler;
|
||||
} // namespace FEXCore
|
||||
|
||||
namespace FEXCore::Core {
|
||||
@@ -175,6 +176,7 @@ public:
|
||||
#endif
|
||||
FEX_DEFAULT_VISIBILITY virtual void SetSignalDelegator(FEXCore::SignalDelegator* SignalDelegation) = 0;
|
||||
FEX_DEFAULT_VISIBILITY virtual void SetSyscallHandler(FEXCore::HLE::SyscallHandler* Handler) = 0;
|
||||
FEX_DEFAULT_VISIBILITY virtual void SetThunkHandler(FEXCore::ThunkHandler* Handler) = 0;
|
||||
|
||||
FEX_DEFAULT_VISIBILITY virtual FEXCore::CPUID::FunctionResults RunCPUIDFunction(uint32_t Function, uint32_t Leaf) = 0;
|
||||
FEX_DEFAULT_VISIBILITY virtual FEXCore::CPUID::XCRResults RunXCRFunction(uint32_t Function) = 0;
|
||||
@@ -211,14 +213,6 @@ public:
|
||||
*/
|
||||
FEX_DEFAULT_VISIBILITY virtual bool IsAddressInCodeBuffer(FEXCore::Core::InternalThreadState* Thread, uintptr_t Address) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Allows the frontend to register its own thunk handlers independent of what is controlled in the backend.
|
||||
*
|
||||
* @param CTX A valid non-null context instance.
|
||||
* @param Definitions A vector of thunk definitions that the frontend controls
|
||||
*/
|
||||
FEX_DEFAULT_VISIBILITY virtual void AppendThunkDefinitions(std::span<const FEXCore::IR::ThunkDefinition> Definitions) = 0;
|
||||
|
||||
/**
|
||||
* @brief Informs the context if hardware TSO is supported.
|
||||
* Once hardware TSO is enabled, then TSO emulation through atomics is disabled and relies on the hardware.
|
||||
@@ -235,6 +229,14 @@ public:
|
||||
*/
|
||||
FEX_DEFAULT_VISIBILITY virtual void EnableExitOnHLT() = 0;
|
||||
|
||||
/**
|
||||
* @brief Adds a new Thunk trampoline handler
|
||||
*
|
||||
* @param Entrypoint The guest PC that the custom thunk trampoline IR handler will be installed at.
|
||||
* @param GuestThunkEntrypoint The thunk entrypoint that the IR handler will redirect to.
|
||||
*/
|
||||
FEX_DEFAULT_VISIBILITY virtual void AddThunkTrampolineIRHandler(uintptr_t Entrypoint, uintptr_t GuestThunkEntrypoint) = 0;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
+2
-8
@@ -7,13 +7,12 @@ $end_info$
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Interface/IR/IR.h"
|
||||
|
||||
#include <FEXCore/fextl/memory.h>
|
||||
#include <FEXCore/fextl/vector.h>
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
namespace FEXCore::Context {
|
||||
class ContextImpl;
|
||||
class Context;
|
||||
}
|
||||
|
||||
namespace FEXCore::Core {
|
||||
@@ -30,11 +29,6 @@ typedef void ThunkedFunction(void* ArgsRv);
|
||||
class ThunkHandler {
|
||||
public:
|
||||
virtual ThunkedFunction* LookupThunk(const IR::SHA256Sum& sha256) = 0;
|
||||
virtual void RegisterTLSState(FEXCore::Core::InternalThreadState* Thread) = 0;
|
||||
virtual ~ThunkHandler() {}
|
||||
|
||||
static fextl::unique_ptr<ThunkHandler> Create();
|
||||
|
||||
virtual void AppendThunkDefinitions(std::span<const FEXCore::IR::ThunkDefinition> Definitions) = 0;
|
||||
};
|
||||
}; // namespace FEXCore
|
||||
@@ -21,6 +21,7 @@ $end_info$
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
#include "LinuxSyscalls/SignalDelegator.h"
|
||||
#include "Linux/Utils/ELFContainer.h"
|
||||
#include "Thunks.h"
|
||||
|
||||
#include <FEXCore/Config/Config.h>
|
||||
#include <FEXCore/Core/Context.h>
|
||||
@@ -510,9 +511,11 @@ int main(int argc, char** argv, char** const envp) {
|
||||
FEX::TSO::SetupTSOEmulation(CTX.get());
|
||||
|
||||
auto SignalDelegation = FEX::HLE::CreateSignalDelegator(CTX.get(), Program.ProgramName, SupportsAVX);
|
||||
auto ThunkHandler = FEX::HLE::CreateThunkHandler();
|
||||
|
||||
auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX.get(), SignalDelegation.get()) :
|
||||
FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), std::move(Allocator));
|
||||
auto SyscallHandler = Loader.Is64BitMode() ?
|
||||
FEX::HLE::x64::CreateHandler(CTX.get(), SignalDelegation.get(), ThunkHandler.get()) :
|
||||
FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), ThunkHandler.get(), std::move(Allocator));
|
||||
|
||||
// Load VDSO in to memory prior to mapping our ELFs.
|
||||
auto VDSOMapping = FEX::VDSO::LoadVDSOThunks(Loader.Is64BitMode(), SyscallHandler.get());
|
||||
@@ -545,6 +548,7 @@ int main(int argc, char** argv, char** const envp) {
|
||||
|
||||
CTX->SetSignalDelegator(SignalDelegation.get());
|
||||
CTX->SetSyscallHandler(SyscallHandler.get());
|
||||
CTX->SetThunkHandler(ThunkHandler.get());
|
||||
|
||||
FEX_CONFIG_OPT(GdbServer, GDBSERVER);
|
||||
fextl::unique_ptr<FEX::GdbServer> DebugServer;
|
||||
@@ -559,9 +563,10 @@ int main(int argc, char** argv, char** const envp) {
|
||||
auto ParentThread = SyscallHandler->TM.CreateThread(Loader.DefaultRIP(), Loader.GetStackPointer());
|
||||
SyscallHandler->TM.TrackThread(ParentThread);
|
||||
SignalDelegation->RegisterTLSState(ParentThread);
|
||||
ThunkHandler->RegisterTLSState(ParentThread);
|
||||
|
||||
// Pass in our VDSO thunks
|
||||
CTX->AppendThunkDefinitions(FEX::VDSO::GetVDSOThunkDefinitions());
|
||||
ThunkHandler->AppendThunkDefinitions(FEX::VDSO::GetVDSOThunkDefinitions());
|
||||
SignalDelegation->SetVDSOSigReturn();
|
||||
|
||||
SyscallHandler->DeserializeSeccompFD(ParentThread, FEXSeccompFD);
|
||||
|
||||
@@ -2,6 +2,7 @@ add_compile_options(-fno-operator-names)
|
||||
|
||||
set (SRCS
|
||||
VDSO_Emulation.cpp
|
||||
Thunks.cpp
|
||||
LinuxSyscalls/GdbServer.cpp
|
||||
LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp
|
||||
LinuxSyscalls/FaultSafeUserMemAccess.cpp
|
||||
|
||||
@@ -21,6 +21,7 @@ $end_info$
|
||||
#include "LinuxSyscalls/x64/Syscalls.h"
|
||||
#include "LinuxSyscalls/x32/Types.h"
|
||||
#include "LinuxSyscalls/x64/Types.h"
|
||||
#include "Thunks.h"
|
||||
|
||||
#include <FEXCore/Config/Config.h>
|
||||
#include <FEXCore/Core/Context.h>
|
||||
@@ -740,12 +741,13 @@ void SyscallHandler::DefaultProgramBreak(uint64_t Base, uint64_t Size) {
|
||||
DataSpaceStartingSize = Size;
|
||||
}
|
||||
|
||||
SyscallHandler::SyscallHandler(FEXCore::Context::Context* _CTX, FEX::HLE::SignalDelegator* _SignalDelegation)
|
||||
SyscallHandler::SyscallHandler(FEXCore::Context::Context* _CTX, FEX::HLE::SignalDelegator* _SignalDelegation, FEX::HLE::ThunkHandler* ThunkHandler)
|
||||
: TM {_CTX, _SignalDelegation}
|
||||
, SeccompEmulator {this, _SignalDelegation}
|
||||
, FM {_CTX}
|
||||
, CTX {_CTX}
|
||||
, SignalDelegation {_SignalDelegation} {
|
||||
, SignalDelegation {_SignalDelegation}
|
||||
, ThunkHandler {ThunkHandler} {
|
||||
FEX::HLE::_SyscallHandler = this;
|
||||
HostKernelVersion = CalculateHostKernelVersion();
|
||||
GuestKernelVersion = CalculateGuestKernelVersion();
|
||||
@@ -872,6 +874,15 @@ void SyscallHandler::UnlockAfterFork(FEXCore::Core::InternalThreadState* LiveThr
|
||||
TM.UnlockAfterFork(LiveThread, Child);
|
||||
}
|
||||
|
||||
void SyscallHandler::RegisterTLSState(FEX::HLE::ThreadStateObject* Thread) {
|
||||
SignalDelegation->RegisterTLSState(Thread);
|
||||
ThunkHandler->RegisterTLSState(Thread);
|
||||
}
|
||||
|
||||
void SyscallHandler::UninstallTLSState(FEX::HLE::ThreadStateObject* Thread) {
|
||||
SignalDelegation->UninstallTLSState(Thread);
|
||||
}
|
||||
|
||||
static bool isHEX(char c) {
|
||||
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ $end_info$
|
||||
#include "LinuxSyscalls/Seccomp/SeccompEmulator.h"
|
||||
|
||||
#include <FEXCore/Config/Config.h>
|
||||
#include <FEXCore/Core/Thunks.h>
|
||||
#include <FEXCore/HLE/SyscallHandler.h>
|
||||
#include <FEXCore/HLE/SourcecodeResolver.h>
|
||||
#include <FEXCore/IR/IR.h>
|
||||
@@ -66,6 +67,8 @@ namespace FEX::HLE {
|
||||
|
||||
class SyscallHandler;
|
||||
class SignalDelegator;
|
||||
class ThunkHandler;
|
||||
|
||||
void RegisterEpoll(FEX::HLE::SyscallHandler* Handler);
|
||||
void RegisterFD(FEX::HLE::SyscallHandler* Handler);
|
||||
void RegisterFS(FEX::HLE::SyscallHandler* Handler);
|
||||
@@ -189,6 +192,10 @@ public:
|
||||
return SignalDelegation;
|
||||
}
|
||||
|
||||
FEX::HLE::ThunkHandler* GetThunkHandler() {
|
||||
return ThunkHandler;
|
||||
}
|
||||
|
||||
FEX_CONFIG_OPT(IsInterpreter, IS_INTERPRETER);
|
||||
FEX_CONFIG_OPT(IsInterpreterInstalled, INTERPRETER_INSTALLED);
|
||||
FEX_CONFIG_OPT(Filename, APP_FILENAME);
|
||||
@@ -254,6 +261,9 @@ public:
|
||||
void LockBeforeFork(FEXCore::Core::InternalThreadState* Thread);
|
||||
void UnlockAfterFork(FEXCore::Core::InternalThreadState* LiveThread, bool Child);
|
||||
|
||||
void RegisterTLSState(FEX::HLE::ThreadStateObject* Thread);
|
||||
void UninstallTLSState(FEX::HLE::ThreadStateObject* Thread);
|
||||
|
||||
SourcecodeResolver* GetSourcecodeResolver() override {
|
||||
return this;
|
||||
}
|
||||
@@ -272,7 +282,7 @@ public:
|
||||
constexpr static uint64_t TASK_MAX_64BIT = (1ULL << 48);
|
||||
|
||||
protected:
|
||||
SyscallHandler(FEXCore::Context::Context* _CTX, FEX::HLE::SignalDelegator* _SignalDelegation);
|
||||
SyscallHandler(FEXCore::Context::Context* _CTX, FEX::HLE::SignalDelegator* _SignalDelegation, FEX::HLE::ThunkHandler* ThunkHandler);
|
||||
|
||||
fextl::vector<SyscallFunctionDefinition> Definitions {std::max<std::size_t>(FEX::HLE::x64::SYSCALL_x64_MAX, FEX::HLE::x32::SYSCALL_x86_MAX),
|
||||
{
|
||||
@@ -296,6 +306,7 @@ protected:
|
||||
private:
|
||||
|
||||
FEX::HLE::SignalDelegator* SignalDelegation;
|
||||
FEX::HLE::ThunkHandler* ThunkHandler;
|
||||
|
||||
std::mutex FutexMutex;
|
||||
std::mutex SyscallMutex;
|
||||
|
||||
@@ -57,9 +57,9 @@ static void* ThreadHandler(void* Data) {
|
||||
Thread->ThreadInfo.PID = ::getpid();
|
||||
Thread->ThreadInfo.TID = FHU::Syscalls::gettid();
|
||||
|
||||
FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterTLSState(Thread);
|
||||
FEX::HLE::_SyscallHandler->RegisterTLSState(Thread);
|
||||
CTX->ExecutionThread(Thread->Thread);
|
||||
FEX::HLE::_SyscallHandler->GetSignalDelegator()->UninstallTLSState(Thread);
|
||||
FEX::HLE::_SyscallHandler->UninstallTLSState(Thread);
|
||||
FEX::HLE::_SyscallHandler->TM.DestroyThread(Thread);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -216,13 +216,13 @@ uint64_t HandleNewClone(FEX::HLE::ThreadStateObject* Thread, FEXCore::Context::C
|
||||
FEX::HLE::_SyscallHandler->TM.TrackThread(Thread);
|
||||
}
|
||||
|
||||
FEX::HLE::_SyscallHandler->GetSignalDelegator()->RegisterTLSState(Thread);
|
||||
FEX::HLE::_SyscallHandler->RegisterTLSState(Thread);
|
||||
|
||||
// Start exuting the thread directly
|
||||
// Our host clone starts in a new stack space, so it can't return back to the JIT space
|
||||
CTX->ExecutionThread(Thread->Thread);
|
||||
|
||||
FEX::HLE::_SyscallHandler->GetSignalDelegator()->UninstallTLSState(Thread);
|
||||
FEX::HLE::_SyscallHandler->UninstallTLSState(Thread);
|
||||
|
||||
// The rest of the context remains as is and the thread will continue executing
|
||||
return Thread->Thread->StatusCode;
|
||||
|
||||
@@ -43,8 +43,8 @@ void RegisterTimer(FEX::HLE::SyscallHandler* Handler);
|
||||
void RegisterPassthrough(FEX::HLE::SyscallHandler* Handler);
|
||||
|
||||
x32SyscallHandler::x32SyscallHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation,
|
||||
fextl::unique_ptr<MemAllocator> Allocator)
|
||||
: SyscallHandler {ctx, _SignalDelegation}
|
||||
FEX::HLE::ThunkHandler* ThunkHandler, fextl::unique_ptr<MemAllocator> Allocator)
|
||||
: SyscallHandler {ctx, _SignalDelegation, ThunkHandler}
|
||||
, AllocHandler {std::move(Allocator)} {
|
||||
OSABI = FEXCore::HLE::SyscallOSABI::OS_LINUX32;
|
||||
RegisterSyscallHandlers();
|
||||
@@ -91,9 +91,9 @@ void x32SyscallHandler::RegisterSyscallHandlers() {
|
||||
#endif
|
||||
}
|
||||
|
||||
fextl::unique_ptr<FEX::HLE::SyscallHandler>
|
||||
CreateHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation, fextl::unique_ptr<MemAllocator> Allocator) {
|
||||
return fextl::make_unique<x32SyscallHandler>(ctx, _SignalDelegation, std::move(Allocator));
|
||||
fextl::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation,
|
||||
FEX::HLE::ThunkHandler* ThunkHandler, fextl::unique_ptr<MemAllocator> Allocator) {
|
||||
return fextl::make_unique<x32SyscallHandler>(ctx, _SignalDelegation, ThunkHandler, std::move(Allocator));
|
||||
}
|
||||
|
||||
} // namespace FEX::HLE::x32
|
||||
@@ -28,13 +28,15 @@ namespace Core {
|
||||
|
||||
namespace FEX::HLE {
|
||||
class SignalDelegator;
|
||||
}
|
||||
class ThunkHandler;
|
||||
} // namespace FEX::HLE
|
||||
|
||||
namespace FEX::HLE::x32 {
|
||||
|
||||
class x32SyscallHandler final : public FEX::HLE::SyscallHandler {
|
||||
public:
|
||||
x32SyscallHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation, fextl::unique_ptr<MemAllocator> Allocator);
|
||||
x32SyscallHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation, FEX::HLE::ThunkHandler* ThunkHandler,
|
||||
fextl::unique_ptr<MemAllocator> Allocator);
|
||||
|
||||
FEX::HLE::MemAllocator* GetAllocator() {
|
||||
return AllocHandler.get();
|
||||
@@ -65,8 +67,8 @@ private:
|
||||
fextl::unique_ptr<MemAllocator> AllocHandler {};
|
||||
};
|
||||
|
||||
fextl::unique_ptr<FEX::HLE::SyscallHandler>
|
||||
CreateHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation, fextl::unique_ptr<MemAllocator> Allocator);
|
||||
fextl::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation,
|
||||
FEX::HLE::ThunkHandler* ThunkHandler, fextl::unique_ptr<MemAllocator> Allocator);
|
||||
//////
|
||||
// REGISTER_SYSCALL_IMPL implementation
|
||||
// Given a syscall name + a lambda, and it will generate an strace string, extract number of arguments
|
||||
|
||||
@@ -23,8 +23,8 @@ void RegisterTime(FEX::HLE::SyscallHandler* Handler);
|
||||
void RegisterNotImplemented(FEX::HLE::SyscallHandler* Handler);
|
||||
void RegisterPassthrough(FEX::HLE::SyscallHandler* Handler);
|
||||
|
||||
x64SyscallHandler::x64SyscallHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation)
|
||||
: SyscallHandler {ctx, _SignalDelegation} {
|
||||
x64SyscallHandler::x64SyscallHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation, FEX::HLE::ThunkHandler* ThunkHandler)
|
||||
: SyscallHandler {ctx, _SignalDelegation, ThunkHandler} {
|
||||
OSABI = FEXCore::HLE::SyscallOSABI::OS_LINUX64;
|
||||
|
||||
RegisterSyscallHandlers();
|
||||
@@ -80,7 +80,8 @@ void x64SyscallHandler::RegisterSyscallHandlers() {
|
||||
#endif
|
||||
}
|
||||
|
||||
fextl::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation) {
|
||||
return fextl::make_unique<x64SyscallHandler>(ctx, _SignalDelegation);
|
||||
fextl::unique_ptr<FEX::HLE::SyscallHandler>
|
||||
CreateHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation, FEX::HLE::ThunkHandler* ThunkHandler) {
|
||||
return fextl::make_unique<x64SyscallHandler>(ctx, _SignalDelegation, ThunkHandler);
|
||||
}
|
||||
} // namespace FEX::HLE::x64
|
||||
@@ -23,6 +23,7 @@ $end_info$
|
||||
namespace FEX::HLE {
|
||||
class SignalDelegator;
|
||||
class SyscallHandler;
|
||||
class ThunkHandler;
|
||||
} // namespace FEX::HLE
|
||||
|
||||
namespace FEXCore::Core {
|
||||
@@ -32,7 +33,7 @@ struct InternalThreadState;
|
||||
namespace FEX::HLE::x64 {
|
||||
class x64SyscallHandler final : public FEX::HLE::SyscallHandler {
|
||||
public:
|
||||
x64SyscallHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation);
|
||||
x64SyscallHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation, FEX::HLE::ThunkHandler* ThunkHandler);
|
||||
|
||||
void* GuestMmap(FEXCore::Core::InternalThreadState* Thread, void* addr, size_t length, int prot, int flags, int fd, off_t offset) override;
|
||||
int GuestMunmap(FEXCore::Core::InternalThreadState* Thread, void* addr, uint64_t length) override;
|
||||
@@ -60,7 +61,8 @@ private:
|
||||
void RegisterSyscallHandlers();
|
||||
};
|
||||
|
||||
fextl::unique_ptr<FEX::HLE::SyscallHandler> CreateHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation);
|
||||
fextl::unique_ptr<FEX::HLE::SyscallHandler>
|
||||
CreateHandler(FEXCore::Context::Context* ctx, FEX::HLE::SignalDelegator* _SignalDelegation, FEX::HLE::ThunkHandler* ThunkHandler);
|
||||
|
||||
//////
|
||||
// REGISTER_SYSCALL_IMPL implementation
|
||||
|
||||
+209
-249
@@ -6,29 +6,26 @@ tags: glue|thunks
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include "Interface/IR/IR.h"
|
||||
#include "Interface/IR/IREmitter.h"
|
||||
#include "Thunks.h"
|
||||
#include "LinuxSyscalls/Syscalls.h"
|
||||
#include "LinuxSyscalls/ThreadManager.h"
|
||||
|
||||
#include <FEXCore/Config/Config.h>
|
||||
#include <FEXCore/Core/CoreState.h>
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
#include <FEXCore/Core/Thunks.h>
|
||||
#include <FEXCore/Debug/InternalThreadState.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <FEXCore/Utils/CompilerDefs.h>
|
||||
#include <FEXCore/fextl/set.h>
|
||||
#include <FEXCore/fextl/string.h>
|
||||
#include <FEXCore/fextl/unordered_map.h>
|
||||
#include "Thunks.h"
|
||||
|
||||
#include <cstdint>
|
||||
#ifndef _WIN32
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include <Interface/Context/Context.h>
|
||||
#include "FEXCore/Core/X86Enums.h"
|
||||
#include <malloc.h>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <shared_mutex>
|
||||
#include <stdint.h>
|
||||
#include <utility>
|
||||
@@ -43,7 +40,6 @@ FEX_DEFAULT_VISIBILITY JEMALLOC_NOTHROW extern int glibc_je_is_known_allocation(
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
static __attribute__((aligned(16), naked, section("HostToGuestTrampolineTemplate"))) void HostToGuestTrampolineTemplate() {
|
||||
#if defined(_M_X86_64)
|
||||
asm("lea 0f(%rip), %r11 \n"
|
||||
@@ -71,21 +67,10 @@ static __attribute__((aligned(16), naked, section("HostToGuestTrampolineTemplate
|
||||
|
||||
extern char __start_HostToGuestTrampolineTemplate[];
|
||||
extern char __stop_HostToGuestTrampolineTemplate[];
|
||||
#endif
|
||||
|
||||
namespace FEXCore {
|
||||
#ifndef _WIN32
|
||||
struct LoadlibArgs {
|
||||
const char* Name;
|
||||
};
|
||||
namespace FEX::HLE {
|
||||
|
||||
static thread_local FEXCore::Core::InternalThreadState* Thread = nullptr;
|
||||
|
||||
|
||||
struct ExportEntry {
|
||||
uint8_t* sha256;
|
||||
ThunkedFunction* Fn;
|
||||
};
|
||||
static thread_local FEX::HLE::ThreadStateObject* ThreadObject {};
|
||||
|
||||
struct TrampolineInstanceInfo {
|
||||
void* HostPacker;
|
||||
@@ -119,41 +104,17 @@ struct GuestcallInfoHash {
|
||||
}
|
||||
};
|
||||
|
||||
// Bits in a SHA256 sum are already randomly distributed, so truncation yields a suitable hash function
|
||||
struct TruncatingSHA256Hash {
|
||||
size_t operator()(const FEXCore::IR::SHA256Sum& SHA256Sum) const noexcept {
|
||||
return (const size_t&)SHA256Sum;
|
||||
}
|
||||
};
|
||||
namespace ThunkFunctions {
|
||||
void LoadLib(void* ArgsV);
|
||||
void IsLibLoaded(void* ArgsRV);
|
||||
void IsHostHeapAllocation(void* ArgsRV);
|
||||
void LinkAddressToGuestFunction(void* argsv);
|
||||
void AllocateHostTrampolineForGuestFunction(void* ArgsRV);
|
||||
} // namespace ThunkFunctions
|
||||
|
||||
HostToGuestTrampolinePtr* MakeHostTrampolineForGuestFunction(void* HostPacker, uintptr_t GuestTarget, uintptr_t GuestUnpacker);
|
||||
|
||||
struct ThunkHandler_impl final : public ThunkHandler {
|
||||
struct ThunkHandler_impl final : public FEX::HLE::ThunkHandler {
|
||||
std::shared_mutex ThunksMutex;
|
||||
|
||||
fextl::unordered_map<IR::SHA256Sum, ThunkedFunction*, TruncatingSHA256Hash> Thunks = {
|
||||
{// sha256(fex:loadlib)
|
||||
{0x27, 0x7e, 0xb7, 0x69, 0x5b, 0xe9, 0xab, 0x12, 0x6e, 0xf7, 0x85, 0x9d, 0x4b, 0xc9, 0xa2, 0x44,
|
||||
0x46, 0xcf, 0xbd, 0xb5, 0x87, 0x43, 0xef, 0x28, 0xa2, 0x65, 0xba, 0xfc, 0x89, 0x0f, 0x77, 0x80},
|
||||
&LoadLib},
|
||||
{// sha256(fex:is_lib_loaded)
|
||||
{0xee, 0x57, 0xba, 0x0c, 0x5f, 0x6e, 0xef, 0x2a, 0x8c, 0xb5, 0x19, 0x81, 0xc9, 0x23, 0xe6, 0x51,
|
||||
0xae, 0x65, 0x02, 0x8f, 0x2b, 0x5d, 0x59, 0x90, 0x6a, 0x7e, 0xe2, 0xe7, 0x1c, 0x33, 0x8a, 0xff},
|
||||
&IsLibLoaded},
|
||||
{// sha256(fex:is_host_heap_allocation)
|
||||
{0xf5, 0x77, 0x68, 0x43, 0xbb, 0x6b, 0x28, 0x18, 0x40, 0xb0, 0xdb, 0x8a, 0x66, 0xfb, 0x0e, 0x2d,
|
||||
0x98, 0xc2, 0xad, 0xe2, 0x5a, 0x18, 0x5a, 0x37, 0x2e, 0x13, 0xc9, 0xe7, 0xb9, 0x8c, 0xa9, 0x3e},
|
||||
&IsHostHeapAllocation},
|
||||
{// sha256(fex:link_address_to_function)
|
||||
{0xe6, 0xa8, 0xec, 0x1c, 0x7b, 0x74, 0x35, 0x27, 0xe9, 0x4f, 0x5b, 0x6e, 0x2d, 0xc9, 0xa0, 0x27,
|
||||
0xd6, 0x1f, 0x2b, 0x87, 0x8f, 0x2d, 0x35, 0x50, 0xea, 0x16, 0xb8, 0xc4, 0x5e, 0x42, 0xfd, 0x77},
|
||||
&LinkAddressToGuestFunction},
|
||||
{// sha256(fex:allocate_host_trampoline_for_guest_function)
|
||||
{0x9b, 0xb2, 0xf4, 0xb4, 0x83, 0x7d, 0x28, 0x93, 0x40, 0xcb, 0xf4, 0x7a, 0x0b, 0x47, 0x85, 0x87,
|
||||
0xf9, 0xbc, 0xb5, 0x27, 0xca, 0xa6, 0x93, 0xa5, 0xc0, 0x73, 0x27, 0x24, 0xae, 0xc8, 0xb8, 0x5a},
|
||||
&AllocateHostTrampolineForGuestFunction},
|
||||
};
|
||||
|
||||
// Can't be a string_view. We need to keep a copy of the library name in-case string_view pointer goes away.
|
||||
// Ideally we track when a library has been unloaded and remove it from this set before the memory backing goes away.
|
||||
fextl::set<fextl::string> Libs;
|
||||
@@ -163,199 +124,32 @@ struct ThunkHandler_impl final : public ThunkHandler {
|
||||
uint8_t* HostTrampolineInstanceDataPtr;
|
||||
size_t HostTrampolineInstanceDataAvailable = 0;
|
||||
|
||||
|
||||
/*
|
||||
Set arg0/1 to arg regs, use CTX::HandleCallback to handle the callback
|
||||
*/
|
||||
static void CallCallback(void* callback, void* arg0, void* arg1) {
|
||||
if (!Thread) {
|
||||
if (!ThreadObject) {
|
||||
ERROR_AND_DIE_FMT("Thunked library attempted to invoke guest callback asynchronously");
|
||||
}
|
||||
|
||||
auto CTX = static_cast<Context::ContextImpl*>(Thread->CTX);
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RDI] = (uintptr_t)arg0;
|
||||
Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSI] = (uintptr_t)arg1;
|
||||
auto CTX = static_cast<FEXCore::Context::Context*>(ThreadObject->Thread->CTX);
|
||||
auto ThunkHandler = reinterpret_cast<ThunkHandler_impl*>(FEX::HLE::_SyscallHandler->GetThunkHandler());
|
||||
|
||||
if (ThunkHandler->Is64BitMode()) {
|
||||
ThreadObject->Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RDI] = (uintptr_t)arg0;
|
||||
ThreadObject->Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSI] = (uintptr_t)arg1;
|
||||
} else {
|
||||
if ((reinterpret_cast<uintptr_t>(arg1) >> 32) != 0) {
|
||||
ERROR_AND_DIE_FMT("Tried to call guest function with arguments packed to a 64-bit address");
|
||||
}
|
||||
Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RCX] = (uintptr_t)arg0;
|
||||
Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RDX] = (uintptr_t)arg1;
|
||||
ThreadObject->Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RCX] = (uintptr_t)arg0;
|
||||
ThreadObject->Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RDX] = (uintptr_t)arg1;
|
||||
}
|
||||
|
||||
Thread->CTX->HandleCallback(Thread, (uintptr_t)callback);
|
||||
CTX->HandleCallback(ThreadObject->Thread, (uintptr_t)callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the Core to redirect calls to functions at the given
|
||||
* address to another function. The original callee address is passed
|
||||
* to the target function through an implicit argument stored in r11.
|
||||
*
|
||||
* For 32-bit the implicit argument is stored in the lower 32-bits of mm0.
|
||||
*
|
||||
* The primary use case of this is ensuring that host function pointers
|
||||
* returned from thunked APIs can safely be called by the guest.
|
||||
*/
|
||||
static void LinkAddressToGuestFunction(void* argsv) {
|
||||
struct args_t {
|
||||
uintptr_t original_callee;
|
||||
uintptr_t target_addr; // Guest function to call when branching to original_callee
|
||||
};
|
||||
|
||||
auto args = reinterpret_cast<args_t*>(argsv);
|
||||
auto CTX = static_cast<Context::ContextImpl*>(Thread->CTX);
|
||||
|
||||
LOGMAN_THROW_AA_FMT(args->original_callee, "Tried to link null pointer address to guest function");
|
||||
LOGMAN_THROW_AA_FMT(args->target_addr, "Tried to link address to null pointer guest function");
|
||||
if (!CTX->Config.Is64BitMode) {
|
||||
LOGMAN_THROW_AA_FMT((args->original_callee >> 32) == 0, "Tried to link 64-bit address in 32-bit mode");
|
||||
LOGMAN_THROW_AA_FMT((args->target_addr >> 32) == 0, "Tried to link 64-bit address in 32-bit mode");
|
||||
}
|
||||
|
||||
LogMan::Msg::DFmt("Thunks: Adding guest trampoline from address {:#x} to guest function {:#x}", args->original_callee, args->target_addr);
|
||||
|
||||
auto Result = CTX->AddCustomIREntrypoint(
|
||||
args->original_callee,
|
||||
[CTX, GuestThunkEntrypoint = args->target_addr](uintptr_t Entrypoint, FEXCore::IR::IREmitter* emit) {
|
||||
auto IRHeader = emit->_IRHeader(emit->Invalid(), Entrypoint, 0, 0);
|
||||
auto Block = emit->CreateCodeNode();
|
||||
IRHeader.first->Blocks = emit->WrapNode(Block);
|
||||
emit->SetCurrentCodeBlock(Block);
|
||||
|
||||
const uint8_t GPRSize = CTX->GetGPRSize();
|
||||
|
||||
if (GPRSize == 8) {
|
||||
emit->_StoreRegister(emit->_Constant(Entrypoint), X86State::REG_R11, IR::GPRClass, GPRSize);
|
||||
} else {
|
||||
emit->_StoreContext(GPRSize, IR::FPRClass, emit->_VCastFromGPR(8, 8, emit->_Constant(Entrypoint)), offsetof(Core::CPUState, mm[0][0]));
|
||||
}
|
||||
emit->_ExitFunction(emit->_Constant(GuestThunkEntrypoint));
|
||||
},
|
||||
CTX->ThunkHandler.get(), (void*)args->target_addr);
|
||||
|
||||
if (!Result) {
|
||||
if (Result.Creator != CTX->ThunkHandler.get()) {
|
||||
ERROR_AND_DIE_FMT("Input address for LinkAddressToGuestFunction is already linked by another module");
|
||||
}
|
||||
if (Result.Data != (void*)args->target_addr) {
|
||||
// NOTE: This may happen in Vulkan thunks if the Vulkan driver resolves two different symbols
|
||||
// to the same function (e.g. vkGetPhysicalDeviceFeatures2/vkGetPhysicalDeviceFeatures2KHR)
|
||||
LogMan::Msg::EFmt("Input address for LinkAddressToGuestFunction is already linked elsewhere");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Guest-side helper to initiate creation of a host trampoline for
|
||||
* calling guest functions. This must be followed by a host-side call
|
||||
* to FinalizeHostTrampolineForGuestFunction to make the trampoline
|
||||
* usable.
|
||||
*
|
||||
* This two-step initialization is equivalent to a host-side call to
|
||||
* MakeHostTrampolineForGuestFunction. The split is needed if the
|
||||
* host doesn't have all information needed to create the trampoline
|
||||
* on its own.
|
||||
*/
|
||||
static void AllocateHostTrampolineForGuestFunction(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
uintptr_t GuestUnpacker;
|
||||
uintptr_t GuestTarget;
|
||||
uintptr_t rv; // Pointer to host trampoline + TrampolineInstanceInfo
|
||||
}* args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = (uintptr_t)MakeHostTrampolineForGuestFunction(nullptr, args->GuestTarget, args->GuestUnpacker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given pointer is allocated on the host heap.
|
||||
*
|
||||
* This is useful for thunking APIs that need to work with both guest
|
||||
* and host heap pointers.
|
||||
*/
|
||||
static void IsHostHeapAllocation(void* ArgsRV) {
|
||||
#ifdef ENABLE_JEMALLOC_GLIBC
|
||||
struct ArgsRV_t {
|
||||
void* ptr;
|
||||
bool rv;
|
||||
}* args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = glibc_je_is_known_allocation(args->ptr);
|
||||
#else
|
||||
// Thunks usage without jemalloc isn't supported
|
||||
ERROR_AND_DIE_FMT("Unsupported: Thunks querying for host heap allocation information");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void LoadLib(void* ArgsV) {
|
||||
auto CTX = static_cast<Context::ContextImpl*>(Thread->CTX);
|
||||
|
||||
auto Args = reinterpret_cast<LoadlibArgs*>(ArgsV);
|
||||
|
||||
std::string_view Name = Args->Name;
|
||||
|
||||
auto SOName = (CTX->Config.Is64BitMode() ? CTX->Config.ThunkHostLibsPath() : CTX->Config.ThunkHostLibsPath32()) + "/" + Name.data() + "-host.so";
|
||||
|
||||
LogMan::Msg::DFmt("LoadLib: {} -> {}", Name, SOName);
|
||||
|
||||
auto Handle = dlopen(SOName.c_str(), RTLD_LOCAL | RTLD_NOW);
|
||||
if (!Handle) {
|
||||
ERROR_AND_DIE_FMT("LoadLib: Failed to dlopen thunk library {}: {}", SOName, dlerror());
|
||||
}
|
||||
|
||||
// Library names often include dashes, which may not be used in C++ identifiers.
|
||||
// They are replaced with underscores hence.
|
||||
auto InitSym = "fexthunks_exports_" + fextl::string {Name};
|
||||
std::replace(InitSym.begin(), InitSym.end(), '-', '_');
|
||||
|
||||
ExportEntry* (*InitFN)();
|
||||
(void*&)InitFN = dlsym(Handle, InitSym.c_str());
|
||||
if (!InitFN) {
|
||||
ERROR_AND_DIE_FMT("LoadLib: Failed to find export {}", InitSym);
|
||||
}
|
||||
|
||||
auto Exports = InitFN();
|
||||
if (!Exports) {
|
||||
ERROR_AND_DIE_FMT("LoadLib: Failed to initialize thunk library {}. "
|
||||
"Check if the corresponding host library is installed "
|
||||
"or disable thunking of this library.",
|
||||
Name);
|
||||
}
|
||||
|
||||
auto That = reinterpret_cast<ThunkHandler_impl*>(CTX->ThunkHandler.get());
|
||||
|
||||
{
|
||||
std::lock_guard lk(That->ThunksMutex);
|
||||
|
||||
That->Libs.insert(fextl::string {Name});
|
||||
|
||||
int i;
|
||||
for (i = 0; Exports[i].sha256; i++) {
|
||||
That->Thunks[*reinterpret_cast<IR::SHA256Sum*>(Exports[i].sha256)] = Exports[i].Fn;
|
||||
}
|
||||
|
||||
LogMan::Msg::DFmt("Loaded {} syms", i);
|
||||
}
|
||||
}
|
||||
|
||||
static void IsLibLoaded(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
const char* Name;
|
||||
bool rv;
|
||||
};
|
||||
|
||||
auto& [Name, rv] = *reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
auto CTX = static_cast<Context::ContextImpl*>(Thread->CTX);
|
||||
auto That = reinterpret_cast<ThunkHandler_impl*>(CTX->ThunkHandler.get());
|
||||
|
||||
{
|
||||
std::shared_lock lk(That->ThunksMutex);
|
||||
rv = That->Libs.contains(Name);
|
||||
}
|
||||
}
|
||||
|
||||
ThunkedFunction* LookupThunk(const IR::SHA256Sum& sha256) override {
|
||||
FEXCore::ThunkedFunction* LookupThunk(const FEXCore::IR::SHA256Sum& sha256) override {
|
||||
|
||||
std::shared_lock lk(ThunksMutex);
|
||||
|
||||
@@ -368,8 +162,8 @@ struct ThunkHandler_impl final : public ThunkHandler {
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterTLSState(FEXCore::Core::InternalThreadState* _Thread) override {
|
||||
Thread = _Thread;
|
||||
void RegisterTLSState(FEX::HLE::ThreadStateObject* _ThreadObject) override {
|
||||
ThreadObject = _ThreadObject;
|
||||
}
|
||||
|
||||
void AppendThunkDefinitions(std::span<const FEXCore::IR::ThunkDefinition> Definitions) override {
|
||||
@@ -377,10 +171,91 @@ struct ThunkHandler_impl final : public ThunkHandler {
|
||||
Thunks.emplace(Definition.Sum, Definition.ThunkFunction);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadLib(std::string_view Name);
|
||||
|
||||
private:
|
||||
// Bits in a SHA256 sum are already randomly distributed, so truncation yields a suitable hash function
|
||||
struct TruncatingSHA256Hash {
|
||||
size_t operator()(const FEXCore::IR::SHA256Sum& SHA256Sum) const noexcept {
|
||||
return (const size_t&)SHA256Sum;
|
||||
}
|
||||
};
|
||||
|
||||
fextl::unordered_map<FEXCore::IR::SHA256Sum, FEXCore::ThunkedFunction*, TruncatingSHA256Hash> Thunks = {
|
||||
{// sha256(fex:loadlib)
|
||||
{0x27, 0x7e, 0xb7, 0x69, 0x5b, 0xe9, 0xab, 0x12, 0x6e, 0xf7, 0x85, 0x9d, 0x4b, 0xc9, 0xa2, 0x44,
|
||||
0x46, 0xcf, 0xbd, 0xb5, 0x87, 0x43, 0xef, 0x28, 0xa2, 0x65, 0xba, 0xfc, 0x89, 0x0f, 0x77, 0x80},
|
||||
&ThunkFunctions::LoadLib},
|
||||
{// sha256(fex:is_lib_loaded)
|
||||
{0xee, 0x57, 0xba, 0x0c, 0x5f, 0x6e, 0xef, 0x2a, 0x8c, 0xb5, 0x19, 0x81, 0xc9, 0x23, 0xe6, 0x51,
|
||||
0xae, 0x65, 0x02, 0x8f, 0x2b, 0x5d, 0x59, 0x90, 0x6a, 0x7e, 0xe2, 0xe7, 0x1c, 0x33, 0x8a, 0xff},
|
||||
&ThunkFunctions::IsLibLoaded},
|
||||
{// sha256(fex:is_host_heap_allocation)
|
||||
{0xf5, 0x77, 0x68, 0x43, 0xbb, 0x6b, 0x28, 0x18, 0x40, 0xb0, 0xdb, 0x8a, 0x66, 0xfb, 0x0e, 0x2d,
|
||||
0x98, 0xc2, 0xad, 0xe2, 0x5a, 0x18, 0x5a, 0x37, 0x2e, 0x13, 0xc9, 0xe7, 0xb9, 0x8c, 0xa9, 0x3e},
|
||||
&ThunkFunctions::IsHostHeapAllocation},
|
||||
{// sha256(fex:link_address_to_function)
|
||||
{0xe6, 0xa8, 0xec, 0x1c, 0x7b, 0x74, 0x35, 0x27, 0xe9, 0x4f, 0x5b, 0x6e, 0x2d, 0xc9, 0xa0, 0x27,
|
||||
0xd6, 0x1f, 0x2b, 0x87, 0x8f, 0x2d, 0x35, 0x50, 0xea, 0x16, 0xb8, 0xc4, 0x5e, 0x42, 0xfd, 0x77},
|
||||
&ThunkFunctions::LinkAddressToGuestFunction},
|
||||
{// sha256(fex:allocate_host_trampoline_for_guest_function)
|
||||
{0x9b, 0xb2, 0xf4, 0xb4, 0x83, 0x7d, 0x28, 0x93, 0x40, 0xcb, 0xf4, 0x7a, 0x0b, 0x47, 0x85, 0x87,
|
||||
0xf9, 0xbc, 0xb5, 0x27, 0xca, 0xa6, 0x93, 0xa5, 0xc0, 0x73, 0x27, 0x24, 0xae, 0xc8, 0xb8, 0x5a},
|
||||
&ThunkFunctions::AllocateHostTrampolineForGuestFunction},
|
||||
};
|
||||
|
||||
FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE);
|
||||
FEX_CONFIG_OPT(ThunkHostLibsPath, THUNKHOSTLIBS);
|
||||
FEX_CONFIG_OPT(ThunkHostLibsPath32, THUNKHOSTLIBS32);
|
||||
};
|
||||
|
||||
fextl::unique_ptr<ThunkHandler> ThunkHandler::Create() {
|
||||
return fextl::make_unique<ThunkHandler_impl>();
|
||||
void ThunkHandler_impl::LoadLib(std::string_view Name) {
|
||||
auto SOName = (Is64BitMode() ? ThunkHostLibsPath() : ThunkHostLibsPath32()) + "/" + Name.data() + "-host.so";
|
||||
|
||||
LogMan::Msg::DFmt("LoadLib: {} -> {}", Name, SOName);
|
||||
|
||||
auto Handle = dlopen(SOName.c_str(), RTLD_LOCAL | RTLD_NOW);
|
||||
if (!Handle) {
|
||||
ERROR_AND_DIE_FMT("LoadLib: Failed to dlopen thunk library {}: {}", SOName, dlerror());
|
||||
}
|
||||
|
||||
// Library names often include dashes, which may not be used in C++ identifiers.
|
||||
// They are replaced with underscores hence.
|
||||
auto InitSym = "fexthunks_exports_" + fextl::string {Name};
|
||||
std::replace(InitSym.begin(), InitSym.end(), '-', '_');
|
||||
|
||||
struct ExportEntry {
|
||||
uint8_t* sha256;
|
||||
FEXCore::ThunkedFunction* Fn;
|
||||
};
|
||||
|
||||
ExportEntry* (*InitFN)();
|
||||
(void*&)InitFN = dlsym(Handle, InitSym.c_str());
|
||||
if (!InitFN) {
|
||||
ERROR_AND_DIE_FMT("LoadLib: Failed to find export {}", InitSym);
|
||||
}
|
||||
|
||||
auto Exports = InitFN();
|
||||
if (!Exports) {
|
||||
ERROR_AND_DIE_FMT("LoadLib: Failed to initialize thunk library {}. "
|
||||
"Check if the corresponding host library is installed "
|
||||
"or disable thunking of this library.",
|
||||
Name);
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard lk(ThunksMutex);
|
||||
|
||||
Libs.insert(fextl::string {Name});
|
||||
|
||||
int i;
|
||||
for (i = 0; Exports[i].sha256; i++) {
|
||||
Thunks[*reinterpret_cast<FEXCore::IR::SHA256Sum*>(Exports[i].sha256)] = Exports[i].Fn;
|
||||
}
|
||||
|
||||
LogMan::Msg::DFmt("Loaded {} syms", i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -410,8 +285,7 @@ FEX_DEFAULT_VISIBILITY HostToGuestTrampolinePtr*
|
||||
MakeHostTrampolineForGuestFunction(void* HostPacker, uintptr_t GuestTarget, uintptr_t GuestUnpacker) {
|
||||
LOGMAN_THROW_AA_FMT(GuestTarget, "Tried to create host-trampoline to null pointer guest function");
|
||||
|
||||
const auto CTX = static_cast<Context::ContextImpl*>(Thread->CTX);
|
||||
const auto ThunkHandler = reinterpret_cast<ThunkHandler_impl*>(CTX->ThunkHandler.get());
|
||||
const auto ThunkHandler = reinterpret_cast<ThunkHandler_impl*>(FEX::HLE::_SyscallHandler->GetThunkHandler());
|
||||
|
||||
const GuestcallInfo gci = {GuestUnpacker, GuestTarget};
|
||||
|
||||
@@ -460,7 +334,6 @@ MakeHostTrampolineForGuestFunction(void* HostPacker, uintptr_t GuestTarget, uint
|
||||
}
|
||||
|
||||
FEX_DEFAULT_VISIBILITY void FinalizeHostTrampolineForGuestFunction(HostToGuestTrampolinePtr* TrampolineAddress, void* HostPacker) {
|
||||
|
||||
if (TrampolineAddress == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -476,16 +349,106 @@ FEX_DEFAULT_VISIBILITY void FinalizeHostTrampolineForGuestFunction(HostToGuestTr
|
||||
}
|
||||
}
|
||||
|
||||
namespace ThunkFunctions {
|
||||
void LoadLib(void* ArgsV) {
|
||||
struct LoadlibArgs {
|
||||
const char* Name;
|
||||
};
|
||||
|
||||
auto Args = reinterpret_cast<LoadlibArgs*>(ArgsV);
|
||||
auto ThunkHandler = reinterpret_cast<ThunkHandler_impl*>(FEX::HLE::_SyscallHandler->GetThunkHandler());
|
||||
|
||||
ThunkHandler->LoadLib(Args->Name);
|
||||
}
|
||||
|
||||
void IsLibLoaded(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
const char* Name;
|
||||
bool rv;
|
||||
};
|
||||
|
||||
auto& [Name, rv] = *reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
auto ThunkHandler = reinterpret_cast<ThunkHandler_impl*>(FEX::HLE::_SyscallHandler->GetThunkHandler());
|
||||
|
||||
{
|
||||
std::shared_lock lk(ThunkHandler->ThunksMutex);
|
||||
rv = ThunkHandler->Libs.contains(Name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given pointer is allocated on the host heap.
|
||||
*
|
||||
* This is useful for thunking APIs that need to work with both guest
|
||||
* and host heap pointers.
|
||||
*/
|
||||
void IsHostHeapAllocation(void* ArgsRV) {
|
||||
#ifdef ENABLE_JEMALLOC_GLIBC
|
||||
struct ArgsRV_t {
|
||||
void* ptr;
|
||||
bool rv;
|
||||
}* args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = glibc_je_is_known_allocation(args->ptr);
|
||||
#else
|
||||
// Thunks usage without jemalloc isn't supported
|
||||
ERROR_AND_DIE_FMT("Unsupported: Thunks querying for host heap allocation information");
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the Core to redirect calls to functions at the given
|
||||
* address to another function. The original callee address is passed
|
||||
* to the target function through an implicit argument stored in r11.
|
||||
*
|
||||
* For 32-bit the implicit argument is stored in the lower 32-bits of mm0.
|
||||
*
|
||||
* The primary use case of this is ensuring that host function pointers
|
||||
* returned from thunked APIs can safely be called by the guest.
|
||||
*/
|
||||
void LinkAddressToGuestFunction(void* argsv) {
|
||||
struct args_t {
|
||||
uintptr_t original_callee;
|
||||
uintptr_t target_addr; // Guest function to call when branching to original_callee
|
||||
};
|
||||
|
||||
auto args = reinterpret_cast<args_t*>(argsv);
|
||||
auto CTX = static_cast<FEXCore::Context::Context*>(ThreadObject->Thread->CTX);
|
||||
CTX->AddThunkTrampolineIRHandler(args->original_callee, args->target_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Guest-side helper to initiate creation of a host trampoline for
|
||||
* calling guest functions. This must be followed by a host-side call
|
||||
* to FinalizeHostTrampolineForGuestFunction to make the trampoline
|
||||
* usable.
|
||||
*
|
||||
* This two-step initialization is equivalent to a host-side call to
|
||||
* MakeHostTrampolineForGuestFunction. The split is needed if the
|
||||
* host doesn't have all information needed to create the trampoline
|
||||
* on its own.
|
||||
*/
|
||||
void AllocateHostTrampolineForGuestFunction(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
uintptr_t GuestUnpacker;
|
||||
uintptr_t GuestTarget;
|
||||
uintptr_t rv; // Pointer to host trampoline + TrampolineInstanceInfo
|
||||
}* args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = (uintptr_t)MakeHostTrampolineForGuestFunction(nullptr, args->GuestTarget, args->GuestUnpacker);
|
||||
}
|
||||
} // namespace ThunkFunctions
|
||||
|
||||
FEX_DEFAULT_VISIBILITY void* GetGuestStack() {
|
||||
if (!Thread) {
|
||||
if (!ThreadObject) {
|
||||
ERROR_AND_DIE_FMT("Thunked library attempted to query guest stack pointer asynchronously");
|
||||
}
|
||||
|
||||
return (void*)(uintptr_t)((Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP]));
|
||||
return (void*)(uintptr_t)((ThreadObject->Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP]));
|
||||
}
|
||||
|
||||
FEX_DEFAULT_VISIBILITY void MoveGuestStack(uintptr_t NewAddress) {
|
||||
if (!Thread) {
|
||||
if (!ThreadObject) {
|
||||
ERROR_AND_DIE_FMT("Thunked library attempted to query guest stack pointer asynchronously");
|
||||
}
|
||||
|
||||
@@ -493,13 +456,10 @@ FEX_DEFAULT_VISIBILITY void MoveGuestStack(uintptr_t NewAddress) {
|
||||
ERROR_AND_DIE_FMT("Tried to set stack pointer for 32-bit guest to a 64-bit address");
|
||||
}
|
||||
|
||||
Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP] = NewAddress;
|
||||
ThreadObject->Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP] = NewAddress;
|
||||
}
|
||||
|
||||
#else
|
||||
fextl::unique_ptr<ThunkHandler> ThunkHandler::Create() {
|
||||
ERROR_AND_DIE_FMT("Unsupported");
|
||||
fextl::unique_ptr<ThunkHandler> CreateThunkHandler() {
|
||||
return fextl::make_unique<ThunkHandler_impl>();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace FEXCore
|
||||
} // namespace FEX::HLE
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <FEXCore/Core/Thunks.h>
|
||||
#include <FEXCore/fextl/memory.h>
|
||||
|
||||
#include <span>
|
||||
|
||||
namespace FEX::HLE {
|
||||
struct ThreadStateObject;
|
||||
|
||||
class ThunkHandler : public FEXCore::ThunkHandler {
|
||||
public:
|
||||
virtual void RegisterTLSState(FEX::HLE::ThreadStateObject* ThreadObject) = 0;
|
||||
/**
|
||||
* @brief Allows the frontend to register its own thunk handlers independent of what is controlled in the backend.
|
||||
*
|
||||
* @param CTX A valid non-null context instance.
|
||||
* @param Definitions A vector of thunk definitions that the frontend controls
|
||||
*/
|
||||
virtual void AppendThunkDefinitions(std::span<const FEXCore::IR::ThunkDefinition> Definitions) = 0;
|
||||
};
|
||||
fextl::unique_ptr<ThunkHandler> CreateThunkHandler();
|
||||
} // namespace FEX::HLE
|
||||
@@ -300,8 +300,8 @@ int main(int argc, char** argv, char** const envp) {
|
||||
|
||||
if (!IsHostRunner) {
|
||||
#ifndef _WIN32
|
||||
auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX.get(), SignalDelegation.get()) :
|
||||
FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), std::move(Allocator));
|
||||
auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX.get(), SignalDelegation.get(), nullptr) :
|
||||
FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), nullptr, std::move(Allocator));
|
||||
|
||||
#else
|
||||
auto SyscallHandler = FEX::WindowsHandlers::CreateSyscallHandler();
|
||||
|
||||
@@ -15,12 +15,12 @@ $end_info$
|
||||
|
||||
#include "PackedArguments.h"
|
||||
|
||||
// Import FEXCore functions for use in host thunk libraries.
|
||||
// Import FEX::HLE functions for use in host thunk libraries.
|
||||
//
|
||||
// Note these are statically linked into the FEX executable. The linker hence
|
||||
// doesn't know about them when linking thunk libraries. This issue is avoided
|
||||
// by declaring the functions as weak symbols.
|
||||
namespace FEXCore {
|
||||
namespace FEX::HLE {
|
||||
struct HostToGuestTrampolinePtr;
|
||||
|
||||
__attribute__((weak)) HostToGuestTrampolinePtr* MakeHostTrampolineForGuestFunction(void* HostPacker, uintptr_t GuestTarget, uintptr_t GuestUnpacker);
|
||||
@@ -30,7 +30,7 @@ __attribute__((weak)) HostToGuestTrampolinePtr* FinalizeHostTrampolineForGuestFu
|
||||
__attribute__((weak)) void* GetGuestStack();
|
||||
|
||||
__attribute__((weak)) void MoveGuestStack(uintptr_t NewAddress);
|
||||
} // namespace FEXCore
|
||||
} // namespace FEX::HLE
|
||||
|
||||
template<typename Fn>
|
||||
struct function_traits;
|
||||
@@ -504,19 +504,19 @@ auto Projection(guest_layout<T>& data) {
|
||||
* restored.
|
||||
*/
|
||||
class GuestStackBumpAllocator final {
|
||||
uintptr_t Top = reinterpret_cast<uintptr_t>(FEXCore::GetGuestStack());
|
||||
uintptr_t Top = reinterpret_cast<uintptr_t>(FEX::HLE::GetGuestStack());
|
||||
uintptr_t Next = Top;
|
||||
|
||||
public:
|
||||
~GuestStackBumpAllocator() {
|
||||
FEXCore::MoveGuestStack(Top);
|
||||
FEX::HLE::MoveGuestStack(Top);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
T* New(Args&&... args) {
|
||||
Next -= sizeof(T);
|
||||
Next &= ~uintptr_t {alignof(T) - 1};
|
||||
FEXCore::MoveGuestStack(Next);
|
||||
FEX::HLE::MoveGuestStack(Next);
|
||||
return new (reinterpret_cast<void*>(Next)) T {std::forward<Args>(args)...};
|
||||
}
|
||||
};
|
||||
@@ -625,19 +625,19 @@ struct GuestWrapperForHostFunction<Result(Args...), GuestArgs...> {
|
||||
|
||||
template<typename FuncType>
|
||||
void MakeHostTrampolineForGuestFunctionAt(uintptr_t GuestTarget, uintptr_t GuestUnpacker, FuncType** Func) {
|
||||
*Func = (FuncType*)FEXCore::MakeHostTrampolineForGuestFunction((void*)&CallbackUnpack<FuncType>::CallGuestPtr, GuestTarget, GuestUnpacker);
|
||||
*Func = (FuncType*)FEX::HLE::MakeHostTrampolineForGuestFunction((void*)&CallbackUnpack<FuncType>::CallGuestPtr, GuestTarget, GuestUnpacker);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void FinalizeHostTrampolineForGuestFunction(F* PreallocatedTrampolineForGuestFunction) {
|
||||
FEXCore::FinalizeHostTrampolineForGuestFunction((FEXCore::HostToGuestTrampolinePtr*)PreallocatedTrampolineForGuestFunction,
|
||||
(void*)&CallbackUnpack<F>::CallGuestPtr);
|
||||
FEX::HLE::FinalizeHostTrampolineForGuestFunction((FEX::HLE::HostToGuestTrampolinePtr*)PreallocatedTrampolineForGuestFunction,
|
||||
(void*)&CallbackUnpack<F>::CallGuestPtr);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void FinalizeHostTrampolineForGuestFunction(guest_layout<F*> PreallocatedTrampolineForGuestFunction) {
|
||||
FEXCore::FinalizeHostTrampolineForGuestFunction((FEXCore::HostToGuestTrampolinePtr*)PreallocatedTrampolineForGuestFunction.data,
|
||||
(void*)&CallbackUnpack<F>::CallGuestPtr);
|
||||
FEX::HLE::FinalizeHostTrampolineForGuestFunction((FEX::HLE::HostToGuestTrampolinePtr*)PreallocatedTrampolineForGuestFunction.data,
|
||||
(void*)&CallbackUnpack<F>::CallGuestPtr);
|
||||
}
|
||||
|
||||
// In the case of the thunk host_loader being the default, FEX need to use dlsym with RTLD_DEFAULT.
|
||||
|
||||
@@ -335,8 +335,8 @@ fexfn_impl_libwayland_client_wl_proxy_add_listener(struct wl_proxy* proxy, guest
|
||||
WaylandFinalizeHostTrampolineForGuestListener<>(callback);
|
||||
} else if (signature == "a") {
|
||||
// E.g. xdg_toplevel::wm_capabilities
|
||||
FEXCore::FinalizeHostTrampolineForGuestFunction((FEXCore::HostToGuestTrampolinePtr*)callback,
|
||||
(void*)CallGuestPtrWithWaylandArray<void, void*, wl_proxy*>);
|
||||
FEX::HLE::FinalizeHostTrampolineForGuestFunction((FEX::HLE::HostToGuestTrampolinePtr*)callback,
|
||||
(void*)CallGuestPtrWithWaylandArray<void, void*, wl_proxy*>);
|
||||
} else if (signature == "hu") {
|
||||
// E.g. zwp_linux_dmabuf_feedback_v1::format_table
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'h', 'u'>(callback);
|
||||
@@ -354,8 +354,8 @@ fexfn_impl_libwayland_client_wl_proxy_add_listener(struct wl_proxy* proxy, guest
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'i', 'i'>(callback);
|
||||
} else if (signature == "iia") {
|
||||
// E.g. xdg_toplevel::configure
|
||||
FEXCore::FinalizeHostTrampolineForGuestFunction((FEXCore::HostToGuestTrampolinePtr*)callback,
|
||||
(void*)CallGuestPtrWithWaylandArray<void, void*, wl_proxy*, int32_t, int32_t>);
|
||||
FEX::HLE::FinalizeHostTrampolineForGuestFunction((FEX::HLE::HostToGuestTrampolinePtr*)callback,
|
||||
(void*)CallGuestPtrWithWaylandArray<void, void*, wl_proxy*, int32_t, int32_t>);
|
||||
} else if (signature == "iiiiissi") {
|
||||
// E.g. wl_output_listener::geometry
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'i', 'i', 'i', 'i', 'i', 's', 's', 'i'>(callback);
|
||||
@@ -388,8 +388,8 @@ fexfn_impl_libwayland_client_wl_proxy_add_listener(struct wl_proxy* proxy, guest
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'u', 'o'>(callback);
|
||||
} else if (signature == "uoa") {
|
||||
// E.g. wl_keyboard_listener::enter
|
||||
FEXCore::FinalizeHostTrampolineForGuestFunction((FEXCore::HostToGuestTrampolinePtr*)callback,
|
||||
(void*)CallGuestPtrWithWaylandArray<void, void*, wl_proxy*, uint32_t, wl_surface*>);
|
||||
FEX::HLE::FinalizeHostTrampolineForGuestFunction((FEX::HLE::HostToGuestTrampolinePtr*)callback,
|
||||
(void*)CallGuestPtrWithWaylandArray<void, void*, wl_proxy*, uint32_t, wl_surface*>);
|
||||
} else if (signature == "uoff") {
|
||||
// E.g. wl_pointer_listener::enter
|
||||
WaylandFinalizeHostTrampolineForGuestListener<'u', 'o', 'f', 'f'>(callback);
|
||||
|
||||
Reference in new issue
Block a user