From ad315fd20dba17593f83f1d40bab95e5e6814883 Mon Sep 17 00:00:00 2001 From: Vitor Kiguchi Date: Wed, 28 Apr 2021 01:03:43 -0300 Subject: [PATCH 1/3] Attempt to implement changes necessary for JIT on Apple Silicon as described on https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon --- src/backend/A64/block_of_code.cpp | 10 ++++++++++ src/backend/A64/emitter/a64_emitter.cpp | 6 ++++++ src/backend/A64/emitter/code_block.h | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/src/backend/A64/block_of_code.cpp b/src/backend/A64/block_of_code.cpp index fd370d7f..c27f66a1 100644 --- a/src/backend/A64/block_of_code.cpp +++ b/src/backend/A64/block_of_code.cpp @@ -20,6 +20,10 @@ #include #endif +#ifdef __APPLE__ +#include +#endif + namespace Dynarmic::BackendA64 { const Arm64Gen::ARM64Reg BlockOfCode::ABI_RETURN = Arm64Gen::ARM64Reg::X0; @@ -86,12 +90,18 @@ void BlockOfCode::EnableWriting() { #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT ProtectMemory(GetCodePtr(), TOTAL_CODE_SIZE, false); #endif +#ifdef __APPLE__ + pthread_jit_write_protect_np(false); +#endif } void BlockOfCode::DisableWriting() { #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT ProtectMemory(GetCodePtr(), TOTAL_CODE_SIZE, true); #endif +#ifdef __APPLE__ + pthread_jit_write_protect_np(true); +#endif } void BlockOfCode::ClearCache() { diff --git a/src/backend/A64/emitter/a64_emitter.cpp b/src/backend/A64/emitter/a64_emitter.cpp index 0718afb6..cfe905be 100644 --- a/src/backend/A64/emitter/a64_emitter.cpp +++ b/src/backend/A64/emitter/a64_emitter.cpp @@ -8,6 +8,10 @@ #include #include +#if defined(__APPLE__) +#include +#endif + #include "a64_emitter.h" #include "common/assert.h" #include "common/bit_util.h" @@ -366,6 +370,8 @@ void ARM64XEmitter::FlushIcacheSection(const u8* start, const u8* end) { // Header file says this is equivalent to: sys_icache_invalidate(start, end - // start); sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start); +#elif defined(__APPLE__) + sys_icache_invalidate(const_cast(start), end - start); #else // Don't rely on GCC's __clear_cache implementation, as it caches // icache/dcache cache line sizes, that can vary between cores on diff --git a/src/backend/A64/emitter/code_block.h b/src/backend/A64/emitter/code_block.h index 5f1bfa91..26b0ebbc 100644 --- a/src/backend/A64/emitter/code_block.h +++ b/src/backend/A64/emitter/code_block.h @@ -56,8 +56,12 @@ public: total_region_size = size; #if defined(_WIN32) void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else +#if defined(__APPLE__) + void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE | MAP_JIT, -1, 0); #else void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0); +#endif if (ptr == MAP_FAILED) ptr = nullptr; From 94d1f7c01a5c73ee74b71269ca4bc3741e74b22c Mon Sep 17 00:00:00 2001 From: Vitor Kiguchi Date: Tue, 4 May 2021 03:21:29 -0300 Subject: [PATCH 2/3] Simplify apple silicon changes --- src/backend/A64/block_of_code.cpp | 10 +++------- src/backend/A64/emitter/a64_emitter.cpp | 6 ++---- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/backend/A64/block_of_code.cpp b/src/backend/A64/block_of_code.cpp index c27f66a1..cff246f8 100644 --- a/src/backend/A64/block_of_code.cpp +++ b/src/backend/A64/block_of_code.cpp @@ -52,9 +52,11 @@ constexpr size_t FAR_CODE_OFFSET = 100 * 1024 * 1024; #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT void ProtectMemory(const void* base, size_t size, bool is_executable) { -#ifdef _WIN32 +#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); @@ -90,18 +92,12 @@ void BlockOfCode::EnableWriting() { #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT ProtectMemory(GetCodePtr(), TOTAL_CODE_SIZE, false); #endif -#ifdef __APPLE__ - pthread_jit_write_protect_np(false); -#endif } void BlockOfCode::DisableWriting() { #ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT ProtectMemory(GetCodePtr(), TOTAL_CODE_SIZE, true); #endif -#ifdef __APPLE__ - pthread_jit_write_protect_np(true); -#endif } void BlockOfCode::ClearCache() { diff --git a/src/backend/A64/emitter/a64_emitter.cpp b/src/backend/A64/emitter/a64_emitter.cpp index cfe905be..efbb4767 100644 --- a/src/backend/A64/emitter/a64_emitter.cpp +++ b/src/backend/A64/emitter/a64_emitter.cpp @@ -366,12 +366,10 @@ void ARM64XEmitter::FlushIcacheSection(const u8* start, const u8* end) { if (start == end) return; -#if defined(IOS) +#if defined(__APPLE__) // Header file says this is equivalent to: sys_icache_invalidate(start, end - // start); - sys_cache_control(kCacheFunctionPrepareForExecution, start, end - start); -#elif defined(__APPLE__) - sys_icache_invalidate(const_cast(start), end - start); + sys_cache_control(kCacheFunctionPrepareForExecution, const_cast(start), end - start); #else // Don't rely on GCC's __clear_cache implementation, as it caches // icache/dcache cache line sizes, that can vary between cores on From 2b3be5eee8b6cea1e4dd7924ba7fe9115f8e13ce Mon Sep 17 00:00:00 2001 From: Vitor Kiguchi Date: Tue, 4 May 2021 03:36:24 -0300 Subject: [PATCH 3/3] enable DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT by default on apple silicon --- CMakeLists.txt | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6348f53f..211927cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,9 +8,32 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(MASTER_PROJECT ON) endif() +# Add the module directory to the list of paths +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") + +# Arch detection +include(DetectArchitecture) +if (MSVC) + detect_architecture("_M_AMD64" x86_64) + detect_architecture("_M_ARM64" Aarch64) +else() + detect_architecture("__x86_64__" x86_64) + detect_architecture("__aarch64__" Aarch64) +endif() +if (NOT DEFINED DYNARMIC_ARCHITECTURE) + message(FATAL_ERROR "Unsupported architecture encountered. Ending CMake generation.") +endif() +message(STATUS "Target architecture: ${DYNARMIC_ARCHITECTURE}") + +set(REQUIRES_NO_EXECUTE_SUPPORT OFF) +#Apple Silicon chips require W^X +if(APPLE AND ARCHITECTURE_Aarch64) + set(REQUIRES_NO_EXECUTE_SUPPORT ON) +endif() + # Dynarmic project options option(DYNARMIC_ENABLE_CPU_FEATURE_DETECTION "Turning this off causes dynarmic to assume the host CPU doesn't support anything later than SSE3" ON) -option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" OFF) +option(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT "Enables support for systems that require W^X" ${REQUIRES_NO_EXECUTE_SUPPORT}) option(DYNARMIC_FATAL_ERRORS "Errors are fatal" OFF) option(DYNARMIC_TESTS "Build tests" ${MASTER_PROJECT}) option(DYNARMIC_TESTS_USE_UNICORN "Enable fuzzing tests against unicorn" OFF) @@ -38,9 +61,6 @@ if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") message(SEND_ERROR "In-source builds are not allowed.") endif() -# Add the module directory to the list of paths -list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules") - # Compiler flags if (MSVC) set(DYNARMIC_CXX_FLAGS @@ -99,20 +119,6 @@ else() endif() endif() -# Arch detection -include(DetectArchitecture) -if (MSVC) - detect_architecture("_M_AMD64" x86_64) - detect_architecture("_M_ARM64" Aarch64) -else() - detect_architecture("__x86_64__" x86_64) - detect_architecture("__aarch64__" Aarch64) -endif() -if (NOT DEFINED DYNARMIC_ARCHITECTURE) - message(FATAL_ERROR "Unsupported architecture encountered. Ending CMake generation.") -endif() -message(STATUS "Target architecture: ${DYNARMIC_ARCHITECTURE}") - # Include Boost if (NOT TARGET boost) if (NOT Boost_INCLUDE_DIRS)