Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/jit/src/memory/mod.rs
3050 views
1
use cranelift_module::{ModuleError, ModuleResult};
2
use std::io;
3
4
mod arena;
5
mod system;
6
7
pub use arena::ArenaMemoryProvider;
8
pub use system::SystemMemoryProvider;
9
10
/// Type of branch protection to apply to executable memory.
11
#[derive(Clone, Copy, Debug, PartialEq)]
12
pub enum BranchProtection {
13
/// No protection.
14
None,
15
/// Use the Branch Target Identification extension of the Arm architecture.
16
BTI,
17
}
18
19
pub enum JITMemoryKind {
20
/// Allocate memory that will be executable once finalized.
21
Executable,
22
/// Allocate writable memory.
23
Writable,
24
/// Allocate memory that will be read-only once finalized.
25
ReadOnly,
26
}
27
28
/// A provider of memory for the JIT.
29
pub trait JITMemoryProvider {
30
/// Allocate memory
31
fn allocate(&mut self, size: usize, align: u64, kind: JITMemoryKind) -> io::Result<*mut u8>;
32
33
/// Free the memory region.
34
unsafe fn free_memory(&mut self);
35
/// Finalize the memory region and apply memory protections.
36
fn finalize(&mut self, branch_protection: BranchProtection) -> ModuleResult<()>;
37
}
38
39
/// Marks the memory region as readable and executable.
40
///
41
/// This function deals with applies branch protection and clears the icache,
42
/// but *doesn't* flush the pipeline. Callers have to ensure that
43
/// [`wasmtime_jit_icache_coherence::pipeline_flush_mt`] is called before the
44
/// mappings are used.
45
pub(crate) fn set_readable_and_executable(
46
ptr: *mut u8,
47
len: usize,
48
branch_protection: BranchProtection,
49
) -> ModuleResult<()> {
50
// Clear all the newly allocated code from cache if the processor requires it
51
//
52
// Do this before marking the memory as R+X, technically we should be able to do it after
53
// but there are some CPU's that have had errata about doing this with read only memory.
54
unsafe {
55
wasmtime_jit_icache_coherence::clear_cache(ptr as *const libc::c_void, len)
56
.expect("Failed cache clear")
57
};
58
59
unsafe {
60
region::protect(ptr, len, region::Protection::READ_EXECUTE).map_err(|e| {
61
ModuleError::Backend(
62
anyhow::Error::new(e).context("unable to make memory readable+executable"),
63
)
64
})?;
65
}
66
67
// If BTI is requested, and the architecture supports it, use mprotect to set the PROT_BTI flag.
68
if branch_protection == BranchProtection::BTI {
69
#[cfg(all(target_arch = "aarch64", target_os = "linux"))]
70
if std::arch::is_aarch64_feature_detected!("bti") {
71
let prot = libc::PROT_EXEC | libc::PROT_READ | /* PROT_BTI */ 0x10;
72
73
unsafe {
74
if libc::mprotect(ptr as *mut libc::c_void, len, prot) < 0 {
75
return Err(ModuleError::Backend(
76
anyhow::Error::new(io::Error::last_os_error())
77
.context("unable to make memory readable+executable"),
78
));
79
}
80
}
81
}
82
}
83
84
Ok(())
85
}
86
87