Skip to content

Commit

Permalink
Merge pull request #4022 from Sonicadvance1/move_sigreturn_to_frontend
Browse files Browse the repository at this point in the history
FEX: Moves sigreturn symbols to frontend
  • Loading branch information
alyssarosenzweig authored Sep 2, 2024
2 parents b4a67a6 + c748dbf commit 4baeffe
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 53 deletions.
10 changes: 0 additions & 10 deletions FEXCore/Source/Interface/Context/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,16 +328,6 @@ class ContextImpl final : public FEXCore::Context::Context {

FEXCore::JITSymbols Symbols;

void GetVDSOSigReturn(VDSOSigReturn* VDSOPointers) override {
if (VDSOPointers->VDSO_kernel_sigreturn == nullptr) {
VDSOPointers->VDSO_kernel_sigreturn = reinterpret_cast<void*>(X86CodeGen.sigreturn_32);
}

if (VDSOPointers->VDSO_kernel_rt_sigreturn == nullptr) {
VDSOPointers->VDSO_kernel_rt_sigreturn = reinterpret_cast<void*>(X86CodeGen.rt_sigreturn_32);
}
}

FEXCore::Utils::PooledAllocatorVirtual OpDispatcherAllocator;
FEXCore::Utils::PooledAllocatorVirtual FrontendAllocator;

Expand Down
23 changes: 0 additions & 23 deletions FEXCore/Source/Interface/Core/X86HelperGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,32 +31,9 @@ X86GeneratedCode::X86GeneratedCode() {
0x0F, 0x37, // CALLBACKRET FEX Instruction
};

// Signal return handlers need to be bit-exact to what the Linux kernel provides in VDSO.
// GDB and unwinding libraries key off of these instructions to understand if the stack frame is a signal frame or not.
// This two code sections match exactly what libSegFault expects.
//
// Typically this handlers are provided by the 32-bit VDSO thunk library, but that isn't available in all cases.
// Falling back to this generated code segment still allows a backtrace to work, just might not show
// the symbol as VDSO since there is no ELF to parse.
constexpr std::array<uint8_t, 9> sigreturn_32_code = {
0x58, // pop eax
0xb8, 0x77, 0x00, 0x00, 0x00, // mov eax, 0x77
0xcd, 0x80, // int 0x80
0x90, // nop
};

constexpr std::array<uint8_t, 7> rt_sigreturn_32_code = {
0xb8, 0xad, 0x00, 0x00, 0x00, // mov eax, 0xad
0xcd, 0x80, // int 0x80
};

CallbackReturn = reinterpret_cast<uint64_t>(CodePtr);
sigreturn_32 = CallbackReturn + SignalReturnCode.size();
rt_sigreturn_32 = sigreturn_32 + sigreturn_32_code.size();

memcpy(reinterpret_cast<void*>(CallbackReturn), &SignalReturnCode.at(0), SignalReturnCode.size());
memcpy(reinterpret_cast<void*>(sigreturn_32), &sigreturn_32_code.at(0), sigreturn_32_code.size());
memcpy(reinterpret_cast<void*>(rt_sigreturn_32), &rt_sigreturn_32_code.at(0), rt_sigreturn_32_code.size());

mprotect(CodePtr, CODE_SIZE, PROT_READ);
#endif
Expand Down
2 changes: 0 additions & 2 deletions FEXCore/Source/Interface/Core/X86HelperGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ class X86GeneratedCode final {
~X86GeneratedCode();

uint64_t CallbackReturn {};
uint64_t sigreturn_32 {};
uint64_t rt_sigreturn_32 {};

private:
void* CodePtr {};
Expand Down
2 changes: 0 additions & 2 deletions FEXCore/include/FEXCore/Core/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,6 @@ class Context {
*/
FEX_DEFAULT_VISIBILITY virtual void AppendThunkDefinitions(std::span<const FEXCore::IR::ThunkDefinition> Definitions) = 0;

FEX_DEFAULT_VISIBILITY virtual void GetVDSOSigReturn(VDSOSigReturn* VDSOPointers) = 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.
Expand Down
9 changes: 6 additions & 3 deletions Source/Tools/FEXLoader/FEXLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,9 @@ int main(int argc, char** argv, char** const envp) {
auto SyscallHandler = Loader.Is64BitMode() ? FEX::HLE::x64::CreateHandler(CTX.get(), SignalDelegation.get()) :
FEX::HLE::x32::CreateHandler(CTX.get(), SignalDelegation.get(), std::move(Allocator));

// Load VDSO in to memory prior to mapping our ELFs.
auto VDSOMapping = FEX::VDSO::LoadVDSOThunks(Loader.Is64BitMode(), SyscallHandler.get());

// Now that we have the syscall handler. Track some FDs that are FEX owned.
if (OutputFD != -1) {
SyscallHandler->FM.TrackFEXFD(OutputFD);
Expand All @@ -477,9 +480,7 @@ int main(int argc, char** argv, char** const envp) {
}

{
// Load VDSO in to memory prior to mapping our ELFs.
void* VDSOBase = FEX::VDSO::LoadVDSOThunks(Loader.Is64BitMode(), SyscallHandler.get());
Loader.SetVDSOBase(VDSOBase);
Loader.SetVDSOBase(VDSOMapping.VDSOBase);
Loader.CalculateHWCaps(CTX.get());

if (!Loader.MapMemory(SyscallHandler.get())) {
Expand Down Expand Up @@ -591,6 +592,8 @@ int main(int argc, char** argv, char** const envp) {
SignalDelegation->UninstallTLSState(ParentThread);
SyscallHandler->TM.DestroyThread(ParentThread);

FEX::VDSO::UnloadVDSOMapping(VDSOMapping);

DebugServer.reset();
SyscallHandler.reset();
SignalDelegation.reset();
Expand Down
4 changes: 0 additions & 4 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,6 @@ class SignalDelegator final : public FEXCore::SignalDelegator, public FEXCore::A
void SetVDSOSigReturn() {
// Get symbols from VDSO.
VDSOPointers = FEX::VDSO::GetVDSOSymbols();

// Update VDSO to generated code.
// TODO: Have the frontend generate the x86 sigreturn pointers.
CTX->GetVDSOSigReturn(&VDSOPointers);
}

[[noreturn]]
Expand Down
94 changes: 86 additions & 8 deletions Source/Tools/LinuxEmulation/VDSO_Emulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,8 +527,81 @@ void LoadGuestVDSOSymbols(bool Is64Bit, char* VDSOBase) {
}
}

void* LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler) {
void* VDSOBase {};
void LoadUnique32BitSigreturn(VDSOMapping* Mapping) {
// Hardcoded to one page for now
const auto PageSize = sysconf(_SC_PAGESIZE);
Mapping->OptionalMappingSize = PageSize;

// First 64bit page
constexpr uintptr_t LOCATION_MAX = 0x1'0000'0000;

// 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<void*>(Location), PageSize, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

if (Ptr != MAP_FAILED && reinterpret_cast<uintptr_t>(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);
continue;
}

if (Ptr != MAP_FAILED) {
Mapping->OptionalSigReturnMapping = Ptr;
break;
}
}

// Can't do anything about this
// Here's hoping the application doesn't use signals
if (!Mapping->OptionalSigReturnMapping) {
return;
}

// Signal return handlers need to be bit-exact to what the Linux kernel provides in VDSO.
// GDB and unwinding libraries key off of these instructions to understand if the stack frame is a signal frame or not.
// This two code sections match exactly what libSegFault expects.
//
// Typically this handlers are provided by the 32-bit VDSO thunk library, but that isn't available in all cases.
// Falling back to this generated code segment still allows a backtrace to work, just might not show
// the symbol as VDSO since there is no ELF to parse.
constexpr std::array<uint8_t, 9> sigreturn_32_code = {
0x58, // pop eax
0xb8, 0x77, 0x00, 0x00, 0x00, // mov eax, 0x77
0xcd, 0x80, // int 0x80
0x90, // nop
};

constexpr std::array<uint8_t, 7> rt_sigreturn_32_code = {
0xb8, 0xad, 0x00, 0x00, 0x00, // mov eax, 0xad
0xcd, 0x80, // int 0x80
};

VDSOPointers.VDSO_kernel_sigreturn = Mapping->OptionalSigReturnMapping;
VDSOPointers.VDSO_kernel_rt_sigreturn =
reinterpret_cast<void*>(reinterpret_cast<uint64_t>(Mapping->OptionalSigReturnMapping) + sigreturn_32_code.size());

memcpy(reinterpret_cast<void*>(VDSOPointers.VDSO_kernel_sigreturn), &sigreturn_32_code.at(0), sigreturn_32_code.size());
memcpy(reinterpret_cast<void*>(VDSOPointers.VDSO_kernel_rt_sigreturn), &rt_sigreturn_32_code.at(0), rt_sigreturn_32_code.size());

mprotect(Mapping->OptionalSigReturnMapping, Mapping->OptionalMappingSize, PROT_READ);
}

void UnloadVDSOMapping(const VDSOMapping& Mapping) {
if (Mapping.VDSOBase) {
munmap(Mapping.VDSOBase, Mapping.VDSOSize);
}

if (Mapping.OptionalSigReturnMapping) {
munmap(Mapping.OptionalSigReturnMapping, Mapping.OptionalMappingSize);
}
}

VDSOMapping LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler) {
VDSOMapping Mapping {};
FEX_CONFIG_OPT(ThunkGuestLibs, THUNKGUESTLIBS);
FEX_CONFIG_OPT(ThunkGuestLibs32, THUNKGUESTLIBS32);

Expand Down Expand Up @@ -560,24 +633,29 @@ void* LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler) {

if (VDSOFD != -1) {
// Get file size
size_t VDSOSize = lseek(VDSOFD, 0, SEEK_END);
Mapping.VDSOSize = lseek(VDSOFD, 0, SEEK_END);

if (VDSOSize >= 4) {
if (Mapping.VDSOSize >= 4) {
// Reset to beginning
lseek(VDSOFD, 0, SEEK_SET);
VDSOSize = FEXCore::AlignUp(VDSOSize, 4096);
Mapping.VDSOSize = FEXCore::AlignUp(Mapping.VDSOSize, 4096);

// Map the VDSO file to memory
VDSOBase = Handler->GuestMmap(nullptr, nullptr, VDSOSize, PROT_READ, MAP_PRIVATE, VDSOFD, 0);
Mapping.VDSOBase = Handler->GuestMmap(nullptr, nullptr, Mapping.VDSOSize, PROT_READ, MAP_PRIVATE, VDSOFD, 0);

// Since we found our VDSO thunk library, find our host VDSO function implementations.
LoadHostVDSO();
}
close(VDSOFD);
LoadGuestVDSOSymbols(Is64Bit, reinterpret_cast<char*>(VDSOBase));
LoadGuestVDSOSymbols(Is64Bit, reinterpret_cast<char*>(Mapping.VDSOBase));
}

if (!Is64Bit && (!VDSOPointers.VDSO_kernel_sigreturn || !VDSOPointers.VDSO_kernel_rt_sigreturn)) {
// If VDSO couldn't find sigreturn then FEX needs to provide unique implementations.
LoadUnique32BitSigreturn(&Mapping);
}

return VDSOBase;
return Mapping;
}

uint64_t GetVSyscallEntry(const void* VDSOBase) {
Expand Down
9 changes: 8 additions & 1 deletion Source/Tools/LinuxEmulation/VDSO_Emulation.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,14 @@ struct VDSOSigReturn;

namespace FEX::VDSO {
using MapperFn = std::function<void*(void* addr, size_t length, int prot, int flags, int fd, off_t offset)>;
void* LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler);
struct VDSOMapping {
void* VDSOBase {};
size_t VDSOSize {};
void* OptionalSigReturnMapping {};
size_t OptionalMappingSize {};
};
VDSOMapping LoadVDSOThunks(bool Is64Bit, FEX::HLE::SyscallHandler* const Handler);
void UnloadVDSOMapping(const VDSOMapping& Mapping);

uint64_t GetVSyscallEntry(const void* VDSOBase);

Expand Down

0 comments on commit 4baeffe

Please sign in to comment.