asmjit 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/asmjit.gemspec +1 -1
- data/ext/asmjit/asmjit/.editorconfig +10 -0
- data/ext/asmjit/asmjit/.github/FUNDING.yml +1 -0
- data/ext/asmjit/asmjit/.github/workflows/build-config.json +47 -0
- data/ext/asmjit/asmjit/.github/workflows/build.yml +156 -0
- data/ext/asmjit/asmjit/.gitignore +6 -0
- data/ext/asmjit/asmjit/CMakeLists.txt +611 -0
- data/ext/asmjit/asmjit/LICENSE.md +17 -0
- data/ext/asmjit/asmjit/README.md +69 -0
- data/ext/asmjit/asmjit/src/asmjit/a64.h +62 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64archtraits_p.h +81 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.cpp +5115 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.h +72 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.cpp +51 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.h +57 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.cpp +60 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.h +247 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper.cpp +464 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper_p.h +50 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64emitter.h +1228 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter.cpp +298 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter_p.h +59 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64func.cpp +189 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64func_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64globals.h +1894 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi.cpp +278 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi_p.h +41 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.cpp +1957 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.h +74 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb_p.h +876 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.cpp +85 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.h +312 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass.cpp +852 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass_p.h +105 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/a64utils.h +179 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armformatter.cpp +143 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armformatter_p.h +44 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armglobals.h +21 -0
- data/ext/asmjit/asmjit/src/asmjit/arm/armoperand.h +621 -0
- data/ext/asmjit/asmjit/src/asmjit/arm.h +62 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-begin.h +17 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-end.h +9 -0
- data/ext/asmjit/asmjit/src/asmjit/asmjit.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/core/api-build_p.h +55 -0
- data/ext/asmjit/asmjit/src/asmjit/core/api-config.h +613 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archcommons.h +229 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archtraits.cpp +160 -0
- data/ext/asmjit/asmjit/src/asmjit/core/archtraits.h +290 -0
- data/ext/asmjit/asmjit/src/asmjit/core/assembler.cpp +406 -0
- data/ext/asmjit/asmjit/src/asmjit/core/assembler.h +129 -0
- data/ext/asmjit/asmjit/src/asmjit/core/builder.cpp +889 -0
- data/ext/asmjit/asmjit/src/asmjit/core/builder.h +1391 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codebuffer.h +113 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codeholder.cpp +1149 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codeholder.h +1035 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codewriter.cpp +175 -0
- data/ext/asmjit/asmjit/src/asmjit/core/codewriter_p.h +179 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compiler.cpp +582 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compiler.h +737 -0
- data/ext/asmjit/asmjit/src/asmjit/core/compilerdefs.h +173 -0
- data/ext/asmjit/asmjit/src/asmjit/core/constpool.cpp +363 -0
- data/ext/asmjit/asmjit/src/asmjit/core/constpool.h +250 -0
- data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.cpp +1162 -0
- data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.h +813 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emithelper.cpp +323 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emithelper_p.h +58 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitter.cpp +333 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitter.h +741 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitterutils.cpp +129 -0
- data/ext/asmjit/asmjit/src/asmjit/core/emitterutils_p.h +89 -0
- data/ext/asmjit/asmjit/src/asmjit/core/environment.cpp +46 -0
- data/ext/asmjit/asmjit/src/asmjit/core/environment.h +508 -0
- data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.cpp +14 -0
- data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.h +228 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter.cpp +584 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter.h +247 -0
- data/ext/asmjit/asmjit/src/asmjit/core/formatter_p.h +34 -0
- data/ext/asmjit/asmjit/src/asmjit/core/func.cpp +286 -0
- data/ext/asmjit/asmjit/src/asmjit/core/func.h +1445 -0
- data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext.cpp +293 -0
- data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext_p.h +199 -0
- data/ext/asmjit/asmjit/src/asmjit/core/globals.cpp +133 -0
- data/ext/asmjit/asmjit/src/asmjit/core/globals.h +393 -0
- data/ext/asmjit/asmjit/src/asmjit/core/inst.cpp +113 -0
- data/ext/asmjit/asmjit/src/asmjit/core/inst.h +772 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.cpp +1242 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.h +261 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.cpp +80 -0
- data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.h +89 -0
- data/ext/asmjit/asmjit/src/asmjit/core/logger.cpp +69 -0
- data/ext/asmjit/asmjit/src/asmjit/core/logger.h +198 -0
- data/ext/asmjit/asmjit/src/asmjit/core/misc_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/core/operand.cpp +132 -0
- data/ext/asmjit/asmjit/src/asmjit/core/operand.h +1611 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils.cpp +84 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils.h +61 -0
- data/ext/asmjit/asmjit/src/asmjit/core/osutils_p.h +68 -0
- data/ext/asmjit/asmjit/src/asmjit/core/raassignment_p.h +418 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rabuilders_p.h +612 -0
- data/ext/asmjit/asmjit/src/asmjit/core/radefs_p.h +1204 -0
- data/ext/asmjit/asmjit/src/asmjit/core/ralocal.cpp +1166 -0
- data/ext/asmjit/asmjit/src/asmjit/core/ralocal_p.h +254 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rapass.cpp +1969 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rapass_p.h +1183 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rastack.cpp +184 -0
- data/ext/asmjit/asmjit/src/asmjit/core/rastack_p.h +171 -0
- data/ext/asmjit/asmjit/src/asmjit/core/string.cpp +559 -0
- data/ext/asmjit/asmjit/src/asmjit/core/string.h +372 -0
- data/ext/asmjit/asmjit/src/asmjit/core/support.cpp +494 -0
- data/ext/asmjit/asmjit/src/asmjit/core/support.h +1773 -0
- data/ext/asmjit/asmjit/src/asmjit/core/target.cpp +14 -0
- data/ext/asmjit/asmjit/src/asmjit/core/target.h +53 -0
- data/ext/asmjit/asmjit/src/asmjit/core/type.cpp +74 -0
- data/ext/asmjit/asmjit/src/asmjit/core/type.h +419 -0
- data/ext/asmjit/asmjit/src/asmjit/core/virtmem.cpp +722 -0
- data/ext/asmjit/asmjit/src/asmjit/core/virtmem.h +242 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zone.cpp +353 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zone.h +615 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonehash.cpp +309 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonehash.h +186 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonelist.cpp +163 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonelist.h +209 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestack.cpp +176 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestack.h +239 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonestring.h +120 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonetree.cpp +99 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonetree.h +380 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonevector.cpp +356 -0
- data/ext/asmjit/asmjit/src/asmjit/core/zonevector.h +690 -0
- data/ext/asmjit/asmjit/src/asmjit/core.h +1861 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86archtraits_p.h +148 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.cpp +5110 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.h +685 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.cpp +52 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.h +351 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.cpp +61 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.h +721 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper.cpp +619 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper_p.h +60 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86emitter.h +4315 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter.cpp +944 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter_p.h +58 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86func.cpp +503 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86func_p.h +33 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86globals.h +2169 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi.cpp +1732 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi_p.h +41 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.cpp +4427 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.h +563 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb_p.h +311 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86opcode_p.h +436 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.cpp +231 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.h +1085 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass.cpp +1509 -0
- data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass_p.h +94 -0
- data/ext/asmjit/asmjit/src/asmjit/x86.h +93 -0
- data/ext/asmjit/asmjit/src/asmjit.natvis +245 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler.cpp +84 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler.h +85 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_a64.cpp +4006 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_x64.cpp +17833 -0
- data/ext/asmjit/asmjit/test/asmjit_test_assembler_x86.cpp +8300 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler.cpp +253 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler.h +73 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler_a64.cpp +690 -0
- data/ext/asmjit/asmjit/test/asmjit_test_compiler_x86.cpp +4317 -0
- data/ext/asmjit/asmjit/test/asmjit_test_emitters.cpp +197 -0
- data/ext/asmjit/asmjit/test/asmjit_test_instinfo.cpp +181 -0
- data/ext/asmjit/asmjit/test/asmjit_test_misc.h +257 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf.cpp +62 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf.h +61 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf_a64.cpp +699 -0
- data/ext/asmjit/asmjit/test/asmjit_test_perf_x86.cpp +5032 -0
- data/ext/asmjit/asmjit/test/asmjit_test_unit.cpp +172 -0
- data/ext/asmjit/asmjit/test/asmjit_test_x86_sections.cpp +172 -0
- data/ext/asmjit/asmjit/test/asmjitutils.h +38 -0
- data/ext/asmjit/asmjit/test/broken.cpp +312 -0
- data/ext/asmjit/asmjit/test/broken.h +148 -0
- data/ext/asmjit/asmjit/test/cmdline.h +61 -0
- data/ext/asmjit/asmjit/test/performancetimer.h +41 -0
- data/ext/asmjit/asmjit/tools/configure-makefiles.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-ninja.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-sanitizers.sh +13 -0
- data/ext/asmjit/asmjit/tools/configure-vs2019-x64.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2019-x86.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2022-x64.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-vs2022-x86.bat +2 -0
- data/ext/asmjit/asmjit/tools/configure-xcode.sh +8 -0
- data/ext/asmjit/asmjit/tools/enumgen.js +417 -0
- data/ext/asmjit/asmjit/tools/enumgen.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen-arm.js +365 -0
- data/ext/asmjit/asmjit/tools/tablegen-arm.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen-x86.js +2638 -0
- data/ext/asmjit/asmjit/tools/tablegen-x86.sh +3 -0
- data/ext/asmjit/asmjit/tools/tablegen.js +947 -0
- data/ext/asmjit/asmjit/tools/tablegen.sh +4 -0
- data/ext/asmjit/asmjit.cc +18 -0
- data/lib/asmjit/version.rb +1 -1
- metadata +197 -2
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
// This file is part of AsmJit project <https://asmjit.com>
|
|
2
|
+
//
|
|
3
|
+
// See asmjit.h or LICENSE.md for license and copyright information
|
|
4
|
+
// SPDX-License-Identifier: Zlib
|
|
5
|
+
|
|
6
|
+
#include "../core/api-build_p.h"
|
|
7
|
+
#ifndef ASMJIT_NO_JIT
|
|
8
|
+
|
|
9
|
+
#include "../core/osutils.h"
|
|
10
|
+
#include "../core/string.h"
|
|
11
|
+
#include "../core/support.h"
|
|
12
|
+
#include "../core/virtmem.h"
|
|
13
|
+
|
|
14
|
+
#if !defined(_WIN32)
|
|
15
|
+
#include <errno.h>
|
|
16
|
+
#include <fcntl.h>
|
|
17
|
+
#include <sys/mman.h>
|
|
18
|
+
#include <sys/stat.h>
|
|
19
|
+
#include <sys/types.h>
|
|
20
|
+
#include <unistd.h>
|
|
21
|
+
|
|
22
|
+
// Linux has a `memfd_create` syscall that we would like to use, if available.
|
|
23
|
+
#if defined(__linux__)
|
|
24
|
+
#include <sys/syscall.h>
|
|
25
|
+
#endif
|
|
26
|
+
|
|
27
|
+
// Apple recently introduced MAP_JIT flag, which we want to use.
|
|
28
|
+
#if defined(__APPLE__)
|
|
29
|
+
#include <pthread.h>
|
|
30
|
+
#include <TargetConditionals.h>
|
|
31
|
+
#if TARGET_OS_OSX
|
|
32
|
+
#include <sys/utsname.h>
|
|
33
|
+
#include <libkern/OSCacheControl.h> // sys_icache_invalidate().
|
|
34
|
+
#endif
|
|
35
|
+
// Older SDK doesn't define `MAP_JIT`.
|
|
36
|
+
#ifndef MAP_JIT
|
|
37
|
+
#define MAP_JIT 0x800
|
|
38
|
+
#endif
|
|
39
|
+
#endif
|
|
40
|
+
|
|
41
|
+
// BSD/MAC: `MAP_ANONYMOUS` is not defined, `MAP_ANON` is.
|
|
42
|
+
#if !defined(MAP_ANONYMOUS)
|
|
43
|
+
#define MAP_ANONYMOUS MAP_ANON
|
|
44
|
+
#endif
|
|
45
|
+
#endif
|
|
46
|
+
|
|
47
|
+
#include <atomic>
|
|
48
|
+
|
|
49
|
+
#if defined(__APPLE__) || defined(__BIONIC__)
|
|
50
|
+
#define ASMJIT_VM_SHM_DETECT 0
|
|
51
|
+
#else
|
|
52
|
+
#define ASMJIT_VM_SHM_DETECT 1
|
|
53
|
+
#endif
|
|
54
|
+
|
|
55
|
+
// Android NDK doesn't provide `shm_open()` and `shm_unlink()`.
|
|
56
|
+
#if defined(__BIONIC__)
|
|
57
|
+
#define ASMJIT_VM_SHM_AVAILABLE 0
|
|
58
|
+
#else
|
|
59
|
+
#define ASMJIT_VM_SHM_AVAILABLE 1
|
|
60
|
+
#endif
|
|
61
|
+
|
|
62
|
+
#if defined(__APPLE__) && ASMJIT_ARCH_ARM >= 64
|
|
63
|
+
#define ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP
|
|
64
|
+
#endif
|
|
65
|
+
|
|
66
|
+
ASMJIT_BEGIN_SUB_NAMESPACE(VirtMem)
|
|
67
|
+
|
|
68
|
+
// Virtual Memory Utilities
|
|
69
|
+
// ========================
|
|
70
|
+
|
|
71
|
+
static const MemoryFlags dualMappingFilter[2] = {
|
|
72
|
+
MemoryFlags::kAccessWrite | MemoryFlags::kMMapMaxAccessWrite,
|
|
73
|
+
MemoryFlags::kAccessExecute | MemoryFlags::kMMapMaxAccessExecute
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Virtual Memory [Windows]
|
|
77
|
+
// ========================
|
|
78
|
+
|
|
79
|
+
#if defined(_WIN32)
|
|
80
|
+
|
|
81
|
+
struct ScopedHandle {
|
|
82
|
+
inline ScopedHandle() noexcept
|
|
83
|
+
: value(nullptr) {}
|
|
84
|
+
|
|
85
|
+
inline ~ScopedHandle() noexcept {
|
|
86
|
+
if (value != nullptr)
|
|
87
|
+
::CloseHandle(value);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
HANDLE value;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
static void getVMInfo(Info& vmInfo) noexcept {
|
|
94
|
+
SYSTEM_INFO systemInfo;
|
|
95
|
+
|
|
96
|
+
::GetSystemInfo(&systemInfo);
|
|
97
|
+
vmInfo.pageSize = Support::alignUpPowerOf2<uint32_t>(systemInfo.dwPageSize);
|
|
98
|
+
vmInfo.pageGranularity = systemInfo.dwAllocationGranularity;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Returns windows-specific protectFlags from \ref MemoryFlags.
|
|
102
|
+
static DWORD protectFlagsFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
|
|
103
|
+
DWORD protectFlags;
|
|
104
|
+
|
|
105
|
+
// READ|WRITE|EXECUTE.
|
|
106
|
+
if (Support::test(memoryFlags, MemoryFlags::kAccessExecute))
|
|
107
|
+
protectFlags = Support::test(memoryFlags, MemoryFlags::kAccessWrite) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
|
108
|
+
else if (Support::test(memoryFlags, MemoryFlags::kAccessRW))
|
|
109
|
+
protectFlags = Support::test(memoryFlags, MemoryFlags::kAccessWrite) ? PAGE_READWRITE : PAGE_READONLY;
|
|
110
|
+
else
|
|
111
|
+
protectFlags = PAGE_NOACCESS;
|
|
112
|
+
|
|
113
|
+
// Any other flags to consider?
|
|
114
|
+
return protectFlags;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static DWORD desiredAccessFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
|
|
118
|
+
DWORD access = Support::test(memoryFlags, MemoryFlags::kAccessWrite) ? FILE_MAP_WRITE : FILE_MAP_READ;
|
|
119
|
+
if (Support::test(memoryFlags, MemoryFlags::kAccessExecute))
|
|
120
|
+
access |= FILE_MAP_EXECUTE;
|
|
121
|
+
return access;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static HardenedRuntimeFlags getHardenedRuntimeFlags() noexcept {
|
|
125
|
+
return HardenedRuntimeFlags::kNone;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
Error alloc(void** p, size_t size, MemoryFlags memoryFlags) noexcept {
|
|
129
|
+
*p = nullptr;
|
|
130
|
+
if (size == 0)
|
|
131
|
+
return DebugUtils::errored(kErrorInvalidArgument);
|
|
132
|
+
|
|
133
|
+
DWORD protectFlags = protectFlagsFromMemoryFlags(memoryFlags);
|
|
134
|
+
void* result = ::VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, protectFlags);
|
|
135
|
+
|
|
136
|
+
if (!result)
|
|
137
|
+
return DebugUtils::errored(kErrorOutOfMemory);
|
|
138
|
+
|
|
139
|
+
*p = result;
|
|
140
|
+
return kErrorOk;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
Error release(void* p, size_t size) noexcept {
|
|
144
|
+
DebugUtils::unused(size);
|
|
145
|
+
if (ASMJIT_UNLIKELY(!::VirtualFree(p, 0, MEM_RELEASE)))
|
|
146
|
+
return DebugUtils::errored(kErrorInvalidArgument);
|
|
147
|
+
return kErrorOk;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
Error protect(void* p, size_t size, MemoryFlags memoryFlags) noexcept {
|
|
151
|
+
DWORD protectFlags = protectFlagsFromMemoryFlags(memoryFlags);
|
|
152
|
+
DWORD oldFlags;
|
|
153
|
+
|
|
154
|
+
if (::VirtualProtect(p, size, protectFlags, &oldFlags))
|
|
155
|
+
return kErrorOk;
|
|
156
|
+
|
|
157
|
+
return DebugUtils::errored(kErrorInvalidArgument);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
Error allocDualMapping(DualMapping* dm, size_t size, MemoryFlags memoryFlags) noexcept {
|
|
161
|
+
dm->rx = nullptr;
|
|
162
|
+
dm->rw = nullptr;
|
|
163
|
+
|
|
164
|
+
if (size == 0)
|
|
165
|
+
return DebugUtils::errored(kErrorInvalidArgument);
|
|
166
|
+
|
|
167
|
+
ScopedHandle handle;
|
|
168
|
+
handle.value = ::CreateFileMappingW(
|
|
169
|
+
INVALID_HANDLE_VALUE,
|
|
170
|
+
nullptr,
|
|
171
|
+
PAGE_EXECUTE_READWRITE,
|
|
172
|
+
(DWORD)(uint64_t(size) >> 32),
|
|
173
|
+
(DWORD)(size & 0xFFFFFFFFu),
|
|
174
|
+
nullptr);
|
|
175
|
+
|
|
176
|
+
if (ASMJIT_UNLIKELY(!handle.value))
|
|
177
|
+
return DebugUtils::errored(kErrorOutOfMemory);
|
|
178
|
+
|
|
179
|
+
void* ptr[2];
|
|
180
|
+
for (uint32_t i = 0; i < 2; i++) {
|
|
181
|
+
MemoryFlags accessFlags = memoryFlags & ~dualMappingFilter[i];
|
|
182
|
+
DWORD desiredAccess = desiredAccessFromMemoryFlags(accessFlags);
|
|
183
|
+
ptr[i] = ::MapViewOfFile(handle.value, desiredAccess, 0, 0, size);
|
|
184
|
+
|
|
185
|
+
if (ptr[i] == nullptr) {
|
|
186
|
+
if (i == 0)
|
|
187
|
+
::UnmapViewOfFile(ptr[0]);
|
|
188
|
+
return DebugUtils::errored(kErrorOutOfMemory);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
dm->rx = ptr[0];
|
|
193
|
+
dm->rw = ptr[1];
|
|
194
|
+
return kErrorOk;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
Error releaseDualMapping(DualMapping* dm, size_t size) noexcept {
|
|
198
|
+
DebugUtils::unused(size);
|
|
199
|
+
bool failed = false;
|
|
200
|
+
|
|
201
|
+
if (!::UnmapViewOfFile(dm->rx))
|
|
202
|
+
failed = true;
|
|
203
|
+
|
|
204
|
+
if (dm->rx != dm->rw && !UnmapViewOfFile(dm->rw))
|
|
205
|
+
failed = true;
|
|
206
|
+
|
|
207
|
+
if (failed)
|
|
208
|
+
return DebugUtils::errored(kErrorInvalidArgument);
|
|
209
|
+
|
|
210
|
+
dm->rx = nullptr;
|
|
211
|
+
dm->rw = nullptr;
|
|
212
|
+
return kErrorOk;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
#endif
|
|
216
|
+
|
|
217
|
+
// Virtual Memory [Posix]
|
|
218
|
+
// ======================
|
|
219
|
+
|
|
220
|
+
#if !defined(_WIN32)
|
|
221
|
+
|
|
222
|
+
static void getVMInfo(Info& vmInfo) noexcept {
|
|
223
|
+
uint32_t pageSize = uint32_t(::getpagesize());
|
|
224
|
+
|
|
225
|
+
vmInfo.pageSize = pageSize;
|
|
226
|
+
vmInfo.pageGranularity = Support::max<uint32_t>(pageSize, 65536);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
#if !defined(SHM_ANON)
|
|
230
|
+
static const char* getTmpDir() noexcept {
|
|
231
|
+
const char* tmpDir = getenv("TMPDIR");
|
|
232
|
+
return tmpDir ? tmpDir : "/tmp";
|
|
233
|
+
}
|
|
234
|
+
#endif
|
|
235
|
+
|
|
236
|
+
// Translates libc errors specific to VirtualMemory mapping to `asmjit::Error`.
|
|
237
|
+
static Error asmjitErrorFromErrno(int e) noexcept {
|
|
238
|
+
switch (e) {
|
|
239
|
+
case EACCES:
|
|
240
|
+
case EAGAIN:
|
|
241
|
+
case ENODEV:
|
|
242
|
+
case EPERM:
|
|
243
|
+
return kErrorInvalidState;
|
|
244
|
+
|
|
245
|
+
case EFBIG:
|
|
246
|
+
case ENOMEM:
|
|
247
|
+
case EOVERFLOW:
|
|
248
|
+
return kErrorOutOfMemory;
|
|
249
|
+
|
|
250
|
+
case EMFILE:
|
|
251
|
+
case ENFILE:
|
|
252
|
+
return kErrorTooManyHandles;
|
|
253
|
+
|
|
254
|
+
default:
|
|
255
|
+
return kErrorInvalidArgument;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Some operating systems don't allow /dev/shm to be executable. On Linux this happens when /dev/shm is mounted with
|
|
260
|
+
// 'noexec', which is enforced by systemd. Other operating systems like MacOS also restrict executable permissions
|
|
261
|
+
// regarding /dev/shm, so we use a runtime detection before attempting to allocate executable memory. Sometimes we
|
|
262
|
+
// don't need the detection as we know it would always result in `ShmStrategy::kTmpDir`.
|
|
263
|
+
enum class ShmStrategy : uint32_t {
|
|
264
|
+
kUnknown = 0,
|
|
265
|
+
kDevShm = 1,
|
|
266
|
+
kTmpDir = 2
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
class AnonymousMemory {
|
|
270
|
+
public:
|
|
271
|
+
enum FileType : uint32_t {
|
|
272
|
+
kFileTypeNone,
|
|
273
|
+
kFileTypeShm,
|
|
274
|
+
kFileTypeTmp
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
int _fd;
|
|
278
|
+
FileType _fileType;
|
|
279
|
+
StringTmp<128> _tmpName;
|
|
280
|
+
|
|
281
|
+
inline AnonymousMemory() noexcept
|
|
282
|
+
: _fd(-1),
|
|
283
|
+
_fileType(kFileTypeNone),
|
|
284
|
+
_tmpName() {}
|
|
285
|
+
|
|
286
|
+
inline ~AnonymousMemory() noexcept {
|
|
287
|
+
unlink();
|
|
288
|
+
close();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
inline int fd() const noexcept { return _fd; }
|
|
292
|
+
|
|
293
|
+
Error open(bool preferTmpOverDevShm) noexcept {
|
|
294
|
+
#if defined(__linux__) && defined(__NR_memfd_create)
|
|
295
|
+
// Linux specific 'memfd_create' - if the syscall returns `ENOSYS` it means
|
|
296
|
+
// it's not available and we will never call it again (would be pointless).
|
|
297
|
+
|
|
298
|
+
// Zero initialized, if ever changed to '1' that would mean the syscall is not
|
|
299
|
+
// available and we must use `shm_open()` and `shm_unlink()`.
|
|
300
|
+
static volatile uint32_t memfd_create_not_supported;
|
|
301
|
+
|
|
302
|
+
if (!memfd_create_not_supported) {
|
|
303
|
+
_fd = (int)syscall(__NR_memfd_create, "vmem", 0);
|
|
304
|
+
if (ASMJIT_LIKELY(_fd >= 0))
|
|
305
|
+
return kErrorOk;
|
|
306
|
+
|
|
307
|
+
int e = errno;
|
|
308
|
+
if (e == ENOSYS)
|
|
309
|
+
memfd_create_not_supported = 1;
|
|
310
|
+
else
|
|
311
|
+
return DebugUtils::errored(asmjitErrorFromErrno(e));
|
|
312
|
+
}
|
|
313
|
+
#endif
|
|
314
|
+
|
|
315
|
+
#if defined(SHM_ANON)
|
|
316
|
+
// Originally FreeBSD extension, apparently works in other BSDs too.
|
|
317
|
+
DebugUtils::unused(preferTmpOverDevShm);
|
|
318
|
+
_fd = ::shm_open(SHM_ANON, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
|
319
|
+
|
|
320
|
+
if (ASMJIT_LIKELY(_fd >= 0))
|
|
321
|
+
return kErrorOk;
|
|
322
|
+
else
|
|
323
|
+
return DebugUtils::errored(asmjitErrorFromErrno(errno));
|
|
324
|
+
#else
|
|
325
|
+
// POSIX API. We have to generate somehow a unique name. This is nothing cryptographic, just using a bit from
|
|
326
|
+
// the stack address to always have a different base for different threads (as threads have their own stack)
|
|
327
|
+
// and retries for avoiding collisions. We use `shm_open()` with flags that require creation of the file so we
|
|
328
|
+
// never open an existing shared memory.
|
|
329
|
+
static std::atomic<uint32_t> internalCounter;
|
|
330
|
+
const char* kShmFormat = "/shm-id-%016llX";
|
|
331
|
+
|
|
332
|
+
uint32_t kRetryCount = 100;
|
|
333
|
+
uint64_t bits = ((uintptr_t)(void*)this) & 0x55555555u;
|
|
334
|
+
|
|
335
|
+
for (uint32_t i = 0; i < kRetryCount; i++) {
|
|
336
|
+
bits -= uint64_t(OSUtils::getTickCount()) * 773703683;
|
|
337
|
+
bits = ((bits >> 14) ^ (bits << 6)) + uint64_t(++internalCounter) * 10619863;
|
|
338
|
+
|
|
339
|
+
bool useTmp = !ASMJIT_VM_SHM_DETECT || preferTmpOverDevShm;
|
|
340
|
+
|
|
341
|
+
if (useTmp) {
|
|
342
|
+
_tmpName.assign(getTmpDir());
|
|
343
|
+
_tmpName.appendFormat(kShmFormat, (unsigned long long)bits);
|
|
344
|
+
_fd = ::open(_tmpName.data(), O_RDWR | O_CREAT | O_EXCL, 0);
|
|
345
|
+
if (ASMJIT_LIKELY(_fd >= 0)) {
|
|
346
|
+
_fileType = kFileTypeTmp;
|
|
347
|
+
return kErrorOk;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
#if ASMJIT_VM_SHM_AVAILABLE
|
|
351
|
+
else {
|
|
352
|
+
_tmpName.assignFormat(kShmFormat, (unsigned long long)bits);
|
|
353
|
+
_fd = ::shm_open(_tmpName.data(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
|
|
354
|
+
if (ASMJIT_LIKELY(_fd >= 0)) {
|
|
355
|
+
_fileType = kFileTypeShm;
|
|
356
|
+
return kErrorOk;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
#endif
|
|
360
|
+
|
|
361
|
+
int e = errno;
|
|
362
|
+
if (e != EEXIST)
|
|
363
|
+
return DebugUtils::errored(asmjitErrorFromErrno(e));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return DebugUtils::errored(kErrorFailedToOpenAnonymousMemory);
|
|
367
|
+
#endif
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
void unlink() noexcept {
|
|
371
|
+
FileType type = _fileType;
|
|
372
|
+
_fileType = kFileTypeNone;
|
|
373
|
+
|
|
374
|
+
#if ASMJIT_VM_SHM_AVAILABLE
|
|
375
|
+
if (type == kFileTypeShm) {
|
|
376
|
+
::shm_unlink(_tmpName.data());
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
#endif
|
|
380
|
+
|
|
381
|
+
if (type == kFileTypeTmp) {
|
|
382
|
+
::unlink(_tmpName.data());
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
void close() noexcept {
|
|
388
|
+
if (_fd >= 0) {
|
|
389
|
+
::close(_fd);
|
|
390
|
+
_fd = -1;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
Error allocate(size_t size) noexcept {
|
|
395
|
+
// TODO: Improve this by using `posix_fallocate()` when available.
|
|
396
|
+
if (ftruncate(_fd, off_t(size)) != 0)
|
|
397
|
+
return DebugUtils::errored(asmjitErrorFromErrno(errno));
|
|
398
|
+
|
|
399
|
+
return kErrorOk;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// Returns `mmap()` protection flags from \ref MemoryFlags.
|
|
404
|
+
static int mmProtFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
|
|
405
|
+
int protection = 0;
|
|
406
|
+
if (Support::test(memoryFlags, MemoryFlags::kAccessRead)) protection |= PROT_READ;
|
|
407
|
+
if (Support::test(memoryFlags, MemoryFlags::kAccessWrite)) protection |= PROT_READ | PROT_WRITE;
|
|
408
|
+
if (Support::test(memoryFlags, MemoryFlags::kAccessExecute)) protection |= PROT_READ | PROT_EXEC;
|
|
409
|
+
return protection;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
#if defined(__APPLE__)
|
|
413
|
+
// Detects whether the current process is hardened, which means that pages that have WRITE and EXECUTABLE flags cannot
|
|
414
|
+
// be allocated without MAP_JIT flag.
|
|
415
|
+
static inline bool hasHardenedRuntimeMacOS() noexcept {
|
|
416
|
+
#if TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64
|
|
417
|
+
// MacOS on AArch64 has always hardened runtime enabled.
|
|
418
|
+
return true;
|
|
419
|
+
#else
|
|
420
|
+
static std::atomic<uint32_t> globalHardenedFlag;
|
|
421
|
+
|
|
422
|
+
enum HardenedFlag : uint32_t {
|
|
423
|
+
kHardenedFlagUnknown = 0,
|
|
424
|
+
kHardenedFlagDisabled = 1,
|
|
425
|
+
kHardenedFlagEnabled = 2
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
uint32_t flag = globalHardenedFlag.load();
|
|
429
|
+
if (flag == kHardenedFlagUnknown) {
|
|
430
|
+
size_t pageSize = ::getpagesize();
|
|
431
|
+
|
|
432
|
+
void* ptr = mmap(nullptr, pageSize, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
433
|
+
if (ptr == MAP_FAILED) {
|
|
434
|
+
flag = kHardenedFlagEnabled;
|
|
435
|
+
}
|
|
436
|
+
else {
|
|
437
|
+
flag = kHardenedFlagDisabled;
|
|
438
|
+
munmap(ptr, pageSize);
|
|
439
|
+
}
|
|
440
|
+
globalHardenedFlag.store(flag);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return flag == kHardenedFlagEnabled;
|
|
444
|
+
#endif
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
static inline bool hasMapJitSupportMacOS() noexcept {
|
|
448
|
+
#if TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64
|
|
449
|
+
// MacOS for 64-bit AArch architecture always uses hardened runtime. Some documentation can be found here:
|
|
450
|
+
// - https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon
|
|
451
|
+
return true;
|
|
452
|
+
#elif TARGET_OS_OSX
|
|
453
|
+
// MAP_JIT flag required to run unsigned JIT code is only supported by kernel version 10.14+ (Mojave) and IOS.
|
|
454
|
+
static std::atomic<uint32_t> globalVersion;
|
|
455
|
+
|
|
456
|
+
int ver = globalVersion.load();
|
|
457
|
+
if (!ver) {
|
|
458
|
+
struct utsname osname {};
|
|
459
|
+
uname(&osname);
|
|
460
|
+
ver = atoi(osname.release);
|
|
461
|
+
globalVersion.store(ver);
|
|
462
|
+
}
|
|
463
|
+
return ver >= 18;
|
|
464
|
+
#else
|
|
465
|
+
// Assume it's available.
|
|
466
|
+
return true;
|
|
467
|
+
#endif
|
|
468
|
+
}
|
|
469
|
+
#endif // __APPLE__
|
|
470
|
+
|
|
471
|
+
// Detects whether the current process is hardened, which means that pages that have WRITE and EXECUTABLE flags
|
|
472
|
+
// cannot be normally allocated. On MacOS such allocation requires MAP_JIT flag.
|
|
473
|
+
static inline bool hasHardenedRuntime() noexcept {
|
|
474
|
+
#if defined(__APPLE__)
|
|
475
|
+
return hasHardenedRuntimeMacOS();
|
|
476
|
+
#else
|
|
477
|
+
return false;
|
|
478
|
+
#endif
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Detects whether MAP_JIT is available.
|
|
482
|
+
static inline bool hasMapJitSupport() noexcept {
|
|
483
|
+
#if defined(__APPLE__)
|
|
484
|
+
return hasMapJitSupportMacOS();
|
|
485
|
+
#else
|
|
486
|
+
return false;
|
|
487
|
+
#endif
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Returns either MAP_JIT or 0 based on `flags` and the host operating system.
|
|
491
|
+
static inline int mmMapJitFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
|
|
492
|
+
#if defined(__APPLE__)
|
|
493
|
+
// Always use MAP_JIT flag if user asked for it (could be used for testing on non-hardened processes) and detect
|
|
494
|
+
// whether it must be used when the process is actually hardened (in that case it doesn't make sense to rely on
|
|
495
|
+
// user `memoryFlags`).
|
|
496
|
+
bool useMapJit = Support::test(memoryFlags, MemoryFlags::kMMapEnableMapJit) || hasHardenedRuntime();
|
|
497
|
+
if (useMapJit)
|
|
498
|
+
return hasMapJitSupport() ? int(MAP_JIT) : 0;
|
|
499
|
+
else
|
|
500
|
+
return 0;
|
|
501
|
+
#else
|
|
502
|
+
DebugUtils::unused(memoryFlags);
|
|
503
|
+
return 0;
|
|
504
|
+
#endif
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Returns BSD-specific `PROT_MAX()` flags.
|
|
508
|
+
static inline int mmMaxProtFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
|
|
509
|
+
#if defined(PROT_MAX)
|
|
510
|
+
static constexpr uint32_t kMaxProtShift = Support::ConstCTZ<uint32_t(MemoryFlags::kMMapMaxAccessRead)>::value;
|
|
511
|
+
|
|
512
|
+
if (Support::test(memoryFlags, MemoryFlags::kMMapMaxAccessReadWrite | MemoryFlags::kMMapMaxAccessExecute))
|
|
513
|
+
return PROT_MAX(mmProtFromMemoryFlags((MemoryFlags)(uint32_t(memoryFlags) >> kMaxProtShift)));
|
|
514
|
+
else
|
|
515
|
+
return 0;
|
|
516
|
+
#else
|
|
517
|
+
DebugUtils::unused(memoryFlags);
|
|
518
|
+
return 0;
|
|
519
|
+
#endif
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
#if ASMJIT_VM_SHM_DETECT
|
|
523
|
+
static Error detectShmStrategy(ShmStrategy* strategyOut) noexcept {
|
|
524
|
+
AnonymousMemory anonMem;
|
|
525
|
+
Info vmInfo = info();
|
|
526
|
+
|
|
527
|
+
ASMJIT_PROPAGATE(anonMem.open(false));
|
|
528
|
+
ASMJIT_PROPAGATE(anonMem.allocate(vmInfo.pageSize));
|
|
529
|
+
|
|
530
|
+
void* ptr = mmap(nullptr, vmInfo.pageSize, PROT_READ | PROT_EXEC, MAP_SHARED, anonMem.fd(), 0);
|
|
531
|
+
if (ptr == MAP_FAILED) {
|
|
532
|
+
int e = errno;
|
|
533
|
+
if (e == EINVAL) {
|
|
534
|
+
*strategyOut = ShmStrategy::kTmpDir;
|
|
535
|
+
return kErrorOk;
|
|
536
|
+
}
|
|
537
|
+
return DebugUtils::errored(asmjitErrorFromErrno(e));
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
munmap(ptr, vmInfo.pageSize);
|
|
541
|
+
*strategyOut = ShmStrategy::kDevShm;
|
|
542
|
+
return kErrorOk;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
#endif
|
|
546
|
+
|
|
547
|
+
static Error getShmStrategy(ShmStrategy* strategyOut) noexcept {
|
|
548
|
+
#if ASMJIT_VM_SHM_DETECT
|
|
549
|
+
// Initially don't assume anything. It has to be tested whether '/dev/shm' was mounted with 'noexec' flag or not.
|
|
550
|
+
static std::atomic<uint32_t> globalShmStrategy;
|
|
551
|
+
|
|
552
|
+
ShmStrategy strategy = static_cast<ShmStrategy>(globalShmStrategy.load());
|
|
553
|
+
if (strategy == ShmStrategy::kUnknown) {
|
|
554
|
+
ASMJIT_PROPAGATE(detectShmStrategy(&strategy));
|
|
555
|
+
globalShmStrategy.store(static_cast<uint32_t>(strategy));
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
*strategyOut = strategy;
|
|
559
|
+
return kErrorOk;
|
|
560
|
+
#else
|
|
561
|
+
*strategyOut = ShmStrategy::kTmpDir;
|
|
562
|
+
return kErrorOk;
|
|
563
|
+
#endif
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
static HardenedRuntimeFlags getHardenedRuntimeFlags() noexcept {
|
|
567
|
+
HardenedRuntimeFlags hrFlags = HardenedRuntimeFlags::kNone;
|
|
568
|
+
|
|
569
|
+
if (hasHardenedRuntime())
|
|
570
|
+
hrFlags |= HardenedRuntimeFlags::kEnabled;
|
|
571
|
+
|
|
572
|
+
if (hasMapJitSupport())
|
|
573
|
+
hrFlags |= HardenedRuntimeFlags::kMapJit;
|
|
574
|
+
|
|
575
|
+
return hrFlags;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
Error alloc(void** p, size_t size, MemoryFlags memoryFlags) noexcept {
|
|
579
|
+
*p = nullptr;
|
|
580
|
+
if (size == 0)
|
|
581
|
+
return DebugUtils::errored(kErrorInvalidArgument);
|
|
582
|
+
|
|
583
|
+
int protection = mmProtFromMemoryFlags(memoryFlags) | mmMaxProtFromMemoryFlags(memoryFlags);
|
|
584
|
+
int mmFlags = MAP_PRIVATE | MAP_ANONYMOUS | mmMapJitFromMemoryFlags(memoryFlags);
|
|
585
|
+
|
|
586
|
+
void* ptr = mmap(nullptr, size, protection, mmFlags, -1, 0);
|
|
587
|
+
if (ptr == MAP_FAILED)
|
|
588
|
+
return DebugUtils::errored(kErrorOutOfMemory);
|
|
589
|
+
|
|
590
|
+
*p = ptr;
|
|
591
|
+
return kErrorOk;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
Error release(void* p, size_t size) noexcept {
|
|
595
|
+
if (ASMJIT_UNLIKELY(munmap(p, size) != 0))
|
|
596
|
+
return DebugUtils::errored(kErrorInvalidArgument);
|
|
597
|
+
|
|
598
|
+
return kErrorOk;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
Error protect(void* p, size_t size, MemoryFlags memoryFlags) noexcept {
|
|
603
|
+
int protection = mmProtFromMemoryFlags(memoryFlags);
|
|
604
|
+
if (mprotect(p, size, protection) == 0)
|
|
605
|
+
return kErrorOk;
|
|
606
|
+
|
|
607
|
+
return DebugUtils::errored(kErrorInvalidArgument);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
Error allocDualMapping(DualMapping* dm, size_t size, MemoryFlags memoryFlags) noexcept {
|
|
611
|
+
dm->rx = nullptr;
|
|
612
|
+
dm->rw = nullptr;
|
|
613
|
+
|
|
614
|
+
if (off_t(size) <= 0)
|
|
615
|
+
return DebugUtils::errored(size == 0 ? kErrorInvalidArgument : kErrorTooLarge);
|
|
616
|
+
|
|
617
|
+
bool preferTmpOverDevShm = Support::test(memoryFlags, MemoryFlags::kMappingPreferTmp);
|
|
618
|
+
if (!preferTmpOverDevShm) {
|
|
619
|
+
ShmStrategy strategy;
|
|
620
|
+
ASMJIT_PROPAGATE(getShmStrategy(&strategy));
|
|
621
|
+
preferTmpOverDevShm = (strategy == ShmStrategy::kTmpDir);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
AnonymousMemory anonMem;
|
|
625
|
+
ASMJIT_PROPAGATE(anonMem.open(preferTmpOverDevShm));
|
|
626
|
+
ASMJIT_PROPAGATE(anonMem.allocate(size));
|
|
627
|
+
|
|
628
|
+
void* ptr[2];
|
|
629
|
+
for (uint32_t i = 0; i < 2; i++) {
|
|
630
|
+
MemoryFlags accessFlags = memoryFlags & ~dualMappingFilter[i];
|
|
631
|
+
int protection = mmProtFromMemoryFlags(accessFlags) | mmMaxProtFromMemoryFlags(accessFlags);
|
|
632
|
+
|
|
633
|
+
ptr[i] = mmap(nullptr, size, protection, MAP_SHARED, anonMem.fd(), 0);
|
|
634
|
+
if (ptr[i] == MAP_FAILED) {
|
|
635
|
+
// Get the error now before `munmap()` has a chance to clobber it.
|
|
636
|
+
int e = errno;
|
|
637
|
+
if (i == 1)
|
|
638
|
+
munmap(ptr[0], size);
|
|
639
|
+
return DebugUtils::errored(asmjitErrorFromErrno(e));
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
dm->rx = ptr[0];
|
|
644
|
+
dm->rw = ptr[1];
|
|
645
|
+
return kErrorOk;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
Error releaseDualMapping(DualMapping* dm, size_t size) noexcept {
|
|
649
|
+
Error err = release(dm->rx, size);
|
|
650
|
+
if (dm->rx != dm->rw)
|
|
651
|
+
err |= release(dm->rw, size);
|
|
652
|
+
|
|
653
|
+
if (err)
|
|
654
|
+
return DebugUtils::errored(kErrorInvalidArgument);
|
|
655
|
+
|
|
656
|
+
dm->rx = nullptr;
|
|
657
|
+
dm->rw = nullptr;
|
|
658
|
+
return kErrorOk;
|
|
659
|
+
}
|
|
660
|
+
#endif
|
|
661
|
+
|
|
662
|
+
// Virtual Memory - Flush Instruction Cache
|
|
663
|
+
// ========================================
|
|
664
|
+
|
|
665
|
+
void flushInstructionCache(void* p, size_t size) noexcept {
|
|
666
|
+
#if ASMJIT_ARCH_X86
|
|
667
|
+
// X86/X86_64 architecture doesn't require to do anything to flush instruction cache.
|
|
668
|
+
DebugUtils::unused(p, size);
|
|
669
|
+
#elif defined(__APPLE__)
|
|
670
|
+
sys_icache_invalidate(p, size);
|
|
671
|
+
#elif defined(_WIN32)
|
|
672
|
+
// Windows has a built-in support in `kernel32.dll`.
|
|
673
|
+
FlushInstructionCache(GetCurrentProcess(), p, size);
|
|
674
|
+
#elif defined(__GNUC__)
|
|
675
|
+
char* start = static_cast<char*>(p);
|
|
676
|
+
char* end = start + size;
|
|
677
|
+
__builtin___clear_cache(start, end);
|
|
678
|
+
#else
|
|
679
|
+
#pragma message("asmjit::VirtMem::flushInstructionCache() doesn't have implementation for the target OS and compiler")
|
|
680
|
+
DebugUtils::unused(p, size);
|
|
681
|
+
#endif
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// Virtual Memory - Memory Info
|
|
685
|
+
// ============================
|
|
686
|
+
|
|
687
|
+
Info info() noexcept {
|
|
688
|
+
static std::atomic<uint32_t> vmInfoInitialized;
|
|
689
|
+
static Info vmInfo;
|
|
690
|
+
|
|
691
|
+
if (!vmInfoInitialized.load()) {
|
|
692
|
+
Info localMemInfo;
|
|
693
|
+
getVMInfo(localMemInfo);
|
|
694
|
+
|
|
695
|
+
vmInfo = localMemInfo;
|
|
696
|
+
vmInfoInitialized.store(1u);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
return vmInfo;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// Virtual Memory - Hardened Runtime Info
|
|
703
|
+
// ======================================
|
|
704
|
+
|
|
705
|
+
HardenedRuntimeInfo hardenedRuntimeInfo() noexcept {
|
|
706
|
+
return HardenedRuntimeInfo { getHardenedRuntimeFlags() };
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Virtual Memory - Project JIT Memory
|
|
710
|
+
// ===================================
|
|
711
|
+
|
|
712
|
+
void protectJitMemory(ProtectJitAccess access) noexcept {
|
|
713
|
+
#if defined(ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP)
|
|
714
|
+
pthread_jit_write_protect_np(static_cast<uint32_t>(access));
|
|
715
|
+
#else
|
|
716
|
+
DebugUtils::unused(access);
|
|
717
|
+
#endif
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
ASMJIT_END_SUB_NAMESPACE
|
|
721
|
+
|
|
722
|
+
#endif
|