From 3728f5f1781344fabec3c4337059ecce062650e1 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 23 Dec 2025 12:45:40 -0800 Subject: [PATCH] Interpreter: Moves around the thread and ELF initialization code This allows the context and parent thread objects to be created earlier, allowing the VDSO and ELFCodeLoader mapping functions to have a thread object for tracking memory mappings through the regular guest routines. This means that we no longer need to do any form of deferred handling for code caching as all the state is ready early in the initialization process. A little bit of care needed to be taken to ensure we still close the ELFCodeLoader's FDs later and that VDSO unmapping happens before tearing down the parent thread, but overall this is mostly just passing the InternalThreadState object around as normal. I couldn't find any functional regression from this change alongside code caching, but it would be good for @neobrain to double check this. --- Source/Tools/FEXInterpreter/ELFCodeLoader.h | 43 +++++---- .../Tools/FEXInterpreter/FEXInterpreter.cpp | 90 ++++++++++--------- Source/Tools/FEXOfflineCompiler/Main.cpp | 15 ++-- .../LinuxEmulation/LinuxSyscalls/Syscalls.h | 3 - .../LinuxSyscalls/SyscallsSMCTracking.cpp | 16 +--- .../Tools/LinuxEmulation/VDSO_Emulation.cpp | 41 ++++----- Source/Tools/LinuxEmulation/VDSO_Emulation.h | 8 +- 7 files changed, 103 insertions(+), 113 deletions(-) diff --git a/Source/Tools/FEXInterpreter/ELFCodeLoader.h b/Source/Tools/FEXInterpreter/ELFCodeLoader.h index d282ba1a7..eb7832599 100644 --- a/Source/Tools/FEXInterpreter/ELFCodeLoader.h +++ b/Source/Tools/FEXInterpreter/ELFCodeLoader.h @@ -76,7 +76,8 @@ class ELFCodeLoader final : public FEX::CodeLoader { return FEXCore::AlignUp(max_map_address - min_map_address, FEXCore::Utils::FEX_PAGE_SIZE); } - bool MapFile(const ELFParser& file, uintptr_t Base, const Elf64_Phdr& Header, int prot, int flags, FEX::HLE::SyscallMmapInterface* const Handler) { + bool MapFile(const ELFParser& file, uintptr_t Base, const Elf64_Phdr& Header, int prot, int flags, + FEX::HLE::SyscallMmapInterface* const Handler, FEXCore::Core::InternalThreadState* Thread) { auto addr = Base + PAGE_START(Header.p_vaddr); auto size = Header.p_filesz + PAGE_OFFSET(Header.p_vaddr); @@ -89,7 +90,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { return true; } - void* rv = Handler->GuestMmap(nullptr, (void*)addr, size, prot, flags, file.fd, off); + void* rv = Handler->GuestMmap(Thread, (void*)addr, size, prot, flags, file.fd, off); if (FEX::HLE::HasSyscallError(rv)) { // uhoh, something went wrong @@ -124,7 +125,8 @@ class ELFCodeLoader final : public FEX::CodeLoader { return rv; } - std::optional LoadElfFile(ELFParser& Elf, uintptr_t* BrkBase, FEX::HLE::SyscallMmapInterface* const Handler, uint64_t LoadHint = 0) { + std::optional LoadElfFile(ELFParser& Elf, uintptr_t* BrkBase, FEX::HLE::SyscallMmapInterface* const Handler, + FEXCore::Core::InternalThreadState* Thread, uint64_t LoadHint = 0) { uintptr_t LoadBase = 0; uintptr_t BrkLoadBase = 0; @@ -135,7 +137,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { // Allocate a base address plus BRK padding. auto TotalSize = CalculateDYNELFSize(Elf.phdrs) + (BrkBase ? BRK_SIZE : 0); LoadBase = - (uintptr_t)Handler->GuestMmap(nullptr, reinterpret_cast(LoadHint), TotalSize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + (uintptr_t)Handler->GuestMmap(Thread, reinterpret_cast(LoadHint), TotalSize, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (FEX::HLE::HasSyscallError(LoadBase)) { return {}; } @@ -154,7 +156,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { int MapProt = MapFlags(Header); int MapType = MAP_PRIVATE | MAP_DENYWRITE | MAP_FIXED; - if (!MapFile(Elf, LoadBase, Header, MapProt, MapType, Handler)) { + if (!MapFile(Elf, LoadBase, Header, MapProt, MapType, Handler, Thread)) { return {}; } @@ -170,7 +172,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { } if (BSSPageStart != BSSPageEnd) { - auto bss = Handler->GuestMmap(nullptr, (void*)BSSPageStart, BSSPageEnd - BSSPageStart, MapProt, MapType | MAP_ANONYMOUS, -1, 0); + auto bss = Handler->GuestMmap(Thread, (void*)BSSPageStart, BSSPageEnd - BSSPageStart, MapProt, MapType | MAP_ANONYMOUS, -1, 0); if (FEX::HLE::HasSyscallError(bss)) { LogMan::Msg::EFmt("Failed to allocate BSS @ {}, {}\n", fmt::ptr(bss), errno); return {}; @@ -192,7 +194,7 @@ class ELFCodeLoader final : public FEX::CodeLoader { if (NeedsLateBRKMap) { // Map the BRK after ELF if possible. BrkLoadBase = - (uintptr_t)Handler->GuestMmap(nullptr, reinterpret_cast(BrkLoadBase), BRK_SIZE, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + (uintptr_t)Handler->GuestMmap(Thread, reinterpret_cast(BrkLoadBase), BRK_SIZE, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (FEX::HLE::HasSyscallError(BrkLoadBase)) { // This isn't a catastrophic failure. This just means the BRK conflicted with the ELF. BrkLoadBase = 0; @@ -381,11 +383,12 @@ public: return MainElf.fd; } - std::optional LoadMainElfFile(uintptr_t* BrkBase, FEX::HLE::SyscallMmapInterface* const Handler, uint64_t LoadHint = 0) { - return LoadElfFile(MainElf, BrkBase, Handler, LoadHint); + std::optional LoadMainElfFile(uintptr_t* BrkBase, FEX::HLE::SyscallMmapInterface* const Handler, + FEXCore::Core::InternalThreadState* Thread, uint64_t LoadHint = 0) { + return LoadElfFile(MainElf, BrkBase, Handler, Thread, LoadHint); } - bool MapMemory(FEX::HLE::SyscallMmapInterface* const Handler) { + bool MapMemory(FEX::HLE::SyscallMmapInterface* const Handler, FEXCore::Core::InternalThreadState* Thread) { for (const auto& Header : MainElf.phdrs) { if (Header.p_type == PT_GNU_STACK) { if (Header.p_flags & PF_X) { @@ -440,7 +443,7 @@ public: uint64_t StackHint = Is64BitMode() ? STACK_HINT_64 : STACK_HINT_32; // Allocate the base of the full 128MB stack range. - StackPointerBase = Handler->GuestMmap(nullptr, reinterpret_cast(StackHint), FULL_STACK_SIZE, PROT_NONE, + StackPointerBase = Handler->GuestMmap(Thread, reinterpret_cast(StackHint), FULL_STACK_SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN | MAP_NORESERVE, -1, 0); @@ -451,7 +454,7 @@ public: // Allocate with permissions the 8MB of regular stack size. StackPointer = reinterpret_cast( - Handler->GuestMmap(nullptr, reinterpret_cast(reinterpret_cast(StackPointerBase) + FULL_STACK_SIZE - StackSize()), + Handler->GuestMmap(Thread, reinterpret_cast(reinterpret_cast(StackPointerBase) + FULL_STACK_SIZE - StackSize()), StackSize(), PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK | MAP_GROWSDOWN, -1, 0)); if (FEX::HLE::HasSyscallError(StackPointer)) { @@ -498,7 +501,7 @@ public: if (!MainElf.InterpreterElf.empty()) { uint64_t InterpLoadBase = 0; - if (auto elf = LoadElfFile(InterpElf, nullptr, Handler)) { + if (auto elf = LoadElfFile(InterpElf, nullptr, Handler, Thread)) { InterpLoadBase = *elf; } else { LogMan::Msg::EFmt("Failed to load interpreter elf file"); @@ -560,7 +563,7 @@ public: uintptr_t LoadBase = 0; - if (auto elf = LoadElfFile(MainElf, &BrkStart, Handler, ELFLoadHint)) { + if (auto elf = LoadElfFile(MainElf, &BrkStart, Handler, Thread, ELFLoadHint)) { LoadBase = *elf; if (MainElf.ehdr.e_type == ET_DYN) { BaseOffset = LoadBase; @@ -573,8 +576,8 @@ public: if (BrkStart) { // BRK usually comes directly after where the ELF is loaded. // If a value was returned then we have mapped the entire `BRK_SIZE` and need to change protections. - BrkStart = (uint64_t)Handler->GuestMmap(nullptr, (void*)BrkStart, BRK_SIZE, PROT_READ | PROT_WRITE, - MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + BrkStart = + (uint64_t)Handler->GuestMmap(Thread, (void*)BrkStart, BRK_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); if (FEX::HLE::HasSyscallError(BrkStart)) { LogMan::Msg::EFmt("Failed to allocate BRK @ {:x}, {}\n", BrkStart, errno); return false; @@ -618,7 +621,7 @@ public: // If the VDSO thunk doesn't exist then we might not have a vsyscall entry. // Newer glibc requires vsyscall to exist now. So let's allocate a buffer and stick a vsyscall in to it. auto VSyscallPage = - Handler->GuestMmap(nullptr, nullptr, FEXCore::Utils::FEX_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + Handler->GuestMmap(Thread, nullptr, FEXCore::Utils::FEX_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); constexpr static uint8_t VSyscallCode[] = { 0xcd, 0x80, // int 0x80 0xc3, // ret @@ -643,10 +646,12 @@ public: SetupStack(); - // Cleanup FDs so they don't stay open + return true; + } + + void CloseFDs() { MainElf.Closefd(); InterpElf.Closefd(); - return true; } // Helper for stack setup diff --git a/Source/Tools/FEXInterpreter/FEXInterpreter.cpp b/Source/Tools/FEXInterpreter/FEXInterpreter.cpp index a987ee0c9..56675beb5 100644 --- a/Source/Tools/FEXInterpreter/FEXInterpreter.cpp +++ b/Source/Tools/FEXInterpreter/FEXInterpreter.cpp @@ -523,16 +523,20 @@ int main(int argc, char** argv, char** const envp) { 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(FEX::Allocator::Allocator)); + SyscallHandler->SetCodeLoader(&Loader); + CTX->SetSignalDelegator(SignalDelegation.get()); + CTX->SetSyscallHandler(SyscallHandler.get()); + CTX->SetThunkHandler(ThunkHandler.get()); + if (FEXCore::Config::Get_ENABLECODECACHINGWIP()) { CTX->SetCodeMapWriter(fextl::make_unique(*SyscallHandler)); } - // Load VDSO in to memory prior to mapping our ELFs. - auto VDSOMapping = FEX::VDSO::LoadVDSOThunks(Loader.Is64BitMode(), SyscallHandler.get()); - - // Pass in our VDSO thunks - ThunkHandler->AppendThunkDefinitions(FEX::VDSO::GetVDSOThunkDefinitions(Loader.Is64BitMode())); - SignalDelegation->SetVDSOSymbols(); + FEX_CONFIG_OPT(GdbServer, GDBSERVER); + fextl::unique_ptr DebugServer; + if (GdbServer) { + DebugServer = fextl::make_unique(CTX.get(), SignalDelegation.get(), SyscallHandler.get()); + } // Now that we have the syscall handler. Track some FDs that are FEX owned. if (FEX::Logging::OutputFD > 2) { @@ -543,53 +547,51 @@ int main(int argc, char** argv, char** const envp) { SyscallHandler->FM.TrackFEXFD(FEX::Logging::FEXServer::FEXServerFD); } - // query ProgramFD now since MapMemory will close it - const int ProgramFD = dup(Loader.GetMainElfFD()); - - { - Loader.SetVDSOBase(VDSOMapping.VDSOBase); - Loader.CalculateHWCaps(CTX.get()); - - if (!Loader.MapMemory(SyscallHandler.get())) { - // failed to map - LogMan::Msg::EFmt("Failed to map {}-bit elf file.", Loader.Is64BitMode() ? 64 : 32); - return -ENOEXEC; - } - } - - SyscallHandler->SetCodeLoader(&Loader); - - auto BRKInfo = Loader.GetBRKInfo(); - - SyscallHandler->DefaultProgramBreak(BRKInfo.Base, BRKInfo.Size); - - CTX->SetSignalDelegator(SignalDelegation.get()); - CTX->SetSyscallHandler(SyscallHandler.get()); - CTX->SetThunkHandler(ThunkHandler.get()); - - FEX_CONFIG_OPT(GdbServer, GDBSERVER); - fextl::unique_ptr DebugServer; - if (GdbServer) { - DebugServer = fextl::make_unique(CTX.get(), SignalDelegation.get(), SyscallHandler.get()); - } - if (!CTX->InitCore()) { return 1; } - auto ParentThread = SyscallHandler->TM.CreateThread(Loader.DefaultRIP(), Loader.GetStackPointer()); + // Create a thread without a RIP or stack pointer setup initially. + auto ParentThread = SyscallHandler->TM.CreateThread(0, 0); SyscallHandler->TM.TrackThread(ParentThread); SignalDelegation->RegisterTLSState(ParentThread); ThunkHandler->RegisterTLSState(ParentThread); SyscallHandler->DeserializeSeccompFD(ParentThread, FEXSeccompFD); - // Request code cache generation and load caches for all binaries loaded previously - if (FEXCore::Config::Get_ENABLECODECACHINGWIP()) { - FEXServerClient::PopulateCodeCache(FEXServerClient::GetServerFD(), ProgramFD, FEXCore::Config::Get_MULTIBLOCK()); - SyscallHandler->TriggerPostStartupCodeCacheLoad(*ParentThread->Thread); + // Load VDSO in to memory prior to mapping our ELFs. + auto VDSOMapping = FEX::VDSO::LoadVDSOThunks(ParentThread->Thread, Loader.Is64BitMode(), SyscallHandler.get()); + + // Pass in our VDSO thunks + ThunkHandler->AppendThunkDefinitions(FEX::VDSO::GetVDSOThunkDefinitions(Loader.Is64BitMode())); + SignalDelegation->SetVDSOSymbols(); + + { + Loader.SetVDSOBase(VDSOMapping.VDSOBase); + Loader.CalculateHWCaps(CTX.get()); + + if (!Loader.MapMemory(SyscallHandler.get(), ParentThread->Thread)) { + // failed to map + LogMan::Msg::EFmt("Failed to map {}-bit elf file.", Loader.Is64BitMode() ? 64 : 32); + return -ENOEXEC; + } } - close(ProgramFD); + + auto BRKInfo = Loader.GetBRKInfo(); + + SyscallHandler->DefaultProgramBreak(BRKInfo.Base, BRKInfo.Size); + + // Request code cache generation + if (FEXCore::Config::Get_ENABLECODECACHINGWIP()) { + FEXServerClient::PopulateCodeCache(FEXServerClient::GetServerFD(), Loader.GetMainElfFD(), FEXCore::Config::Get_MULTIBLOCK()); + } + + // Pull RIP and stack pointer from loader and set the thread data to it. + ParentThread->Thread->CurrentFrame->State.rip = Loader.DefaultRIP(); + ParentThread->Thread->CurrentFrame->State.gregs[FEXCore::X86State::REG_RSP] = Loader.GetStackPointer(); + + // Close the loader FDs after everything has been parsed and mapped. + Loader.CloseFDs(); CTX->ExecuteThread(ParentThread->Thread); @@ -598,11 +600,11 @@ int main(int argc, char** argv, char** const envp) { auto ProgramStatus = ParentThread->StatusCode; + FEX::VDSO::UnloadVDSOMapping(ParentThread->Thread, SyscallHandler.get(), VDSOMapping); + SignalDelegation->UninstallTLSState(ParentThread); SyscallHandler->TM.DestroyThread(ParentThread); - FEX::VDSO::UnloadVDSOMapping(VDSOMapping); - DebugServer.reset(); SyscallHandler.reset(); SignalDelegation.reset(); diff --git a/Source/Tools/FEXOfflineCompiler/Main.cpp b/Source/Tools/FEXOfflineCompiler/Main.cpp index e6d43b731..1f1a66aa1 100644 --- a/Source/Tools/FEXOfflineCompiler/Main.cpp +++ b/Source/Tools/FEXOfflineCompiler/Main.cpp @@ -153,19 +153,20 @@ GenerateSingleCache(const FEXCore::ExecutableFileInfo& Binary, fextl::setGetCodeCache().InitiateCacheGeneration(); { diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h index bc92a67b9..0e3f3aeb4 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls.h @@ -292,7 +292,6 @@ public: std::optional LookupExecutableFileSection(FEXCore::Core::InternalThreadState* Thread, uint64_t GuestAddr) final override; - void TriggerPostStartupCodeCacheLoad(FEXCore::Core::InternalThreadState&); int OpenCodeMapFile() override; FEXCore::HLE::ExecutableRangeInfo QueryGuestExecutableRange(FEXCore::Core::InternalThreadState* Thread, uint64_t Address) override; @@ -324,8 +323,6 @@ public: constexpr static size_t LDT_ENTRY_SIZE = sizeof(FEXCore::Core::CPUState::gdt_segment); VMATracking::VMATracking VMATracking; - // Collects file mappings added during FEX startup. - fextl::vector StartupBinaryLoads; const uint64_t CodeCacheConfigId = 0; // TODO: Make unique to active configuration diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp index b13fc1ae2..65944a22f 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/SyscallsSMCTracking.cpp @@ -351,18 +351,6 @@ uint64_t SyscallHandler::GuestMremap(bool Is64Bit, FEXCore::Core::InternalThread return Result; } -void SyscallHandler::TriggerPostStartupCodeCacheLoad(FEXCore::Core::InternalThreadState& Thread) { - if (!EnableCodeCaching) { - return; - } - - FEX_CONFIG_OPT(Multiblock, MULTIBLOCK); - for (auto& FileSection : StartupBinaryLoads) { - LoadCodeCache(Thread, FileSection, CodeCacheConfigId); - } - StartupBinaryLoads.clear(); -} - int SyscallHandler::OpenCodeMapFile() { // Query from FEXServer whether this is the first instance of this executable; if it is, also enable code dumping! FEX_CONFIG_OPT(RootFSPath, ROOTFS); @@ -580,8 +568,8 @@ SyscallHandler::TrackMmap(FEXCore::Core::InternalThreadState* Thread, uint64_t a if (Thread) { CachedSection.emplace(BuildSectionInfo(*Resource, addr, Size)); } else { - // Delay loading this entry until FEX is fully initialized - StartupBinaryLoads.push_back(BuildSectionInfo(*Resource, addr, Size)); + // Cache can't be loaded with a thread; skip this for now + LogMan::Msg::DFmt("Oops, tried caching without a thread: {}", Resource->MappedFile->Filename); } } diff --git a/Source/Tools/LinuxEmulation/VDSO_Emulation.cpp b/Source/Tools/LinuxEmulation/VDSO_Emulation.cpp index 3823d57a6..0e67c66be 100644 --- a/Source/Tools/LinuxEmulation/VDSO_Emulation.cpp +++ b/Source/Tools/LinuxEmulation/VDSO_Emulation.cpp @@ -669,7 +669,7 @@ void LoadGuestVDSOSymbols(char* VDSOBase) { } } -void LoadFEXGeneratedCode(bool Is64Bit, VDSOMapping* Mapping, FEX::HLE::SyscallHandler* const Handler) { +void LoadFEXGeneratedCode(FEXCore::Core::InternalThreadState* Thread, bool Is64Bit, VDSOMapping* Mapping, FEX::HLE::SyscallHandler* const Handler) { if (VDSOPointers.VDSO_FEX_CallbackRET && (!Is64Bit || (VDSOPointers.VDSO_kernel_sigreturn && VDSOPointers.VDSO_kernel_rt_sigreturn))) { // Unnecessary if all VDSO paths have already been loaded. return; @@ -682,8 +682,10 @@ void LoadFEXGeneratedCode(bool Is64Bit, VDSOMapping* Mapping, FEX::HLE::SyscallH if (Is64Bit) { // 64bit mode can have its code anywhere - auto Result = FEXCore::Allocator::VirtualAlloc(Mapping->X86GeneratedCodeSize); - if (Result != MAP_FAILED) { + auto Result = + Handler->GuestMmap(Is64Bit, Thread, nullptr, Mapping->X86GeneratedCodeSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + if (!FEX::HLE::HasSyscallError(Result)) { Mapping->X86GeneratedCodePtr = Result; } } else { @@ -693,18 +695,18 @@ void LoadFEXGeneratedCode(bool Is64Bit, VDSOMapping* Mapping, FEX::HLE::SyscallH // We need to have the sigret handler in the lower 32bits of memory space // Scan top down and try to allocate a location for (size_t Location = 0xFFFF'E000; Location != 0x0; Location -= PageSize) { - void* Ptr = - ::mmap(reinterpret_cast(Location), PageSize, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + auto Ptr = Handler->GuestMmap(Is64Bit, Thread, reinterpret_cast(Location), PageSize, PROT_READ | PROT_WRITE, + MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (Ptr != MAP_FAILED && reinterpret_cast(Ptr) >= LOCATION_MAX) { + if (!FEX::HLE::HasSyscallError(Ptr) && reinterpret_cast(Ptr) >= LOCATION_MAX) { // Failed to map in the lower 32bits // Try again // Can happen in the case that host kernel ignores MAP_FIXED_NOREPLACE - ::munmap(Ptr, PageSize); + Handler->GuestMunmap(Thread, Ptr, PageSize); continue; } - if (Ptr != MAP_FAILED) { + if (!FEX::HLE::HasSyscallError(Ptr)) { Mapping->X86GeneratedCodePtr = Ptr; break; } @@ -765,29 +767,20 @@ void LoadFEXGeneratedCode(bool Is64Bit, VDSOMapping* Mapping, FEX::HLE::SyscallH CurrentCodeOffset += CallbackRetCode.size(); } - mprotect(Mapping->X86GeneratedCodePtr, Mapping->X86GeneratedCodeSize, PROT_READ | PROT_EXEC); - { - auto lk = FEXCore::GuardSignalDeferringSectionWithFallback(Handler->VMATracking.Mutex, nullptr); - std::optional IgnoredSection; - FEX::HLE::_SyscallHandler->TrackMmap(nullptr, reinterpret_cast(Mapping->X86GeneratedCodePtr), Mapping->X86GeneratedCodeSize, - PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0, IgnoredSection); - } - - FEX::HLE::_SyscallHandler->InvalidateCodeRangeIfNecessary(nullptr, reinterpret_cast(Mapping->X86GeneratedCodePtr), - Mapping->X86GeneratedCodeSize); + Handler->GuestMprotect(Thread, Mapping->X86GeneratedCodePtr, Mapping->X86GeneratedCodeSize, PROT_READ | PROT_EXEC); } -void UnloadVDSOMapping(const VDSOMapping& Mapping) { +void UnloadVDSOMapping(FEXCore::Core::InternalThreadState* Thread, FEX::HLE::SyscallHandler* const Handler, const VDSOMapping& Mapping) { if (Mapping.VDSOBase) { - munmap(Mapping.VDSOBase, Mapping.VDSOSize); + Handler->GuestMunmap(Thread, Mapping.VDSOBase, Mapping.VDSOSize); } if (Mapping.X86GeneratedCodePtr) { - munmap(Mapping.X86GeneratedCodePtr, Mapping.X86GeneratedCodeSize); + Handler->GuestMunmap(Thread, Mapping.X86GeneratedCodePtr, Mapping.X86GeneratedCodeSize); } } -VDSOMapping LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler) { +VDSOMapping LoadVDSOThunks(FEXCore::Core::InternalThreadState* Thread, bool Is64Bit, FEX::HLE::SyscallHandler* const Handler) { VDSOMapping Mapping {}; FEX_CONFIG_OPT(ThunkGuestLibs, THUNKGUESTLIBS); fextl::string ThunkGuestPath = ThunkGuestLibs(); @@ -808,7 +801,7 @@ VDSOMapping LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler Mapping.VDSOSize = FEXCore::AlignUp(Mapping.VDSOSize, FEXCore::Utils::FEX_PAGE_SIZE); // Map the VDSO file to memory - Mapping.VDSOBase = Handler->GuestMmap(nullptr, nullptr, Mapping.VDSOSize, PROT_READ | PROT_EXEC, MAP_SHARED, VDSOFD, 0); + Mapping.VDSOBase = Handler->GuestMmap(Thread, nullptr, Mapping.VDSOSize, PROT_READ | PROT_EXEC, MAP_SHARED, VDSOFD, 0); // Since we found our VDSO thunk library, find our host VDSO function implementations. LoadHostVDSO(); @@ -822,7 +815,7 @@ VDSOMapping LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler } // If VDSO couldn't find sigreturn then FEX needs to provide unique implementations. - LoadFEXGeneratedCode(Is64Bit, &Mapping, Handler); + LoadFEXGeneratedCode(Thread, Is64Bit, &Mapping, Handler); if (Is64Bit) { // Set the Thunk definition pointers for x86-64 diff --git a/Source/Tools/LinuxEmulation/VDSO_Emulation.h b/Source/Tools/LinuxEmulation/VDSO_Emulation.h index 771e29908..f05ba69bc 100644 --- a/Source/Tools/LinuxEmulation/VDSO_Emulation.h +++ b/Source/Tools/LinuxEmulation/VDSO_Emulation.h @@ -7,6 +7,10 @@ #include #include +namespace FEXCore::Core { +struct InternalThreadState; +} + namespace FEX::HLE { class SyscallHandler; } @@ -24,8 +28,8 @@ struct VDSOEntrypoints { void* VDSO_kernel_rt_sigreturn; void* VDSO_FEX_CallbackRET; }; -VDSOMapping LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler); -void UnloadVDSOMapping(const VDSOMapping& Mapping); +VDSOMapping LoadVDSOThunks(FEXCore::Core::InternalThreadState* Thread, bool Is64Bit, FEX::HLE::SyscallHandler* const Handler); +void UnloadVDSOMapping(FEXCore::Core::InternalThreadState* Thread, FEX::HLE::SyscallHandler* const Handler, const VDSOMapping& Mapping); uint64_t GetVSyscallEntry(const void* VDSOBase);