Merge pull request #4783 from Sonicadvance1/save_restore_segments

LinuxSyscalls: Save and restore segment registers on signal
This commit is contained in:
LC authored and GitHub committed 2025-08-14 15:34:10 -04:00
commit 9072571fc1
2 files changed
+25 -1

No files matched your search

@@ -382,6 +382,15 @@ bool SignalDelegator::HandleDispatcherGuestSignal(FEXCore::Core::InternalThreadS
Frame->State.flags[FEXCore::X86State::RFLAG_RF_LOC] = 0;
Frame->State.flags[FEXCore::X86State::RFLAG_TF_RAW_LOC] = 0;
// Linux resets the CS and SS registers on signal handler.
// This way signal handlers always go back to their original operating mode.
// Doesn't matter for 32-bit processes as they can only be 32-bit, but does
// matter for 64-bit processes as they could have potentially installed a 32-bit code segment.
Frame->State.cs_idx = FEXCore::Core::CPUState::DEFAULT_USER_CS << 3;
Frame->State.ss_idx = 0;
Frame->State.cs_cached = Frame->State.CalculateGDTBase(*Frame->State.GetSegmentFromIndex(Frame->State, Frame->State.cs_idx));
Frame->State.ss_cached = Frame->State.CalculateGDTBase(*Frame->State.GetSegmentFromIndex(Frame->State, Frame->State.ss_idx));
// The guest starts its signal frame with a zero initialized FPU
// Set that up now. Little bit costly but it's a requirement
// This state will be restored on rt_sigreturn
@@ -127,6 +127,15 @@ void SignalDelegator::RestoreFrame_x64(FEXCore::Core::InternalThreadState* Threa
ArchHelpers::Context::SetState(ucontext, reinterpret_cast<uint64_t>(Frame));
Frame->State.rip = guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_RIP];
// Restore segments.
// FS and GS are explicitly ignored here, as WRFSGSbase is used instead.
Frame->State.cs_idx = (guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_CSGSFS] >> 0) & 0xffff;
Frame->State.ss_idx = (guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_CSGSFS] >> 48) & 0xffff;
Frame->State.cs_cached = Frame->State.CalculateGDTBase(*Frame->State.GetSegmentFromIndex(Frame->State, Frame->State.cs_idx));
Frame->State.ss_cached = Frame->State.CalculateGDTBase(*Frame->State.GetSegmentFromIndex(Frame->State, Frame->State.ss_idx));
// XXX: Full context setting
CTX->SetFlagsFromCompactedEFLAGS(Thread, guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_EFL]);
@@ -377,7 +386,13 @@ uint64_t SignalDelegator::SetupFrame_x64(FEXCore::Core::InternalThreadState* Thr
guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_RIP] = ContextBackup->OriginalRIP;
guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_EFL] = eflags;
guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_CSGSFS] = 0;
// This stores the CS/GS/FS selectors. It ALSO stores the SS selector in the top 16 bits...For some reason.
// Despite the naming, the endianness is swapped from what you'd expect.
guest_uctx->uc_mcontext.gregs[FEXCore::x86_64::FEX_REG_CSGSFS] =
((uint64_t)Frame->State.ss_idx << 48) |
((uint64_t)Frame->State.fs_idx << 32) |
((uint64_t)Frame->State.gs_idx << 16) |
((uint64_t)Frame->State.cs_idx << 0);
// aarch64 and x86_64 siginfo_t matches. We can just copy this over
// SI_USER could also potentially have random data in it, needs to be bit perfect