From d968f7ad81023d069dd365a7ad0a06cea5e89a21 Mon Sep 17 00:00:00 2001 From: Steven Smith <1269164+Steveice10@users.noreply.github.com> Date: Fri, 4 Nov 2022 19:25:55 -0700 Subject: [PATCH] backend/A64: Fix SpinLockImpl not setting required memory permissions. (#9) --- src/dynarmic/backend/A64/block_of_code.cpp | 39 ------------------- src/dynarmic/backend/A64/block_of_code.h | 5 --- src/dynarmic/backend/A64/emitter/code_block.h | 35 +++++++++++++++++ src/dynarmic/backend/A64/spin_lock_arm64.cpp | 2 + 4 files changed, 37 insertions(+), 44 deletions(-) diff --git a/src/dynarmic/backend/A64/block_of_code.cpp b/src/dynarmic/backend/A64/block_of_code.cpp index 027b559c..a6c443c3 100644 --- a/src/dynarmic/backend/A64/block_of_code.cpp +++ b/src/dynarmic/backend/A64/block_of_code.cpp @@ -17,16 +17,6 @@ #include "dynarmic/backend/A64/perf_map.h" #include "dynarmic/interface/halt_reason.h" -#ifdef _WIN32 -# include -#else -# include -#endif - -#ifdef __APPLE__ -# include -#endif - namespace Dynarmic::BackendA64 { const Arm64Gen::ARM64Reg BlockOfCode::ABI_RETURN = Arm64Gen::ARM64Reg::X0; @@ -53,23 +43,6 @@ namespace { constexpr size_t TOTAL_CODE_SIZE = 128 * 1024 * 1024; constexpr size_t FAR_CODE_OFFSET = 100 * 1024 * 1024; -#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT -void ProtectMemory([[maybe_unused]] const void* base, [[maybe_unused]] size_t size, bool is_executable) { -# if defined(_WIN32) - DWORD oldProtect = 0; - VirtualProtect(const_cast(base), size, is_executable ? PAGE_EXECUTE_READ : PAGE_READWRITE, &oldProtect); -# elif defined(__APPLE__) - pthread_jit_write_protect_np(is_executable); -# else - static const size_t pageSize = sysconf(_SC_PAGESIZE); - const size_t iaddr = reinterpret_cast(base); - const size_t roundAddr = iaddr & ~(pageSize - static_cast(1)); - const int mode = is_executable ? (PROT_READ | PROT_EXEC) : (PROT_READ | PROT_WRITE); - mprotect(reinterpret_cast(roundAddr), size + (iaddr - roundAddr), mode); -# endif -} -#endif - } // anonymous namespace BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi) @@ -91,18 +64,6 @@ void BlockOfCode::PreludeComplete() { DisableWriting(); } -void BlockOfCode::EnableWriting() { -#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT - ProtectMemory(GetCodePtr(), TOTAL_CODE_SIZE, false); -#endif -} - -void BlockOfCode::DisableWriting() { -#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT - ProtectMemory(GetCodePtr(), TOTAL_CODE_SIZE, true); -#endif -} - void BlockOfCode::ClearCache() { ASSERT(prelude_complete); in_far_code = false; diff --git a/src/dynarmic/backend/A64/block_of_code.h b/src/dynarmic/backend/A64/block_of_code.h index 43ad502c..2d048508 100644 --- a/src/dynarmic/backend/A64/block_of_code.h +++ b/src/dynarmic/backend/A64/block_of_code.h @@ -38,11 +38,6 @@ public: /// Call when external emitters have finished emitting their preludes. void PreludeComplete(); - /// Change permissions to RW. This is required to support systems with W^X enforced. - void EnableWriting(); - /// Change permissions to RX. This is required to support systems with W^X enforced. - void DisableWriting(); - /// Clears this block of code and resets code pointer to beginning. void ClearCache(); /// Calculates how much space is remaining to use. This is the minimum of near code and far code. diff --git a/src/dynarmic/backend/A64/emitter/code_block.h b/src/dynarmic/backend/A64/emitter/code_block.h index 738b3357..094f02b4 100644 --- a/src/dynarmic/backend/A64/emitter/code_block.h +++ b/src/dynarmic/backend/A64/emitter/code_block.h @@ -13,6 +13,10 @@ # include #endif +#ifdef __APPLE__ +# include +#endif + #include #include @@ -29,6 +33,23 @@ private: // host specific breakpoint instruction virtual void PoisonMemory() = 0; +#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT + void ProtectMemory([[maybe_unused]] const void* base, [[maybe_unused]] size_t size, bool is_executable) { +# if defined(_WIN32) + DWORD oldProtect = 0; + VirtualProtect(const_cast(base), size, is_executable ? PAGE_EXECUTE_READ : PAGE_READWRITE, &oldProtect); +# elif defined(__APPLE__) + pthread_jit_write_protect_np(is_executable); +# else + static const size_t pageSize = sysconf(_SC_PAGESIZE); + const size_t iaddr = reinterpret_cast(base); + const size_t roundAddr = iaddr & ~(pageSize - static_cast(1)); + const int mode = is_executable ? (PROT_READ | PROT_EXEC) : (PROT_READ | PROT_WRITE); + mprotect(reinterpret_cast(roundAddr), size + (iaddr - roundAddr), mode); +# endif + } +#endif + protected: u8* region = nullptr; // Size of region we can use. @@ -136,5 +157,19 @@ public: child->ResetCodePtr(); m_children.emplace_back(child); } + + /// Change permissions to RW. This is required to support systems with W^X enforced. + void EnableWriting() { +#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT + ProtectMemory(T::GetCodePtr(), total_region_size, false); +#endif + } + + /// Change permissions to RX. This is required to support systems with W^X enforced. + void DisableWriting() { +#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT + ProtectMemory(T::GetCodePtr(), total_region_size, true); +#endif + } }; } // namespace Dynarmic::BackendA64 diff --git a/src/dynarmic/backend/A64/spin_lock_arm64.cpp b/src/dynarmic/backend/A64/spin_lock_arm64.cpp index 93a17443..d76e0777 100644 --- a/src/dynarmic/backend/A64/spin_lock_arm64.cpp +++ b/src/dynarmic/backend/A64/spin_lock_arm64.cpp @@ -51,6 +51,7 @@ SpinLockImpl impl; SpinLockImpl::SpinLockImpl() { code.AllocCodeSpace(64); + code.EnableWriting(); const ARM64Reg ABI_PARAM1 = BackendA64::HostLocToReg64(BackendA64::ABI_PARAM1); code.AlignCode16(); lock = reinterpret_cast(code.GetWritableCodePtr()); @@ -61,6 +62,7 @@ SpinLockImpl::SpinLockImpl() { unlock = reinterpret_cast(code.GetWritableCodePtr()); EmitSpinLockUnlock(code, ABI_PARAM1); code.RET(); + code.DisableWriting(); code.FlushIcache(); }