mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-24 07:00:44 +02:00
Merge pull request #281 from FEX-Emu/skmp/native-lib-thunking-3
Thunks: ALTINST, OP_THUNK, basic infrastructure
This commit is contained in:
20 files changed
+337
-1
No files matched your search
+1
@@ -164,6 +164,7 @@ set (SRCS
|
||||
Interface/HLE/Syscalls/Timer.cpp
|
||||
Interface/HLE/Syscalls/NotImplemented.cpp
|
||||
Interface/HLE/Syscalls/Stubs.cpp
|
||||
Interface/HLE/Thunks/Thunks.cpp
|
||||
Interface/Memory/MemMapper.cpp
|
||||
Interface/Memory/SharedMem.cpp
|
||||
Interface/IR/IR.cpp
|
||||
|
||||
@@ -42,6 +42,9 @@ namespace FEXCore::Config {
|
||||
case CONFIG_ROOTFSPATH:
|
||||
CTX->Config.RootFSPath = Config;
|
||||
break;
|
||||
case CONFIG_THUNKLIBSPATH:
|
||||
CTX->Config.ThunkLibsPath = Config;
|
||||
break;
|
||||
default: LogMan::Msg::A("Unknown configuration option");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
namespace FEXCore {
|
||||
class SyscallHandler;
|
||||
class ThunkHandler;
|
||||
class BlockSamplingData;
|
||||
class GdbServer;
|
||||
|
||||
@@ -52,6 +53,7 @@ namespace FEXCore::Context {
|
||||
bool GdbServer {false};
|
||||
bool UnifiedMemory {true};
|
||||
std::string RootFSPath;
|
||||
std::string ThunkLibsPath;
|
||||
|
||||
bool Is64BitMode {true};
|
||||
uint64_t EmulatedCPUCores{1};
|
||||
@@ -80,6 +82,8 @@ namespace FEXCore::Context {
|
||||
|
||||
FEXCore::CPUIDEmu CPUID;
|
||||
std::unique_ptr<FEXCore::SyscallHandler> SyscallHandler;
|
||||
std::unique_ptr<FEXCore::ThunkHandler> ThunkHandler;
|
||||
|
||||
CustomCPUFactoryType CustomCPUFactory;
|
||||
CustomCPUFactoryType FallbackCPUFactory;
|
||||
std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> CustomExitHandler;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <FEXCore/Core/CPUBackend.h>
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
|
||||
#include "Interface/HLE/Thunks/Thunks.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -229,6 +231,8 @@ namespace FEXCore::Context {
|
||||
|
||||
bool Context::InitCore(FEXCore::CodeLoader *Loader) {
|
||||
SyscallHandler.reset(FEXCore::CreateHandler(Config.Is64BitMode ? OperatingMode::MODE_64BIT : OperatingMode::MODE_32BIT, this));
|
||||
ThunkHandler.reset(FEXCore::ThunkHandler::Create());
|
||||
|
||||
LocalLoader = Loader;
|
||||
using namespace FEXCore::Core;
|
||||
FEXCore::Core::CPUState NewThreadState{};
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <FEXCore/IR/IR.h>
|
||||
#include <FEXCore/IR/IntrusiveIRList.h>
|
||||
|
||||
#include "Interface/HLE/Thunks/Thunks.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
@@ -248,6 +250,15 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) {
|
||||
GD = Res;
|
||||
break;
|
||||
}
|
||||
case IR::OP_THUNK: {
|
||||
auto Op = IROp->C<IR::IROp_Thunk>();
|
||||
|
||||
//LogMan::Msg::D("Thunk function: %s, %p, %p\n", Op->ThunkName, Op->ThunkFnPtr, *GetSrc<void**>(Op->Header.Args[0]));
|
||||
|
||||
reinterpret_cast<ThunkedFunction*>(Op->ThunkFnPtr)(CTX, *GetSrc<void**>(Op->Header.Args[0]));
|
||||
|
||||
break;
|
||||
}
|
||||
case IR::OP_CPUID: {
|
||||
auto Op = IROp->C<IR::IROp_CPUID>();
|
||||
uint64_t *DstPtr = GetDest<uint64_t*>(*WrapperOp);
|
||||
|
||||
@@ -123,6 +123,45 @@ DEF_OP(Syscall) {
|
||||
add(sp, sp, SPOffset);
|
||||
}
|
||||
|
||||
DEF_OP(Thunk) {
|
||||
auto Op = IROp->C<IR::IROp_Thunk>();
|
||||
// Arguments are passed as follows:
|
||||
// X0: CTX
|
||||
// X1: Args (from guest stack)
|
||||
|
||||
uint64_t SPOffset = AlignUp((RA64.size() + 1) * 8, 16);
|
||||
|
||||
sub(sp, sp, SPOffset);
|
||||
|
||||
int i = 0;
|
||||
for (auto RA : RA64) {
|
||||
str(RA, MemOperand(sp, i * 8));
|
||||
i++;
|
||||
}
|
||||
str(lr, MemOperand(sp, RA64.size() * 8 + 0 * 8));
|
||||
|
||||
LoadConstant(x0, reinterpret_cast<uint64_t>(CTX));
|
||||
mov(x1, GetReg<RA_64>(Op->Header.Args[0].ID()));
|
||||
|
||||
#if _M_X86_64
|
||||
ERROR_AND_DIE("JIT: OP_THUNK not supported with arm simulator")
|
||||
#else
|
||||
LoadConstant(x2, Op->ThunkFnPtr);
|
||||
blr(x2);
|
||||
#endif
|
||||
|
||||
// Fix the stack and any values that were stepped on
|
||||
i = 0;
|
||||
for (auto RA : RA64) {
|
||||
ldr(RA, MemOperand(sp, i * 8));
|
||||
i++;
|
||||
}
|
||||
|
||||
ldr(lr, MemOperand(sp, RA64.size() * 8 + 0 * 8));
|
||||
|
||||
add(sp, sp, SPOffset);
|
||||
}
|
||||
|
||||
DEF_OP(CPUID) {
|
||||
auto Op = IROp->C<IR::IROp_CPUID>();
|
||||
uint64_t SPOffset = AlignUp((RA64.size() + 2 + 2) * 8, 16);
|
||||
@@ -173,6 +212,7 @@ void JITCore::RegisterBranchHandlers() {
|
||||
REGISTER_OP(JUMP, Jump);
|
||||
REGISTER_OP(CONDJUMP, CondJump);
|
||||
REGISTER_OP(SYSCALL, Syscall);
|
||||
REGISTER_OP(THUNK, Thunk);
|
||||
REGISTER_OP(CPUID, CPUID);
|
||||
#undef REGISTER_OP
|
||||
}
|
||||
|
||||
@@ -277,6 +277,7 @@ private:
|
||||
DEF_OP(Jump);
|
||||
DEF_OP(CondJump);
|
||||
DEF_OP(Syscall);
|
||||
DEF_OP(Thunk);
|
||||
DEF_OP(CPUID);
|
||||
|
||||
///< Conversion ops
|
||||
|
||||
@@ -2006,6 +2006,33 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView<true> const
|
||||
mov (GetDst<RA_64>(Node), rax);
|
||||
break;
|
||||
}
|
||||
case IR::OP_THUNK: {
|
||||
auto Op = IROp->C<IR::IROp_Thunk>();
|
||||
|
||||
auto NumPush = 1 + RA64.size();
|
||||
push(rdi);
|
||||
|
||||
for (auto &Reg : RA64)
|
||||
push(Reg);
|
||||
|
||||
if (NumPush & 1)
|
||||
sub(rsp, 8); // Align
|
||||
|
||||
mov(rdi, reinterpret_cast<uintptr_t>(CTX));
|
||||
mov(rsi, GetSrc<RA_64>(Op->Header.Args[0].ID()));
|
||||
|
||||
mov(rax, reinterpret_cast<uintptr_t>(Op->ThunkFnPtr));
|
||||
call(rax);
|
||||
|
||||
if (NumPush & 1)
|
||||
add(rsp, 8); // Align
|
||||
|
||||
for (uint32_t i = RA64.size(); i > 0; --i)
|
||||
pop(RA64[i - 1]);
|
||||
|
||||
pop(rdi);
|
||||
break;
|
||||
}
|
||||
case IR::OP_VEXTRACTTOGPR: {
|
||||
auto Op = IROp->C<IR::IROp_VExtractToGPR>();
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ private:
|
||||
|
||||
struct LLVMCurrentState {
|
||||
llvm::Function *SyscallFunction;
|
||||
llvm::Function *ThunkFunction;
|
||||
llvm::Function *CPUIDFunction;
|
||||
llvm::Function *ExitVMFunction;
|
||||
llvm::Function *ValuePrinter;
|
||||
@@ -991,6 +992,31 @@ void LLVMJITCore::CreateGlobalVariables(llvm::ExecutionEngine *Engine, llvm::Mod
|
||||
Engine->addGlobalMapping(JITCurrentState.SyscallFunction, Ptr.Data);
|
||||
}
|
||||
|
||||
// Thunk Function
|
||||
{
|
||||
auto FuncType = FunctionType::get(voidTy,
|
||||
{
|
||||
i64, // Technically a this pointer
|
||||
i64, // Technically a this pointer
|
||||
i64, // Technically a this pointer
|
||||
},
|
||||
false);
|
||||
JITCurrentState.ThunkFunction = Function::Create(FuncType,
|
||||
Function::ExternalLinkage,
|
||||
"ThunkCaller",
|
||||
FunctionModule);
|
||||
using ClassPtrType = void (*)(void (*)(void*, void*), void*, void*);
|
||||
union PtrCast {
|
||||
ClassPtrType ClassPtr;
|
||||
void* Data;
|
||||
};
|
||||
PtrCast Ptr;
|
||||
Ptr.ClassPtr = [](void(*fn)(void*, void*), void* ctx, void* args) {
|
||||
fn(ctx, args);
|
||||
};
|
||||
Engine->addGlobalMapping(JITCurrentState.ThunkFunction, Ptr.Data);
|
||||
}
|
||||
|
||||
// CPUID Function
|
||||
{
|
||||
auto FuncType = FunctionType::get(i128,
|
||||
@@ -1687,6 +1713,17 @@ void LLVMJITCore::HandleIR(FEXCore::IR::IRListView<true> const *IR, IR::NodeWrap
|
||||
SetDest(*WrapperOp, Result);
|
||||
break;
|
||||
}
|
||||
case IR::OP_THUNK: {
|
||||
auto Op = IROp->C<IR::IROp_Thunk>();
|
||||
std::vector<llvm::Value*> Args{};
|
||||
|
||||
Args.emplace_back(JITState.IRBuilder->getInt64(Op->ThunkFnPtr)); // function to call
|
||||
Args.emplace_back(JITState.IRBuilder->getInt64(reinterpret_cast<uint64_t>(CTX))); // context
|
||||
Args.emplace_back(GetSrc(Op->Header.Args[0])); // params
|
||||
|
||||
JITState.IRBuilder->CreateCall(JITCurrentState.ThunkFunction, Args);
|
||||
break;
|
||||
}
|
||||
case IR::OP_CPUID: {
|
||||
auto Op = IROp->C<IR::IROp_CPUID>();
|
||||
auto Src = GetSrc(Op->Header.Args[0]);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "Interface/Context/Context.h"
|
||||
#include "Interface/Core/OpcodeDispatcher.h"
|
||||
#include "Interface/HLE/Thunks/Thunks.h"
|
||||
|
||||
#include <FEXCore/Core/CoreState.h>
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
@@ -85,6 +87,41 @@ void OpDispatchBuilder::SyscallOp(OpcodeArgs) {
|
||||
_StoreContext(GPRClass, GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RAX]), SyscallOp);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::ThunkOp(OpcodeArgs) {
|
||||
uint8_t GPRSize = CTX->Config.Is64BitMode ? 8 : 4;
|
||||
const char *name;
|
||||
|
||||
if (CTX->Config.UnifiedMemory) {
|
||||
name = (const char*)(Op->PC + 2);
|
||||
} else {
|
||||
name = CTX->MemoryMapper.GetPointer<const char*>(Op->PC + 2);
|
||||
}
|
||||
|
||||
_Thunk(
|
||||
_LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass),
|
||||
name,
|
||||
(uintptr_t)CTX->ThunkHandler->LookupThunk(name)
|
||||
);
|
||||
|
||||
auto Constant = _Constant(GPRSize);
|
||||
|
||||
auto OldSP = _LoadContext(GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSP]), GPRClass);
|
||||
|
||||
auto NewRIP = _LoadMem(GPRClass, GPRSize, OldSP, GPRSize);
|
||||
|
||||
OrderedNode *NewSP;
|
||||
|
||||
NewSP = _Add(OldSP, Constant);
|
||||
|
||||
// Store the new stack pointer
|
||||
_StoreContext(GPRClass, GPRSize, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RSP]), NewSP);
|
||||
|
||||
// Store the new RIP
|
||||
_StoreContext(GPRClass, GPRSize, offsetof(FEXCore::Core::CPUState, rip), NewRIP);
|
||||
_ExitFunction();
|
||||
BlockSetRIP = true;
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::LEAOp(OpcodeArgs) {
|
||||
if (CTX->Config.Is64BitMode) {
|
||||
uint32_t DstSize = X86Tables::DecodeFlags::GetOpAddr(Op->Flags, 0) == X86Tables::DecodeFlags::FLAG_OPERAND_SIZE_LAST ? 2 :
|
||||
@@ -7082,6 +7119,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) {
|
||||
|
||||
{0x31, 1, &OpDispatchBuilder::RDTSCOp},
|
||||
|
||||
{0x3F, 1, &OpDispatchBuilder::ThunkOp},
|
||||
{0x40, 16, &OpDispatchBuilder::CMOVOp},
|
||||
{0x6E, 1, &OpDispatchBuilder::MOVBetweenGPR_FPR},
|
||||
{0x6F, 1, &OpDispatchBuilder::MOVUPSOp},
|
||||
|
||||
@@ -100,6 +100,7 @@ public:
|
||||
void ALUOp(OpcodeArgs);
|
||||
void INTOp(OpcodeArgs);
|
||||
void SyscallOp(OpcodeArgs);
|
||||
void ThunkOp(OpcodeArgs);
|
||||
void LEAOp(OpcodeArgs);
|
||||
void NOPOp(OpcodeArgs);
|
||||
void RETOp(OpcodeArgs);
|
||||
|
||||
@@ -57,7 +57,7 @@ void InitializeSecondaryTables() {
|
||||
{0x38, 1, X86InstInfo{"", TYPE_0F38_TABLE, FLAGS_NO_OVERLAY, 0, nullptr}},
|
||||
{0x39, 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NO_OVERLAY, 0, nullptr}},
|
||||
{0x3A, 1, X86InstInfo{"", TYPE_0F3A_TABLE, FLAGS_NO_OVERLAY, 0, nullptr}},
|
||||
{0x3B, 5, X86InstInfo{"", TYPE_INVALID, FLAGS_NO_OVERLAY, 0, nullptr}},
|
||||
{0x3B, 4, X86InstInfo{"", TYPE_INVALID, FLAGS_NO_OVERLAY, 0, nullptr}},
|
||||
|
||||
{0x40, 1, X86InstInfo{"CMOVO", TYPE_INST, FLAGS_MODRM | FLAGS_NO_OVERLAY, 0, nullptr}},
|
||||
{0x41, 1, X86InstInfo{"CMOVNO", TYPE_INST, FLAGS_MODRM | FLAGS_NO_OVERLAY, 0, nullptr}},
|
||||
@@ -248,6 +248,12 @@ void InitializeSecondaryTables() {
|
||||
{0xFD, 1, X86InstInfo{"PADDW", TYPE_INST, GenFlagsSameSize(SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_MMX, 0, nullptr}},
|
||||
{0xFE, 1, X86InstInfo{"PADDD", TYPE_INST, GenFlagsSameSize(SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_MMX, 0, nullptr}},
|
||||
{0xFF, 1, X86InstInfo{"UD0", TYPE_INST, FLAGS_DEBUG | FLAGS_BLOCK_END, 0, nullptr}},
|
||||
|
||||
// FEX reserved instructions
|
||||
// Unused x86 encoding instruction.
|
||||
|
||||
// This was originally used by VIA to jump to its alternative instruction set. Used for OP_THUNK
|
||||
{0x3F, 1, X86InstInfo{"ALTINST", TYPE_INST, FLAGS_BLOCK_END | FLAGS_NO_OVERLAY | FLAGS_SETS_RIP, 0, nullptr}},
|
||||
};
|
||||
|
||||
const U8U8InfoStruct RepModOpTable[] = {
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
#include "Thunks.h"
|
||||
#include <LogManager.h>
|
||||
|
||||
#include "stdio.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <Interface/Context/Context.h>
|
||||
#include <LogManager.h>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace FEXCore {
|
||||
|
||||
struct ExportEntry { const char* Name; ThunkedFunction* Fn; };
|
||||
|
||||
class ThunkHandler_impl final: public ThunkHandler {
|
||||
std::shared_mutex ThunksMutex;
|
||||
|
||||
std::map<std::string, ThunkedFunction*> Thunks = {
|
||||
{ "fex:loadlib", &loadlib}
|
||||
};
|
||||
|
||||
static void loadlib(FEXCore::Context::Context *CTX, void* Name) {
|
||||
if (!CTX->Config.UnifiedMemory) {
|
||||
Name = CTX->MemoryMapper.GetPointer<void*>((uintptr_t)Name);
|
||||
}
|
||||
|
||||
auto SOName = CTX->Config.ThunkLibsPath + "/" + (const char*)Name + "-host.so";
|
||||
|
||||
LogMan::Msg::D("Load lib: %s -> %s", Name, SOName.c_str());
|
||||
|
||||
auto Handle = dlopen(SOName.c_str(), RTLD_LOCAL | RTLD_NOW);
|
||||
|
||||
if (!Handle) {
|
||||
LogMan::Msg::E("Load lib: failed to dlopen %s", SOName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
ExportEntry* (*InitFN)();
|
||||
|
||||
auto InitSym = std::string("fexthunks_exports_") + (const char*)Name;
|
||||
|
||||
(void*&)InitFN = dlsym(Handle, InitSym.c_str());
|
||||
|
||||
if (!InitFN) {
|
||||
LogMan::Msg::E("Load lib: failed to find export %s", InitSym.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
auto Exports = InitFN();
|
||||
|
||||
auto That = reinterpret_cast<ThunkHandler_impl*>(CTX->ThunkHandler.get());
|
||||
|
||||
{
|
||||
std::unique_lock lk(That->ThunksMutex);
|
||||
|
||||
int i;
|
||||
for (i = 0; Exports[i].Name; i++) {
|
||||
That->Thunks[Exports[i].Name] = Exports[i].Fn;
|
||||
}
|
||||
|
||||
LogMan::Msg::D("Loaded %d syms", i);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
ThunkedFunction* LookupThunk(const char *Name) {
|
||||
|
||||
std::shared_lock lk(ThunksMutex);
|
||||
|
||||
auto it = Thunks.find(Name);
|
||||
|
||||
if (it != Thunks.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ThunkHandler_impl() {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
ThunkHandler* ThunkHandler::Create() {
|
||||
return new ThunkHandler_impl();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace FEXCore::Context {
|
||||
struct Context;
|
||||
}
|
||||
|
||||
namespace FEXCore {
|
||||
typedef void ThunkedFunction(FEXCore::Context::Context *CTX, void* ArgsRv);
|
||||
|
||||
class ThunkHandler {
|
||||
public:
|
||||
virtual ThunkedFunction* LookupThunk(const char *name) = 0;
|
||||
virtual ~ThunkHandler() { }
|
||||
|
||||
static ThunkHandler* Create();
|
||||
};
|
||||
};
|
||||
+4
@@ -15,6 +15,10 @@ static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false>
|
||||
*out << "#0x" << std::hex << Arg;
|
||||
}
|
||||
|
||||
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false> const* IR, const char* Arg) {
|
||||
*out << Arg;
|
||||
}
|
||||
|
||||
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false> const* IR, CondClassType Arg) {
|
||||
std::array<std::string, 14> CondNames = {
|
||||
"EQ",
|
||||
|
||||
+13
@@ -483,6 +483,19 @@
|
||||
]
|
||||
},
|
||||
|
||||
"Thunk": {
|
||||
"HasSideEffects": true,
|
||||
"OpClass": "Branch",
|
||||
"SSAArgs": "1",
|
||||
"SSANames": [
|
||||
"ArgPtr"
|
||||
],
|
||||
"Args":[
|
||||
"const char*", "ThunkName",
|
||||
"uintptr_t", "ThunkFnPtr"
|
||||
]
|
||||
},
|
||||
|
||||
"LoadMem": {
|
||||
"OpClass": "Memory",
|
||||
"HasDest": true,
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace FEXCore::Config {
|
||||
CONFIG_SINGLESTEP,
|
||||
CONFIG_GDBSERVER,
|
||||
CONFIG_ROOTFSPATH,
|
||||
CONFIG_THUNKLIBSPATH,
|
||||
CONFIG_UNIFIED_MEMORY,
|
||||
CONFIG_IS64BIT_MODE,
|
||||
CONFIG_EMULATED_CPU_CORES,
|
||||
|
||||
@@ -66,11 +66,16 @@ namespace FEX::ArgLoader {
|
||||
}
|
||||
{
|
||||
Parser.set_defaults("RootFS", "");
|
||||
Parser.set_defaults("ThunkLibs", "");
|
||||
|
||||
EmulationGroup.add_option("-R", "--rootfs")
|
||||
.dest("RootFS")
|
||||
.help("Which Root filesystem prefix to use");
|
||||
|
||||
EmulationGroup.add_option("-t", "--thunklibs")
|
||||
.dest("ThunkLibs")
|
||||
.help("Folder to find the host-side thunking libs");
|
||||
|
||||
EmulationGroup.add_option("-U", "--unified-memory")
|
||||
.dest("UnifiedMemory")
|
||||
.action("store_true")
|
||||
@@ -177,6 +182,11 @@ namespace FEX::ArgLoader {
|
||||
Config::Add("RootFS", Option);
|
||||
}
|
||||
|
||||
if (Options.is_set_by_user("ThunkLibs")) {
|
||||
std::string Option = Options["ThunkLibs"];
|
||||
Config::Add("ThunkLibs", Option);
|
||||
}
|
||||
|
||||
if (Options.is_set_by_user("UnifiedMemory")) {
|
||||
bool Option = Options.get("UnifiedMemory");
|
||||
Config::Add("UnifiedMemory", std::to_string(Option));
|
||||
|
||||
@@ -101,6 +101,7 @@ int main(int argc, char **argv, char **const envp) {
|
||||
FEX::Config::Value<uint64_t> ThreadsConfig{"Threads", 1};
|
||||
FEX::Config::Value<bool> UnifiedMemory{"UnifiedMemory", true};
|
||||
FEX::Config::Value<std::string> LDPath{"RootFS", ""};
|
||||
FEX::Config::Value<std::string> ThunkLibsPath{"ThunkLibs", ""};
|
||||
FEX::Config::Value<bool> SilentLog{"SilentLog", false};
|
||||
FEX::Config::Value<std::string> Environment{"Env", ""};
|
||||
|
||||
@@ -129,6 +130,7 @@ int main(int argc, char **argv, char **const envp) {
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_MAXBLOCKINST, BlockSizeConfig());
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_GDBSERVER, GdbServerConfig());
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_ROOTFSPATH, LDPath());
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_THUNKLIBSPATH, ThunkLibsPath());
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_UNIFIED_MEMORY, UnifiedMemory());
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_IS64BIT_MODE, Loader.Is64BitMode());
|
||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_EMULATED_CPU_CORES, ThreadsConfig());
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
},
|
||||
"MemoryRegions": {
|
||||
"0x100000000": "4096"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
; this just ensures the thunking system runs
|
||||
; it doesn't actually load a lib
|
||||
|
||||
lea rdi, [rel libname]
|
||||
lea rax, [rel thunk_test]
|
||||
call rax
|
||||
|
||||
hlt
|
||||
|
||||
thunk_test:
|
||||
db 0xf, 0x3f
|
||||
db 'fex:loadlib'
|
||||
db 0
|
||||
|
||||
libname db 'not_a_real_lib'
|
||||
db 0
|
||||
Reference in new issue
Block a user