diff --git a/CMakeLists.txt b/CMakeLists.txt index 84b99d2..3553658 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -686,11 +686,29 @@ if (NOT ASMJIT_EMBED) if (NOT (ASMJIT_NO_BUILDER OR ASMJIT_NO_COMPILER)) # Vectorcall tests and XMM tests require at least SSE2 in 32-bit mode (in 64-bit mode it's implicit). - set(sse2_flags "") - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC") - asmjit_detect_cflags(sse2_flags "-arch:SSE2") - else() - asmjit_detect_cflags(sse2_flags "-msse2") + # Some compilers don't like passing -msse2 for 64-bit targets, and some compilers targeting non-x86 + # would pass "-msse2" compile flag check, but with a warning not detected by CMake. Thus, verify that + # our target is really 32-bit X86 and only use -msse2 or -arch:SSE2 flags when necessary. + set(ASMJIT_SSE2_CFLAGS "") + + check_cxx_source_compiles(" + #if defined(_M_IX86) || defined(__X86__) || defined(__i386__) + int target_is_32_bit_x86() { return 1; } + #else + // Compile error... + #endif + + int main() { + return target_is_32_bit_x86(); + } + " ASMJIT_TARGET_IS_32_BIT_X86) + + if (ASMJIT_TARGET_IS_32_BIT_X86) + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC") + asmjit_detect_cflags(ASMJIT_SSE2_CFLAGS "-arch:SSE2") + else() + asmjit_detect_cflags(ASMJIT_SSE2_CFLAGS "-msse2") + endif() endif() asmjit_add_target(asmjit_test_compiler TEST SOURCES test/asmjit_test_compiler.cpp @@ -698,7 +716,7 @@ if (NOT ASMJIT_EMBED) test/asmjit_test_compiler_a64.cpp test/asmjit_test_compiler_x86.cpp LIBRARIES asmjit::asmjit - CFLAGS ${ASMJIT_PRIVATE_CFLAGS} ${sse2_flags} + CFLAGS ${ASMJIT_PRIVATE_CFLAGS} ${ASMJIT_SSE2_CFLAGS} CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG} CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL}) endif() diff --git a/src/asmjit/core/jitallocator.cpp b/src/asmjit/core/jitallocator.cpp index 7b80c30..6a1a2d1 100644 --- a/src/asmjit/core/jitallocator.cpp +++ b/src/asmjit/core/jitallocator.cpp @@ -1399,11 +1399,12 @@ static void test_jit_allocator_alloc_release() noexcept { using Opt = JitAllocatorOptions; + VirtMem::HardenedRuntimeInfo hri = VirtMem::hardenedRuntimeInfo(); + TestParams testParams[] = { { "Default" , Opt::kNone, 0, 0 }, { "16MB blocks" , Opt::kNone, 16 * 1024 * 1024, 0 }, { "256B granularity" , Opt::kNone, 0, 256 }, - { "kUseDualMapping" , Opt::kUseDualMapping , 0, 0 }, { "kUseMultiplePools" , Opt::kUseMultiplePools, 0, 0 }, { "kFillUnusedMemory" , Opt::kFillUnusedMemory, 0, 0 }, { "kImmediateRelease" , Opt::kImmediateRelease, 0, 0 }, @@ -1411,6 +1412,7 @@ static void test_jit_allocator_alloc_release() noexcept { { "kUseLargePages" , Opt::kUseLargePages, 0, 0 }, { "kUseLargePages | kFillUnusedMemory" , Opt::kUseLargePages | Opt::kFillUnusedMemory, 0, 0 }, { "kUseLargePages | kAlignBlockSizeToLargePage", Opt::kUseLargePages | Opt::kAlignBlockSizeToLargePage, 0, 0 }, + { "kUseDualMapping" , Opt::kUseDualMapping , 0, 0 }, { "kUseDualMapping | kFillUnusedMemory" , Opt::kUseDualMapping | Opt::kFillUnusedMemory, 0, 0 } }; @@ -1427,6 +1429,12 @@ static void test_jit_allocator_alloc_release() noexcept { } for (uint32_t testId = 0; testId < ASMJIT_ARRAY_SIZE(testParams); testId++) { + // Don't try to allocate dual-mapping if dual mapping is not possible - it would fail the test. + if (Support::test(testParams[testId].options, JitAllocatorOptions::kUseDualMapping) && + !Support::test(hri.flags, VirtMem::HardenedRuntimeFlags::kDualMapping)) { + continue; + } + INFO("JitAllocator(%s)", testParams[testId].name); JitAllocator::CreateParams params {}; diff --git a/src/asmjit/core/virtmem.cpp b/src/asmjit/core/virtmem.cpp index 5a1801a..d9a74e8 100644 --- a/src/asmjit/core/virtmem.cpp +++ b/src/asmjit/core/virtmem.cpp @@ -141,6 +141,11 @@ static size_t detectLargePageSize() noexcept { return ::GetLargePageMinimum(); } +static bool hasDualMappingSupport() noexcept { + // TODO: This assumption works on X86 platforms, this may not work on AArch64. + return true; +} + // Returns windows-specific protectFlags from \ref MemoryFlags. static DWORD protectFlagsFromMemoryFlags(MemoryFlags memoryFlags) noexcept { DWORD protectFlags; @@ -165,7 +170,12 @@ static DWORD desiredAccessFromMemoryFlags(MemoryFlags memoryFlags) noexcept { } static HardenedRuntimeFlags getHardenedRuntimeFlags() noexcept { - return HardenedRuntimeFlags::kNone; + HardenedRuntimeFlags flags = HardenedRuntimeFlags::kNone; + + if (hasDualMappingSupport()) + flags |= HardenedRuntimeFlags::kDualMapping; + + return flags; } Error alloc(void** p, size_t size, MemoryFlags memoryFlags) noexcept { @@ -703,8 +713,8 @@ static bool hasHardenedRuntime() noexcept { // Detects whether MAP_JIT is available. static inline bool hasMapJitSupport() noexcept { -#if defined(__APPLE__) && TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64 - // OSX on AArch64 always uses hardened runtime + MAP_JIT: +#if defined(__APPLE__) && TARGET_OS_OSX && ASMJIT_ARCH_X86 == 0 + // Apple platforms always use hardened runtime + MAP_JIT on non-x86 hardware: // - https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon return true; #elif defined(__APPLE__) && TARGET_OS_OSX @@ -746,6 +756,15 @@ static inline int mmMapJitFromMemoryFlags(MemoryFlags memoryFlags) noexcept { #endif } +static inline bool hasDualMappingSupport() noexcept { +#if defined(__APPLE__) && TARGET_OS_OSX && ASMJIT_ARCH_X86 == 0 + // Apple platforms don't allow dual-mapping on non-x86 hardware. + return false; +#else + return true; +#endif +} + static HardenedRuntimeFlags getHardenedRuntimeFlags() noexcept { HardenedRuntimeFlags flags = HardenedRuntimeFlags::kNone; @@ -755,6 +774,9 @@ static HardenedRuntimeFlags getHardenedRuntimeFlags() noexcept { if (hasMapJitSupport()) flags |= HardenedRuntimeFlags::kMapJit; + if (hasDualMappingSupport()) + flags |= HardenedRuntimeFlags::kDualMapping; + return flags; } diff --git a/src/asmjit/core/virtmem.h b/src/asmjit/core/virtmem.h index 5023bda..c2d16a3 100644 --- a/src/asmjit/core/virtmem.h +++ b/src/asmjit/core/virtmem.h @@ -215,8 +215,11 @@ enum class HardenedRuntimeFlags : uint32_t { //! architecture. kEnabled = 0x00000001u, - //! Read+Write+Execute can only be allocated with MAP_JIT flag (Apple specific, only available on OSX). - kMapJit = 0x00000002u + //! Read+Write+Execute can only be allocated with MAP_JIT flag (Apple specific, only available on Apple platforms). + kMapJit = 0x00000002u, + + //! Read+Write+Executa can be allocated with dual mapping approach (one region with RW and the other with RX). + kDualMapping = 0x00000004u }; ASMJIT_DEFINE_ENUM_FLAGS(HardenedRuntimeFlags)