mirror of
https://github.com/FEX-Emu/FEX.git
synced 2025-02-08 23:57:05 +00:00
Resolve most VDSO comments
This commit is contained in:
parent
0869b0aa29
commit
c5a7fc1e2a
@ -202,6 +202,10 @@ namespace FEXCore::Context {
|
||||
return CTX->AddCustomIREntrypoint(Entrypoint, Handler, Creator, Data);
|
||||
}
|
||||
|
||||
void AppendThunkDefinitions(FEXCore::Context::Context *CTX, std::vector<FEXCore::IR::ThunkDefinition> const& Definitions) {
|
||||
CTX->AppendThunkDefinitions(Definitions);
|
||||
}
|
||||
|
||||
namespace Debug {
|
||||
void CompileRIP(FEXCore::Context::Context *CTX, uint64_t RIP) {
|
||||
CTX->CompileRIP(CTX->ParentThread, RIP);
|
||||
|
@ -322,6 +322,8 @@ namespace FEXCore::Context {
|
||||
IRCaptureCache.SetAOTIRRenamer(CacheRenamer);
|
||||
}
|
||||
|
||||
void AppendThunkDefinitions(std::vector<FEXCore::IR::ThunkDefinition> const& Definitions);
|
||||
|
||||
FEXCore::Utils::PooledAllocatorMMap OpDispatcherAllocator;
|
||||
FEXCore::Utils::PooledAllocatorMMap FrontendAllocator;
|
||||
|
||||
|
@ -1332,6 +1332,11 @@ namespace FEXCore::Context {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Context::AppendThunkDefinitions(std::vector<FEXCore::IR::ThunkDefinition> const& Definitions) {
|
||||
ThunkHandler->AppendThunkDefinitions(Definitions);
|
||||
}
|
||||
|
||||
void ConfigureAOTGen(FEXCore::Core::InternalThreadState *Thread, std::set<uint64_t> *ExternalBranches, uint64_t SectionMaxAddress) {
|
||||
Thread->FrontendDecoder->SetExternalBranches(ExternalBranches);
|
||||
Thread->FrontendDecoder->SetSectionMaxAddress(SectionMaxAddress);
|
||||
|
@ -17,12 +17,10 @@ $end_info$
|
||||
#include <cstdint>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <elf.h>
|
||||
#include <Interface/Context/Context.h>
|
||||
#include "FEXCore/Core/X86Enums.h"
|
||||
#include <malloc.h>
|
||||
#include <mutex>
|
||||
#include <sys/auxv.h>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <shared_mutex>
|
||||
@ -69,107 +67,6 @@ extern char __start_HostToGuestTrampolineTemplate[];
|
||||
extern char __stop_HostToGuestTrampolineTemplate[];
|
||||
|
||||
namespace FEXCore {
|
||||
namespace VDSO {
|
||||
using TimeType = decltype(::time)*;
|
||||
using GetTimeOfDayType = decltype(::gettimeofday)*;
|
||||
using ClockGetTimeType = decltype(::clock_gettime)*;
|
||||
using ClockGetResType = decltype(::clock_getres)*;
|
||||
using GetCPUType = decltype(::getcpu)*;
|
||||
|
||||
TimeType TimePtr = ::time;
|
||||
GetTimeOfDayType GetTimeOfDayPtr = ::gettimeofday;
|
||||
ClockGetTimeType ClockGetTimePtr = ::clock_gettime;
|
||||
ClockGetResType ClockGetResPtr = ::clock_getres;
|
||||
GetCPUType GetCPUPtr = ::getcpu;
|
||||
|
||||
static void time(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
time_t *a_0;
|
||||
uint64_t rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = TimePtr(args->a_0);
|
||||
}
|
||||
|
||||
static void gettimeofday(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct timeval *tv;
|
||||
struct timezone *tz;
|
||||
uint64_t rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = GetTimeOfDayPtr(args->tv, args->tz);
|
||||
}
|
||||
|
||||
static void clock_gettime(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
struct timespec *tp;
|
||||
uint64_t rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = ClockGetTimePtr(args->clk_id, args->tp);
|
||||
}
|
||||
|
||||
static void clock_getres(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
struct timespec *tp;
|
||||
uint64_t rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = ClockGetResPtr(args->clk_id, args->tp);
|
||||
}
|
||||
|
||||
static void getcpu(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
uint32_t *cpu;
|
||||
uint32_t *node;
|
||||
uint64_t rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = GetCPUPtr(args->cpu, args->node);
|
||||
}
|
||||
|
||||
void LoadVDSO() {
|
||||
void *vdso = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
|
||||
if (!vdso) {
|
||||
vdso = dlopen("linux-gate.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
|
||||
}
|
||||
|
||||
if (!vdso) {
|
||||
// Couldn't load VDSO
|
||||
return;
|
||||
}
|
||||
|
||||
auto SymbolPtr = dlsym(vdso, "__vdso_time");
|
||||
if (SymbolPtr) {
|
||||
TimePtr = reinterpret_cast<TimeType>(SymbolPtr);
|
||||
}
|
||||
|
||||
SymbolPtr = dlsym(vdso, "__vdso_gettimeofday");
|
||||
if (SymbolPtr) {
|
||||
GetTimeOfDayPtr = reinterpret_cast<GetTimeOfDayType>(SymbolPtr);
|
||||
}
|
||||
|
||||
SymbolPtr = dlsym(vdso, "__vdso_clock_gettime");
|
||||
if (SymbolPtr) {
|
||||
ClockGetTimePtr = reinterpret_cast<ClockGetTimeType>(SymbolPtr);
|
||||
}
|
||||
|
||||
SymbolPtr = dlsym(vdso, "__vdso_clock_getres");
|
||||
if (SymbolPtr) {
|
||||
ClockGetResPtr = reinterpret_cast<ClockGetResType>(SymbolPtr);
|
||||
}
|
||||
|
||||
SymbolPtr = dlsym(vdso, "__vdso_getcpu");
|
||||
if (SymbolPtr) {
|
||||
GetCPUPtr = reinterpret_cast<GetCPUType>(SymbolPtr);
|
||||
}
|
||||
dlclose(vdso);
|
||||
}
|
||||
}
|
||||
|
||||
struct ExportEntry { uint8_t *sha256; ThunkedFunction* Fn; };
|
||||
|
||||
struct TrampolineInstanceInfo {
|
||||
@ -243,32 +140,6 @@ namespace FEXCore {
|
||||
{ 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
|
||||
},
|
||||
// VDSO
|
||||
{
|
||||
// sha256(libVDSO:time)
|
||||
{ 0x37, 0x63, 0x46, 0xb0, 0x79, 0x06, 0x5f, 0x9d, 0x00, 0xb6, 0x8d, 0xfd, 0x9e, 0x4a, 0x62, 0xcd, 0x1e, 0x6c, 0xcc, 0x22, 0xcd, 0xb2, 0xc0, 0x17, 0x7d, 0x42, 0x6a, 0x40, 0xd1, 0xeb, 0xfa, 0xe0 },
|
||||
&VDSO::time
|
||||
},
|
||||
{
|
||||
// sha256(libVDSO:gettimeofday)
|
||||
{ 0x77, 0x2a, 0xde, 0x1c, 0x13, 0x2d, 0xe9, 0x48, 0xaf, 0xe0, 0xba, 0xcc, 0x6a, 0x89, 0xff, 0xca, 0x4a, 0xdc, 0xd5, 0x63, 0x2c, 0xc5, 0x62, 0x8b, 0x5d, 0xde, 0x0b, 0x15, 0x35, 0xc6, 0xc7, 0x14 },
|
||||
&VDSO::gettimeofday
|
||||
},
|
||||
{
|
||||
// sha256(libVDSO:clock_gettime)
|
||||
{ 0x3c, 0x96, 0x9b, 0x2d, 0xc3, 0xad, 0x2b, 0x3b, 0x9c, 0x4e, 0x4d, 0xca, 0x1c, 0xe8, 0x18, 0x4a, 0x12, 0x8a, 0xe4, 0xc1, 0x56, 0x92, 0x73, 0xce, 0x65, 0x85, 0x5f, 0x65, 0x7e, 0x94, 0x26, 0xbe },
|
||||
&VDSO::clock_gettime
|
||||
},
|
||||
{
|
||||
// sha256(libVDSO:clock_getres)
|
||||
{ 0xe4, 0xa1, 0xf6, 0x23, 0x35, 0xae, 0xb7, 0xb6, 0xb0, 0x37, 0xc5, 0xc3, 0xa3, 0xfd, 0xbf, 0xa2, 0xa1, 0xc8, 0x95, 0x78, 0xe5, 0x76, 0x86, 0xdb, 0x3e, 0x6c, 0x54, 0xd5, 0x02, 0x60, 0xd8, 0x6d },
|
||||
&VDSO::clock_getres
|
||||
},
|
||||
{
|
||||
// sha256(libVDSO:getcpu)
|
||||
{ 0x39, 0x83, 0x39, 0x36, 0x0f, 0x68, 0xd6, 0xfc, 0xc2, 0x3a, 0x97, 0x11, 0x85, 0x09, 0xc7, 0x25, 0xbb, 0x50, 0x49, 0x55, 0x6b, 0x0c, 0x9f, 0x50, 0x37, 0xf5, 0x9d, 0xb0, 0x38, 0x58, 0x57, 0x12 },
|
||||
&VDSO::getcpu
|
||||
},
|
||||
};
|
||||
|
||||
// Can't be a string_view. We need to keep a copy of the library name in-case string_view pointer goes away.
|
||||
@ -449,7 +320,7 @@ namespace FEXCore {
|
||||
}
|
||||
}
|
||||
|
||||
ThunkedFunction* LookupThunk(const IR::SHA256Sum &sha256) {
|
||||
ThunkedFunction* LookupThunk(const IR::SHA256Sum &sha256) override {
|
||||
|
||||
std::shared_lock lk(ThunksMutex);
|
||||
|
||||
@ -462,13 +333,18 @@ namespace FEXCore {
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) {
|
||||
void RegisterTLSState(FEXCore::Core::InternalThreadState *Thread) override {
|
||||
::Thread = Thread;
|
||||
}
|
||||
|
||||
void AppendThunkDefinitions(std::vector<FEXCore::IR::ThunkDefinition> const& Definitions) override {
|
||||
for (auto & Definition : Definitions) {
|
||||
Thunks.emplace(Definition.Sum, Definition.ThunkFunction);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ThunkHandler* ThunkHandler::Create() {
|
||||
VDSO::LoadVDSO();
|
||||
return new ThunkHandler_impl();
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,10 @@ $end_info$
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace FEXCore::Context {
|
||||
struct Context;
|
||||
}
|
||||
@ -28,5 +32,7 @@ namespace FEXCore {
|
||||
virtual ~ThunkHandler() { }
|
||||
|
||||
static ThunkHandler* Create();
|
||||
|
||||
virtual void AppendThunkDefinitions(std::vector<FEXCore::IR::ThunkDefinition> const& Definitions) = 0;
|
||||
};
|
||||
};
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <FEXCore/Core/SignalDelegator.h>
|
||||
#include <FEXCore/Core/CPUID.h>
|
||||
#include <FEXCore/IR/IR.h>
|
||||
#include <FEXCore/Utils/CompilerDefs.h>
|
||||
|
||||
#include <istream>
|
||||
@ -280,4 +281,12 @@ namespace FEXCore::Context {
|
||||
|
||||
FEX_DEFAULT_VISIBILITY void ConfigureAOTGen(FEXCore::Core::InternalThreadState *Thread, std::set<uint64_t> *ExternalBranches, uint64_t SectionMaxAddress);
|
||||
FEX_DEFAULT_VISIBILITY CustomIRResult AddCustomIREntrypoint(FEXCore::Context::Context *CTX, uintptr_t Entrypoint, std::function<void(uintptr_t Entrypoint, FEXCore::IR::IREmitter *)> Handler, void *Creator = nullptr, void *Data = nullptr);
|
||||
|
||||
/**
|
||||
* @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 void AppendThunkDefinitions(FEXCore::Context::Context *CTX, std::vector<FEXCore::IR::ThunkDefinition> const& Definitions);
|
||||
}
|
||||
|
7
External/FEXCore/include/FEXCore/IR/IR.h
vendored
7
External/FEXCore/include/FEXCore/IR/IR.h
vendored
@ -413,6 +413,13 @@ struct SHA256Sum final {
|
||||
}
|
||||
};
|
||||
|
||||
typedef void ThunkedFunction(void* ArgsRv);
|
||||
|
||||
struct ThunkDefinition final {
|
||||
SHA256Sum Sum;
|
||||
ThunkedFunction *ThunkFunction;
|
||||
};
|
||||
|
||||
class NodeIterator;
|
||||
|
||||
/* This iterator can be used to step though nodes.
|
||||
|
@ -9,6 +9,7 @@ endif()
|
||||
|
||||
add_executable(FEXLoader
|
||||
FEXLoader.cpp
|
||||
VDSO_Emulation.cpp
|
||||
AOT/AOTGenerator.cpp)
|
||||
|
||||
# Enable FEX APIs to be used by targets that use target_link_libraries on FEXLoader
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <FEXCore/Core/CodeLoader.h>
|
||||
#include <FEXCore/Core/CoreState.h>
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
#include <FEXCore/Utils/MathUtils.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
#include <FEXHeaderUtils/Syscalls.h>
|
||||
|
||||
@ -46,7 +45,6 @@ class ELFCodeLoader2 final : public FEXCore::CodeLoader {
|
||||
uintptr_t Entrypoint;
|
||||
uintptr_t BrkStart;
|
||||
uintptr_t StackPointer;
|
||||
void* VDSOStart{};
|
||||
|
||||
size_t CalculateTotalElfSize(const std::vector<Elf64_Phdr> &headers)
|
||||
{
|
||||
@ -406,28 +404,6 @@ class ELFCodeLoader2 final : public FEXCore::CodeLoader {
|
||||
Entrypoint = MainElfEntrypoint;
|
||||
}
|
||||
|
||||
if (Is64BitMode()) {
|
||||
// Load VDSO if we can
|
||||
FEX_CONFIG_OPT(ThunkGuestLibs, THUNKGUESTLIBS);
|
||||
auto ThunkGuestPath = std::filesystem::path(ThunkGuestLibs()) / "libVDSO-guest.so";
|
||||
int VDSOFD = ::open(ThunkGuestPath.string().c_str(), O_RDONLY);
|
||||
|
||||
if (VDSOFD != -1) {
|
||||
// Get file size
|
||||
size_t VDSOSize = lseek(VDSOFD, 0, SEEK_END);
|
||||
|
||||
if (VDSOSize >= 4) {
|
||||
// Reset to beginning
|
||||
lseek(VDSOFD, 0, SEEK_SET);
|
||||
VDSOSize = FEXCore::AlignUp(VDSOSize, 4096);
|
||||
|
||||
// Map the VDSO file to memory
|
||||
VDSOStart = Mapper(nullptr, VDSOSize, PROT_READ, MAP_PRIVATE, VDSOFD, 0);
|
||||
}
|
||||
close(VDSOFD);
|
||||
}
|
||||
}
|
||||
|
||||
// All done
|
||||
|
||||
// Setup AuxVars
|
||||
@ -453,8 +429,8 @@ class ELFCodeLoader2 final : public FEXCore::CodeLoader {
|
||||
|
||||
// we don't support vsyscall so we don't set those
|
||||
//AuxVariables.emplace_back(auxv_t{32, 0}); // AT_SYSINFO - Entry point to syscall
|
||||
if (VDSOStart) {
|
||||
AuxVariables.emplace_back(auxv_t{33, reinterpret_cast<uint64_t>(VDSOStart)}); // AT_SYSINFO_EHDR - Address of the start of VDSO
|
||||
if (VDSOBase) {
|
||||
AuxVariables.emplace_back(auxv_t{33, reinterpret_cast<uint64_t>(VDSOBase)}); // AT_SYSINFO_EHDR - Address of the start of VDSO
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -667,6 +643,10 @@ class ELFCodeLoader2 final : public FEXCore::CodeLoader {
|
||||
return ElfValid;
|
||||
}
|
||||
|
||||
void SetVDSOBase(void* Base) {
|
||||
VDSOBase = Base;
|
||||
}
|
||||
|
||||
constexpr static uint64_t BRK_SIZE = 8 * 1024 * 1024;
|
||||
constexpr static uint64_t STACK_SIZE = 8 * 1024 * 1024;
|
||||
|
||||
@ -679,6 +659,7 @@ class ELFCodeLoader2 final : public FEXCore::CodeLoader {
|
||||
uint64_t ArgumentBackingSize{};
|
||||
uint64_t EnvironmentBackingSize{};
|
||||
uint64_t BaseOffset{};
|
||||
FEX_CONFIG_OPT(AdditionalArguments, ADDITIONALARGUMENTS);
|
||||
void* VDSOBase{};
|
||||
|
||||
FEX_CONFIG_OPT(AdditionalArguments, ADDITIONALARGUMENTS);
|
||||
};
|
||||
|
@ -9,6 +9,7 @@ $end_info$
|
||||
#include "Common/ArgumentLoader.h"
|
||||
#include "Common/FEXServerClient.h"
|
||||
#include "ELFCodeLoader2.h"
|
||||
#include "VDSO_Emulation.h"
|
||||
#include "Tests/LinuxSyscalls/LinuxAllocator.h"
|
||||
#include "Tests/LinuxSyscalls/Syscalls.h"
|
||||
#include "Tests/LinuxSyscalls/x32/Syscalls.h"
|
||||
@ -389,6 +390,12 @@ int main(int argc, char **argv, char **const envp) {
|
||||
auto Mapper = std::bind_front(&FEX::HLE::SyscallHandler::GuestMmap, SyscallHandler.get());
|
||||
auto Unmapper = std::bind_front(&FEX::HLE::SyscallHandler::GuestMunmap, SyscallHandler.get());
|
||||
|
||||
if (Loader.Is64BitMode()) {
|
||||
// Load VDSO in to memory prior to mapping our ELFs.
|
||||
void* VDSOBase = FEX::VDSO::LoadVDSOThunks(Mapper);
|
||||
Loader.SetVDSOBase(VDSOBase);
|
||||
}
|
||||
|
||||
if (!Loader.MapMemory(Mapper, Unmapper)) {
|
||||
// failed to map
|
||||
LogMan::Msg::EFmt("Failed to map %d-bit elf file.", Loader.Is64BitMode() ? 64 : 32);
|
||||
@ -405,6 +412,9 @@ int main(int argc, char **argv, char **const envp) {
|
||||
FEXCore::Context::SetSyscallHandler(CTX, SyscallHandler.get());
|
||||
FEXCore::Context::InitCore(CTX, Loader.DefaultRIP(), Loader.GetStackPointer());
|
||||
|
||||
// Pass in our VDSO thunks
|
||||
FEXCore::Context::AppendThunkDefinitions(CTX, FEX::VDSO::GetVDSOThunkDefinitions());
|
||||
|
||||
FEXCore::Context::ExitReason ShutdownReason = FEXCore::Context::ExitReason::EXIT_SHUTDOWN;
|
||||
|
||||
// There might already be an exit handler, leave it installed
|
||||
|
177
Source/Tests/VDSO_Emulation.cpp
Normal file
177
Source/Tests/VDSO_Emulation.cpp
Normal file
@ -0,0 +1,177 @@
|
||||
#include "VDSO_Emulation.h"
|
||||
#include "FEXCore/IR/IR.h"
|
||||
|
||||
#include <FEXCore/Config/Config.h>
|
||||
#include <FEXCore/Utils/MathUtils.h>
|
||||
#include <FEXCore/Utils/LogManager.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <filesystem>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FEX::VDSO {
|
||||
using TimeType = decltype(::time)*;
|
||||
using GetTimeOfDayType = decltype(::gettimeofday)*;
|
||||
using ClockGetTimeType = decltype(::clock_gettime)*;
|
||||
using ClockGetResType = decltype(::clock_getres)*;
|
||||
using GetCPUType = decltype(::getcpu)*;
|
||||
|
||||
TimeType TimePtr = ::time;
|
||||
GetTimeOfDayType GetTimeOfDayPtr = ::gettimeofday;
|
||||
ClockGetTimeType ClockGetTimePtr = ::clock_gettime;
|
||||
ClockGetResType ClockGetResPtr = ::clock_getres;
|
||||
GetCPUType GetCPUPtr = ::getcpu;
|
||||
|
||||
static void time(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
time_t *a_0;
|
||||
uint64_t rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = TimePtr(args->a_0);
|
||||
}
|
||||
|
||||
static void gettimeofday(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
struct timeval *tv;
|
||||
struct timezone *tz;
|
||||
uint64_t rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = GetTimeOfDayPtr(args->tv, args->tz);
|
||||
}
|
||||
|
||||
static void clock_gettime(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
struct timespec *tp;
|
||||
uint64_t rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = ClockGetTimePtr(args->clk_id, args->tp);
|
||||
}
|
||||
|
||||
static void clock_getres(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
clockid_t clk_id;
|
||||
struct timespec *tp;
|
||||
uint64_t rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = ClockGetResPtr(args->clk_id, args->tp);
|
||||
}
|
||||
|
||||
static void getcpu(void* ArgsRV) {
|
||||
struct ArgsRV_t {
|
||||
uint32_t *cpu;
|
||||
uint32_t *node;
|
||||
uint64_t rv;
|
||||
} *args = reinterpret_cast<ArgsRV_t*>(ArgsRV);
|
||||
|
||||
args->rv = GetCPUPtr(args->cpu, args->node);
|
||||
}
|
||||
|
||||
void LoadHostVDSO() {
|
||||
void *vdso = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
|
||||
if (!vdso) {
|
||||
vdso = dlopen("linux-gate.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
|
||||
}
|
||||
|
||||
if (!vdso) {
|
||||
// We couldn't load VDSO, fallback to C implementations. Which will still be faster than emulated libc versions.
|
||||
LogMan::Msg::IFmt("linux-vdso implementation falling back to libc. Consider enabling VDSO in your kernel.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto SymbolPtr = dlsym(vdso, "__vdso_time");
|
||||
if (SymbolPtr) {
|
||||
TimePtr = reinterpret_cast<TimeType>(SymbolPtr);
|
||||
}
|
||||
|
||||
SymbolPtr = dlsym(vdso, "__vdso_gettimeofday");
|
||||
if (SymbolPtr) {
|
||||
GetTimeOfDayPtr = reinterpret_cast<GetTimeOfDayType>(SymbolPtr);
|
||||
}
|
||||
|
||||
SymbolPtr = dlsym(vdso, "__vdso_clock_gettime");
|
||||
if (SymbolPtr) {
|
||||
ClockGetTimePtr = reinterpret_cast<ClockGetTimeType>(SymbolPtr);
|
||||
}
|
||||
|
||||
SymbolPtr = dlsym(vdso, "__vdso_clock_getres");
|
||||
if (SymbolPtr) {
|
||||
ClockGetResPtr = reinterpret_cast<ClockGetResType>(SymbolPtr);
|
||||
}
|
||||
|
||||
SymbolPtr = dlsym(vdso, "__vdso_getcpu");
|
||||
if (SymbolPtr) {
|
||||
GetCPUPtr = reinterpret_cast<GetCPUType>(SymbolPtr);
|
||||
}
|
||||
dlclose(vdso);
|
||||
}
|
||||
|
||||
static std::vector<FEXCore::IR::ThunkDefinition> VDSODefinitions = {
|
||||
{
|
||||
// sha256(libVDSO:time)
|
||||
{ 0x37, 0x63, 0x46, 0xb0, 0x79, 0x06, 0x5f, 0x9d, 0x00, 0xb6, 0x8d, 0xfd, 0x9e, 0x4a, 0x62, 0xcd, 0x1e, 0x6c, 0xcc, 0x22, 0xcd, 0xb2, 0xc0, 0x17, 0x7d, 0x42, 0x6a, 0x40, 0xd1, 0xeb, 0xfa, 0xe0 },
|
||||
&FEX::VDSO::time
|
||||
},
|
||||
{
|
||||
// sha256(libVDSO:gettimeofday)
|
||||
{ 0x77, 0x2a, 0xde, 0x1c, 0x13, 0x2d, 0xe9, 0x48, 0xaf, 0xe0, 0xba, 0xcc, 0x6a, 0x89, 0xff, 0xca, 0x4a, 0xdc, 0xd5, 0x63, 0x2c, 0xc5, 0x62, 0x8b, 0x5d, 0xde, 0x0b, 0x15, 0x35, 0xc6, 0xc7, 0x14 },
|
||||
&FEX::VDSO::gettimeofday
|
||||
},
|
||||
{
|
||||
// sha256(libVDSO:clock_gettime)
|
||||
{ 0x3c, 0x96, 0x9b, 0x2d, 0xc3, 0xad, 0x2b, 0x3b, 0x9c, 0x4e, 0x4d, 0xca, 0x1c, 0xe8, 0x18, 0x4a, 0x12, 0x8a, 0xe4, 0xc1, 0x56, 0x92, 0x73, 0xce, 0x65, 0x85, 0x5f, 0x65, 0x7e, 0x94, 0x26, 0xbe },
|
||||
&FEX::VDSO::clock_gettime
|
||||
},
|
||||
{
|
||||
// sha256(libVDSO:clock_getres)
|
||||
{ 0xe4, 0xa1, 0xf6, 0x23, 0x35, 0xae, 0xb7, 0xb6, 0xb0, 0x37, 0xc5, 0xc3, 0xa3, 0xfd, 0xbf, 0xa2, 0xa1, 0xc8, 0x95, 0x78, 0xe5, 0x76, 0x86, 0xdb, 0x3e, 0x6c, 0x54, 0xd5, 0x02, 0x60, 0xd8, 0x6d },
|
||||
&FEX::VDSO::clock_getres
|
||||
},
|
||||
{
|
||||
// sha256(libVDSO:getcpu)
|
||||
{ 0x39, 0x83, 0x39, 0x36, 0x0f, 0x68, 0xd6, 0xfc, 0xc2, 0x3a, 0x97, 0x11, 0x85, 0x09, 0xc7, 0x25, 0xbb, 0x50, 0x49, 0x55, 0x6b, 0x0c, 0x9f, 0x50, 0x37, 0xf5, 0x9d, 0xb0, 0x38, 0x58, 0x57, 0x12 },
|
||||
&FEX::VDSO::getcpu
|
||||
},
|
||||
};
|
||||
|
||||
void* LoadVDSOThunks(MapperFn Mapper) {
|
||||
void* VDSOBase{};
|
||||
FEX_CONFIG_OPT(ThunkGuestLibs, THUNKGUESTLIBS);
|
||||
|
||||
// Load VDSO if we can
|
||||
auto ThunkGuestPath = std::filesystem::path(ThunkGuestLibs()) / "libVDSO-guest.so";
|
||||
int VDSOFD = ::open(ThunkGuestPath.string().c_str(), O_RDONLY);
|
||||
|
||||
if (VDSOFD != -1) {
|
||||
// Get file size
|
||||
size_t VDSOSize = lseek(VDSOFD, 0, SEEK_END);
|
||||
|
||||
if (VDSOSize >= 4) {
|
||||
// Reset to beginning
|
||||
lseek(VDSOFD, 0, SEEK_SET);
|
||||
VDSOSize = FEXCore::AlignUp(VDSOSize, 4096);
|
||||
|
||||
// Map the VDSO file to memory
|
||||
VDSOBase = Mapper(nullptr, VDSOSize, PROT_READ, MAP_PRIVATE, VDSOFD, 0);
|
||||
|
||||
// Since we found our VDSO thunk library, find our host VDSO function implementations.
|
||||
LoadHostVDSO();
|
||||
|
||||
}
|
||||
close(VDSOFD);
|
||||
}
|
||||
|
||||
return VDSOBase;
|
||||
}
|
||||
|
||||
std::vector<FEXCore::IR::ThunkDefinition> const& GetVDSOThunkDefinitions() {
|
||||
return VDSODefinitions;
|
||||
}
|
||||
}
|
9
Source/Tests/VDSO_Emulation.h
Normal file
9
Source/Tests/VDSO_Emulation.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <FEXCore/IR/IR.h>
|
||||
|
||||
namespace FEX::VDSO {
|
||||
using MapperFn = std::function<void *(void *addr, size_t length, int prot, int flags, int fd, off_t offset)>;
|
||||
void* LoadVDSOThunks(MapperFn Mapper);
|
||||
|
||||
std::vector<FEXCore::IR::ThunkDefinition> const& GetVDSOThunkDefinitions();
|
||||
}
|
@ -56,7 +56,7 @@ function(generate NAME SOURCE_FILE)
|
||||
set(GEN_${NAME} ${OUTPUTS} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(add_guest_lib NAME)
|
||||
function(add_guest_lib NAME SONAME)
|
||||
set (SOURCE_FILE ../lib${NAME}/lib${NAME}_Guest.cpp)
|
||||
get_filename_component(SOURCE_FILE_ABS "${SOURCE_FILE}" ABSOLUTE)
|
||||
|
||||
@ -79,10 +79,28 @@ function(add_guest_lib NAME)
|
||||
## Make signed overflow well defined 2's complement overflow
|
||||
target_compile_options(${NAME}-guest PRIVATE -fwrapv)
|
||||
|
||||
# Add linker script if set
|
||||
if (EXISTS "${SOURCE_LDS_FILE_ABS}")
|
||||
target_link_options(VDSO-guest PRIVATE "-T" "${CMAKE_CURRENT_SOURCE_DIR}/../lib${NAME}/lib${NAME}_Guest.lds")
|
||||
target_link_options(${NAME}-guest PRIVATE "-T" "${CMAKE_CURRENT_SOURCE_DIR}/../lib${NAME}/lib${NAME}_Guest.lds")
|
||||
endif()
|
||||
|
||||
# We need to override the soname for the linker.
|
||||
# Our guest thunk libraries are named `lib<Thunk>-guest`.
|
||||
# Once we override the loaded name, the guest is free to dlopen again by SONAME rather than filepath.
|
||||
# eg:
|
||||
# dlopen("libGL.so.1", RTLD_GLOBAL | RTLD_NOW); -> We override this `libGL.so.1` to `libGL-guest.so`
|
||||
# Later on in the program, it can do:
|
||||
# dlopen("libGL.so.1", RTLD_GLOBAL | RTLD_NOLOAD);
|
||||
# This second dlopen will only check to see if the previous load has made the library resident
|
||||
# Searching for SONAME in the process.
|
||||
#
|
||||
# Additionally, VDSO can only be opened by SONAME.
|
||||
# This means it will only ever open the handle with `dlopen("linux-vdso.so.1", RTLD_GLOBAL | RTLD_NOLOAD);
|
||||
# Note that this doesn't have a lib prefix, and also since it doesn't exist on the filesystem, it can never
|
||||
# Actually load from a path.
|
||||
target_link_options(${NAME}-guest PRIVATE "LINKER:-soname,${SONAME}")
|
||||
set_target_properties(${NAME}-guest PROPERTIES NO_SONAME ON)
|
||||
|
||||
if (GENERATE_GUEST_INSTALL_TARGETS)
|
||||
install(TARGETS ${NAME}-guest DESTINATION ${DATA_DIRECTORY}/GuestThunks/)
|
||||
endif()
|
||||
@ -95,13 +113,13 @@ endfunction()
|
||||
#add_guest_lib(fex_malloc)
|
||||
|
||||
generate(libasound ${CMAKE_CURRENT_SOURCE_DIR}/../libasound/libasound_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(asound)
|
||||
add_guest_lib(asound "libasound.so.2")
|
||||
|
||||
generate(libEGL ${CMAKE_CURRENT_SOURCE_DIR}/../libEGL/libEGL_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(EGL)
|
||||
add_guest_lib(EGL "libEGL.so.1")
|
||||
|
||||
generate(libGL ${CMAKE_CURRENT_SOURCE_DIR}/../libGL/libGL_interface.cpp thunks function_packs function_packs_public symbol_list)
|
||||
add_guest_lib(GL)
|
||||
add_guest_lib(GL "libGL.so.1")
|
||||
|
||||
# libGL must pull in libX11.so, so generate a placeholder libX11.so to link against
|
||||
add_library(X11 SHARED ../libX11/libX11_NativeGuest.cpp)
|
||||
@ -124,71 +142,68 @@ set(X11_VERSION_MINOR ${CMAKE_MATCH_2})
|
||||
set(X11_VERSION_PATCH ${CMAKE_MATCH_3})
|
||||
|
||||
generate(libX11 ${CMAKE_CURRENT_SOURCE_DIR}/../libX11/libX11_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(X11)
|
||||
add_guest_lib(X11 "libX11.so.6")
|
||||
|
||||
target_compile_definitions(libX11-guest-deps INTERFACE -DX11_VERSION_MAJOR=${X11_VERSION_MAJOR})
|
||||
target_compile_definitions(libX11-guest-deps INTERFACE -DX11_VERSION_MINOR=${X11_VERSION_MINOR})
|
||||
target_compile_definitions(libX11-guest-deps INTERFACE -DX11_VERSION_PATCH=${X11_VERSION_PATCH})
|
||||
|
||||
generate(libXext ${CMAKE_CURRENT_SOURCE_DIR}/../libXext/libXext_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(Xext)
|
||||
add_guest_lib(Xext "libXext.so.6")
|
||||
|
||||
target_compile_definitions(libXext-guest-deps INTERFACE -DX11_VERSION_MAJOR=${X11_VERSION_MAJOR})
|
||||
target_compile_definitions(libXext-guest-deps INTERFACE -DX11_VERSION_MINOR=${X11_VERSION_MINOR})
|
||||
target_compile_definitions(libXext-guest-deps INTERFACE -DX11_VERSION_PATCH=${X11_VERSION_PATCH})
|
||||
|
||||
generate(libXrender ${CMAKE_CURRENT_SOURCE_DIR}/../libXrender/libXrender_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(Xrender)
|
||||
add_guest_lib(Xrender "libXrender.so.1")
|
||||
|
||||
generate(libXfixes ${CMAKE_CURRENT_SOURCE_DIR}/../libXfixes/libXfixes_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(Xfixes)
|
||||
add_guest_lib(Xfixes "libXfixes.so.3")
|
||||
|
||||
generate(libvulkan ${CMAKE_CURRENT_SOURCE_DIR}/../libvulkan/libvulkan_interface.cpp thunks function_packs function_packs_public symbol_list)
|
||||
target_include_directories(libvulkan-guest-deps INTERFACE ${FEX_PROJECT_SOURCE_DIR}/External/Vulkan-Headers/include/)
|
||||
add_guest_lib(vulkan)
|
||||
add_guest_lib(vulkan "libvulkan.so.1")
|
||||
|
||||
generate(libxcb ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb/libxcb_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(xcb)
|
||||
add_guest_lib(xcb "libxcb.so.1")
|
||||
|
||||
generate(libxcb-dri2 ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-dri2/libxcb-dri2_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(xcb-dri2)
|
||||
add_guest_lib(xcb-dri2 "libxcb-dri2.so.0")
|
||||
|
||||
generate(libxcb-dri3 ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-dri3/libxcb-dri3_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(xcb-dri3)
|
||||
add_guest_lib(xcb-dri3 "libxcb-dri3.so.0")
|
||||
|
||||
generate(libxcb-xfixes ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-xfixes/libxcb-xfixes_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(xcb-xfixes)
|
||||
add_guest_lib(xcb-xfixes "libxcb-xfixes.so.0")
|
||||
|
||||
generate(libxcb-shm ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-shm/libxcb-shm_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(xcb-shm)
|
||||
add_guest_lib(xcb-shm "libxcb-shm.so.0")
|
||||
|
||||
generate(libxcb-sync ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-sync/libxcb-sync_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(xcb-sync)
|
||||
add_guest_lib(xcb-sync "libxcb-sync.so.1")
|
||||
|
||||
generate(libxcb-present ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-present/libxcb-present_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(xcb-present)
|
||||
add_guest_lib(xcb-present "libxcb-present.so.0")
|
||||
|
||||
generate(libxcb-randr ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-randr/libxcb-randr_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(xcb-randr)
|
||||
add_guest_lib(xcb-randr "libxcb-randr.so.0")
|
||||
|
||||
generate(libxcb-glx ${CMAKE_CURRENT_SOURCE_DIR}/../libxcb-glx/libxcb-glx_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(xcb-glx)
|
||||
add_guest_lib(xcb-glx "libxcb-glx.so.0")
|
||||
|
||||
generate(libxshmfence ${CMAKE_CURRENT_SOURCE_DIR}/../libxshmfence/libxshmfence_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(xshmfence)
|
||||
add_guest_lib(xshmfence "libxshmfence.so.1")
|
||||
|
||||
generate(libdrm ${CMAKE_CURRENT_SOURCE_DIR}/../libdrm/libdrm_interface.cpp thunks function_packs function_packs_public)
|
||||
target_include_directories(libdrm-guest-deps INTERFACE /usr/include/drm/)
|
||||
target_include_directories(libdrm-guest-deps INTERFACE /usr/include/libdrm/)
|
||||
add_guest_lib(drm)
|
||||
add_guest_lib(drm "libdrm.so.2")
|
||||
|
||||
generate(libVDSO ${CMAKE_CURRENT_SOURCE_DIR}/../libVDSO/libVDSO_interface.cpp thunks function_packs function_packs_public)
|
||||
add_guest_lib(VDSO)
|
||||
add_guest_lib(VDSO "linux-vdso.so.1")
|
||||
# Can't use a stack protector because otherwise cross-compiling fails
|
||||
# Not necessary anyway because it only trampolines
|
||||
target_compile_options(VDSO-guest PRIVATE "-fno-stack-protector")
|
||||
target_link_options(VDSO-guest PRIVATE "-T" "${CMAKE_CURRENT_SOURCE_DIR}/../libVDSO/libVDSO_Guest.lds" "-nostdlib" "-Wl,-soname,linux-vdso.so.1"
|
||||
"-Wl,--no-undefined" "-Wl,-z,max-page-size=4096" "-Wl,--hash-style=both")
|
||||
|
||||
# Need to override SONAME in linker options
|
||||
set_target_properties(VDSO-guest PROPERTIES NO_SONAME ON)
|
||||
target_link_options(VDSO-guest PRIVATE "-T" "${CMAKE_CURRENT_SOURCE_DIR}/../libVDSO/libVDSO_Guest.lds" "-nostdlib"
|
||||
"LINKER:--no-undefined" "LINKER:-z,max-page-size=4096" "LINKER:--hash-style=both")
|
||||
|
Loading…
x
Reference in New Issue
Block a user