mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
GS: write JIT code through RW alias on iOS dual-map
The GS software renderer's ARM64 code generators (DrawScanline and SetupPrim) handed the raw RX pointer to their vixl MacroAssembler. On iOS 26+ devices using the LuckTXM JIT mode, executable memory is dual-mapped: a read-execute alias for the CPU and a separate read-write alias for the emitter, offset by g_code_rw_offset. Writing to the RX page faults instantly (KERN_PROTECTION_FAILURE) -- the GS-thread SIGBUS crash seen on iPhone 16 / iOS 27 beta. The EE and VU recompilers already handle this via armGetWritableCodePtr (pcsx2/arm64/AsmHelpers.cpp). Mirror that pattern in the GS path: a file-local gsGetWritableCodePtr() helper adds the offset on real iOS devices and is an identity no-op everywhere else (macOS, iOS Simulator, Android, Legacy-iOS). The original RX pointer is kept as m_code_rx so GetCode() still returns the executable entry point the rasterizer calls into -- vixl's GetStartAddress echoes the constructor argument, so without this override GetCode() would return the non-executable RW pointer. Cross-platform safety: the guard (#if __APPLE__ && TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) is byte-identical to the already-shipped EE/VU helper. On every non-iOS path the helper returns the pointer unchanged, and g_code_rw_offset is 0, so behaviour is identical to before. The x86 GS path (.all.cpp, selected by CMakeLists.txt:480-490 under ARCH_X86) shares no code with these arm64 files and is not compiled on any arm64 target.
This commit is contained in:
@@ -11,6 +11,18 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// On iOS dual-map JIT, write through the RW alias (rx + g_code_rw_offset).
|
||||
// Identity no-op elsewhere. Mirrors armGetWritableCodePtr in pcsx2/arm64/AsmHelpers.cpp.
|
||||
#if defined(__APPLE__) && TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
|
||||
#include "common/Darwin/DarwinMisc.h"
|
||||
static void* gsGetWritableCodePtr(void* rx_ptr)
|
||||
{
|
||||
return static_cast<u8*>(rx_ptr) + DarwinMisc::g_code_rw_offset;
|
||||
}
|
||||
#else
|
||||
static void* gsGetWritableCodePtr(void* rx_ptr) { return rx_ptr; }
|
||||
#endif
|
||||
|
||||
// warning : offset of on non-standard-layout type 'GSScanlineGlobalData' [-Winvalid-offsetof]
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
@@ -84,8 +96,9 @@ static const auto& _fd = v2;
|
||||
#define armAsm (&m_emitter)
|
||||
|
||||
GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(u64 key, void* code, size_t maxsize)
|
||||
: m_emitter(static_cast<vixl::byte*>(code), maxsize, vixl::aarch64::PositionDependentCode)
|
||||
: m_emitter(static_cast<vixl::byte*>(gsGetWritableCodePtr(code)), maxsize, vixl::aarch64::PositionDependentCode)
|
||||
, m_sel(key)
|
||||
, m_code_rx(static_cast<const u8*>(code))
|
||||
{
|
||||
// hopefully no constants which need to be moved to register first..
|
||||
m_emitter.GetScratchRegisterList()->Remove(_xscratch.GetCode());
|
||||
|
||||
@@ -15,7 +15,8 @@ public:
|
||||
void Generate();
|
||||
|
||||
size_t GetSize() const { return m_emitter.GetSizeOfCodeGenerated(); }
|
||||
const u8* GetCode() const { return m_emitter.GetBuffer().GetStartAddress<const u8*>(); }
|
||||
// Return RX entry pointer, not the RW write pointer.
|
||||
const u8* GetCode() const { return m_code_rx; }
|
||||
|
||||
private:
|
||||
void Init();
|
||||
@@ -79,4 +80,7 @@ private:
|
||||
GSScanlineSelector m_sel;
|
||||
|
||||
vixl::aarch64::Label m_step_label;
|
||||
|
||||
// RX entry pointer; GetCode() must return RX even when the emitter writes through the RW alias.
|
||||
const u8* m_code_rx;
|
||||
};
|
||||
|
||||
@@ -9,6 +9,18 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// On iOS dual-map JIT, write through the RW alias (rx + g_code_rw_offset).
|
||||
// Identity no-op elsewhere. Mirrors armGetWritableCodePtr in pcsx2/arm64/AsmHelpers.cpp.
|
||||
#if defined(__APPLE__) && TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
|
||||
#include "common/Darwin/DarwinMisc.h"
|
||||
static void* gsGetWritableCodePtr(void* rx_ptr)
|
||||
{
|
||||
return static_cast<u8*>(rx_ptr) + DarwinMisc::g_code_rw_offset;
|
||||
}
|
||||
#else
|
||||
static void* gsGetWritableCodePtr(void* rx_ptr) { return rx_ptr; }
|
||||
#endif
|
||||
|
||||
MULTI_ISA_UNSHARED_IMPL;
|
||||
|
||||
using namespace vixl::aarch64;
|
||||
@@ -28,8 +40,9 @@ static constexpr const GSScanlineConstantData128B& g_const = g_const_128b;
|
||||
#define armAsm (&m_emitter)
|
||||
|
||||
GSSetupPrimCodeGenerator::GSSetupPrimCodeGenerator(u64 key, void* code, size_t maxsize)
|
||||
: m_emitter(static_cast<vixl::byte*>(code), maxsize, vixl::aarch64::PositionDependentCode)
|
||||
: m_emitter(static_cast<vixl::byte*>(gsGetWritableCodePtr(code)), maxsize, vixl::aarch64::PositionDependentCode)
|
||||
, m_sel(key)
|
||||
, m_code_rx(static_cast<const u8*>(code))
|
||||
{
|
||||
m_en.z = m_sel.zb ? 1 : 0;
|
||||
m_en.f = m_sel.fb && m_sel.fge ? 1 : 0;
|
||||
|
||||
@@ -15,7 +15,8 @@ public:
|
||||
void Generate();
|
||||
|
||||
size_t GetSize() const { return m_emitter.GetSizeOfCodeGenerated(); }
|
||||
const u8* GetCode() const { return m_emitter.GetBuffer().GetStartAddress<const u8*>(); }
|
||||
// Return RX entry pointer, not the RW write pointer.
|
||||
const u8* GetCode() const { return m_code_rx; }
|
||||
|
||||
private:
|
||||
void Depth();
|
||||
@@ -30,4 +31,7 @@ private:
|
||||
{
|
||||
u32 z : 1, f : 1, t : 1, c : 1;
|
||||
} m_en;
|
||||
|
||||
// RX entry pointer; GetCode() must return RX even when the emitter writes through the RW alias.
|
||||
const u8* m_code_rx;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user