mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-18 21:14:35 +03:00
Fixed iOS compilation (reworked MAP_JIT detection, and pthread_jit_write_protect_np() support)
This commit is contained in:
@@ -53,13 +53,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Android NDK doesn't provide `shm_open()` and `shm_unlink()`.
|
// Android NDK doesn't provide `shm_open()` and `shm_unlink()`.
|
||||||
#if defined(__BIONIC__)
|
#if !defined(_WIN32) && !defined(__BIONIC__)
|
||||||
#define ASMJIT_VM_SHM_AVAILABLE 0
|
#define ASMJIT_HAS_SHM_OPEN_AND_UNLINK
|
||||||
#else
|
|
||||||
#define ASMJIT_VM_SHM_AVAILABLE 1
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__) && ASMJIT_ARCH_ARM >= 64
|
#if defined(__APPLE__) && TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64
|
||||||
#define ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP
|
#define ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -347,7 +345,7 @@ public:
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if ASMJIT_VM_SHM_AVAILABLE
|
#ifdef ASMJIT_HAS_SHM_OPEN_AND_UNLINK
|
||||||
else {
|
else {
|
||||||
_tmpName.assignFormat(kShmFormat, (unsigned long long)bits);
|
_tmpName.assignFormat(kShmFormat, (unsigned long long)bits);
|
||||||
_fd = ::shm_open(_tmpName.data(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
_fd = ::shm_open(_tmpName.data(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
||||||
@@ -371,7 +369,7 @@ public:
|
|||||||
FileType type = _fileType;
|
FileType type = _fileType;
|
||||||
_fileType = kFileTypeNone;
|
_fileType = kFileTypeNone;
|
||||||
|
|
||||||
#if ASMJIT_VM_SHM_AVAILABLE
|
#ifdef ASMJIT_HAS_SHM_OPEN_AND_UNLINK
|
||||||
if (type == kFileTypeShm) {
|
if (type == kFileTypeShm) {
|
||||||
::shm_unlink(_tmpName.data());
|
::shm_unlink(_tmpName.data());
|
||||||
return;
|
return;
|
||||||
@@ -409,12 +407,29 @@ static int mmProtFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
|
|||||||
return protection;
|
return protection;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__) && TARGET_OS_OSX
|
||||||
// Detects whether the current process is hardened, which means that pages that have WRITE and EXECUTABLE flags cannot
|
static int getOSXVersion() noexcept {
|
||||||
// be allocated without MAP_JIT flag.
|
// MAP_JIT flag required to run unsigned JIT code is only supported by kernel version 10.14+ (Mojave).
|
||||||
static inline bool hasHardenedRuntimeMacOS() noexcept {
|
static std::atomic<uint32_t> globalVersion;
|
||||||
|
|
||||||
|
int ver = globalVersion.load();
|
||||||
|
if (!ver) {
|
||||||
|
struct utsname osname {};
|
||||||
|
uname(&osname);
|
||||||
|
ver = atoi(osname.release);
|
||||||
|
globalVersion.store(ver);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ver;
|
||||||
|
}
|
||||||
|
#endif // __APPLE__ && TARGET_OS_OSX
|
||||||
|
|
||||||
|
// Detects whether the current process is hardened, which means that pages that have WRITE and EXECUTABLE flags
|
||||||
|
// cannot be normally allocated. On OSX + AArch64 such allocation requires MAP_JIT flag, other platforms don't
|
||||||
|
// support this combination.
|
||||||
|
static bool hasHardenedRuntime() noexcept {
|
||||||
#if TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64
|
#if TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64
|
||||||
// MacOS on AArch64 has always hardened runtime enabled.
|
// OSX on AArch64 has always hardened runtime enabled.
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
static std::atomic<uint32_t> globalHardenedFlag;
|
static std::atomic<uint32_t> globalHardenedFlag;
|
||||||
@@ -427,7 +442,7 @@ static inline bool hasHardenedRuntimeMacOS() noexcept {
|
|||||||
|
|
||||||
uint32_t flag = globalHardenedFlag.load();
|
uint32_t flag = globalHardenedFlag.load();
|
||||||
if (flag == kHardenedFlagUnknown) {
|
if (flag == kHardenedFlagUnknown) {
|
||||||
size_t pageSize = ::getpagesize();
|
uint32_t pageSize = uint32_t(::getpagesize());
|
||||||
|
|
||||||
void* ptr = mmap(nullptr, pageSize, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
void* ptr = mmap(nullptr, pageSize, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
if (ptr == MAP_FAILED) {
|
if (ptr == MAP_FAILED) {
|
||||||
@@ -444,45 +459,16 @@ static inline bool hasHardenedRuntimeMacOS() noexcept {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool hasMapJitSupportMacOS() noexcept {
|
|
||||||
#if TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64
|
|
||||||
// MacOS for 64-bit AArch architecture always uses hardened runtime. Some documentation can be found here:
|
|
||||||
// - https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon
|
|
||||||
return true;
|
|
||||||
#elif TARGET_OS_OSX
|
|
||||||
// MAP_JIT flag required to run unsigned JIT code is only supported by kernel version 10.14+ (Mojave) and IOS.
|
|
||||||
static std::atomic<uint32_t> globalVersion;
|
|
||||||
|
|
||||||
int ver = globalVersion.load();
|
|
||||||
if (!ver) {
|
|
||||||
struct utsname osname {};
|
|
||||||
uname(&osname);
|
|
||||||
ver = atoi(osname.release);
|
|
||||||
globalVersion.store(ver);
|
|
||||||
}
|
|
||||||
return ver >= 18;
|
|
||||||
#else
|
|
||||||
// Assume it's available.
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif // __APPLE__
|
|
||||||
|
|
||||||
// Detects whether the current process is hardened, which means that pages that have WRITE and EXECUTABLE flags
|
|
||||||
// cannot be normally allocated. On MacOS such allocation requires MAP_JIT flag.
|
|
||||||
static inline bool hasHardenedRuntime() noexcept {
|
|
||||||
#if defined(__APPLE__)
|
|
||||||
return hasHardenedRuntimeMacOS();
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detects whether MAP_JIT is available.
|
// Detects whether MAP_JIT is available.
|
||||||
static inline bool hasMapJitSupport() noexcept {
|
static inline bool hasMapJitSupport() noexcept {
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__) && TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64
|
||||||
return hasMapJitSupportMacOS();
|
// OSX on AArch64 always uses hardened runtime + MAP_JIT:
|
||||||
|
// - https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon
|
||||||
|
return true;
|
||||||
|
#elif defined(__APPLE__) && TARGET_OS_OSX
|
||||||
|
return getOSXVersion() >= 18;
|
||||||
#else
|
#else
|
||||||
|
// MAP_JIT is not available (it's only available on OSX).
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -564,15 +550,15 @@ static Error getShmStrategy(ShmStrategy* strategyOut) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static HardenedRuntimeFlags getHardenedRuntimeFlags() noexcept {
|
static HardenedRuntimeFlags getHardenedRuntimeFlags() noexcept {
|
||||||
HardenedRuntimeFlags hrFlags = HardenedRuntimeFlags::kNone;
|
HardenedRuntimeFlags flags = HardenedRuntimeFlags::kNone;
|
||||||
|
|
||||||
if (hasHardenedRuntime())
|
if (hasHardenedRuntime())
|
||||||
hrFlags |= HardenedRuntimeFlags::kEnabled;
|
flags |= HardenedRuntimeFlags::kEnabled;
|
||||||
|
|
||||||
if (hasMapJitSupport())
|
if (hasMapJitSupport())
|
||||||
hrFlags |= HardenedRuntimeFlags::kMapJit;
|
flags |= HardenedRuntimeFlags::kMapJit;
|
||||||
|
|
||||||
return hrFlags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error alloc(void** p, size_t size, MemoryFlags memoryFlags) noexcept {
|
Error alloc(void** p, size_t size, MemoryFlags memoryFlags) noexcept {
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ enum class MemoryFlags : uint32_t {
|
|||||||
//! in MAC bundles. This flag is not turned on by default, because when a process uses `fork()` the child process
|
//! in MAC bundles. This flag is not turned on by default, because when a process uses `fork()` the child process
|
||||||
//! has no access to the pages mapped with `MAP_JIT`, which could break code that doesn't expect this behavior.
|
//! has no access to the pages mapped with `MAP_JIT`, which could break code that doesn't expect this behavior.
|
||||||
//!
|
//!
|
||||||
//! \note This flag can only be used with \ref VirtMem::alloc().
|
//! \note This flag can only be used with \ref VirtMem::alloc(), `MAP_JIT` only works on OSX and not on iOS.
|
||||||
kMMapEnableMapJit = 0x00000010u,
|
kMMapEnableMapJit = 0x00000010u,
|
||||||
|
|
||||||
//! Pass `PROT_MAX(PROT_READ)` to mmap() on platforms that support `PROT_MAX`.
|
//! Pass `PROT_MAX(PROT_READ)` to mmap() on platforms that support `PROT_MAX`.
|
||||||
@@ -157,13 +157,13 @@ enum class HardenedRuntimeFlags : uint32_t {
|
|||||||
//! Hardened runtime is enabled - it's not possible to have "Write & Execute" memory protection. The runtime
|
//! Hardened runtime is enabled - it's not possible to have "Write & Execute" memory protection. The runtime
|
||||||
//! enforces W^X (either write or execute).
|
//! enforces W^X (either write or execute).
|
||||||
//!
|
//!
|
||||||
//! \note If the runtime is hardened it means that an operating system specific protection is used. For example on
|
//! \note If the runtime is hardened it means that an operating system specific protection is used. For example
|
||||||
//! MacOS platform it's possible to allocate memory with MAP_JIT flag and then use `pthread_jit_write_protect_np()`
|
//! on Apple OSX it's possible to allocate memory with MAP_JIT flag and then use `pthread_jit_write_protect_np()`
|
||||||
//! to temporarily swap access permissions for the current thread. Dual mapping is also a possibility on X86/X64
|
//! to temporarily swap access permissions for the current thread. Dual mapping is also a possibility on X86/X64
|
||||||
//! architecture.
|
//! architecture.
|
||||||
kEnabled = 0x00000001u,
|
kEnabled = 0x00000001u,
|
||||||
|
|
||||||
//! Read+Write+Execute can only be allocated with MAP_JIT flag (Apple specific).
|
//! Read+Write+Execute can only be allocated with MAP_JIT flag (Apple specific, only available on OSX).
|
||||||
kMapJit = 0x00000002u
|
kMapJit = 0x00000002u
|
||||||
};
|
};
|
||||||
ASMJIT_DEFINE_ENUM_FLAGS(HardenedRuntimeFlags)
|
ASMJIT_DEFINE_ENUM_FLAGS(HardenedRuntimeFlags)
|
||||||
|
|||||||
Reference in New Issue
Block a user