Path: blob/main/cranelift/jit/src/memory/mod.rs
1692 views
use cranelift_module::{ModuleError, ModuleResult};1use std::io;23mod arena;4mod system;56pub use arena::ArenaMemoryProvider;7pub use system::SystemMemoryProvider;89/// Type of branch protection to apply to executable memory.10#[derive(Clone, Copy, Debug, PartialEq)]11pub enum BranchProtection {12/// No protection.13None,14/// Use the Branch Target Identification extension of the Arm architecture.15BTI,16}1718/// A provider of memory for the JIT.19pub trait JITMemoryProvider {20/// Allocate memory that will be executable once finalized.21fn allocate_readexec(&mut self, size: usize, align: u64) -> io::Result<*mut u8>;22/// Allocate writable memory.23fn allocate_readwrite(&mut self, size: usize, align: u64) -> io::Result<*mut u8>;24/// Allocate memory that will be read-only once finalized.25fn allocate_readonly(&mut self, size: usize, align: u64) -> io::Result<*mut u8>;2627/// Free the memory region.28unsafe fn free_memory(&mut self);29/// Finalize the memory region and apply memory protections.30fn finalize(&mut self, branch_protection: BranchProtection) -> ModuleResult<()>;31}3233/// Marks the memory region as readable and executable.34///35/// This function deals with applies branch protection and clears the icache,36/// but *doesn't* flush the pipeline. Callers have to ensure that37/// [`wasmtime_jit_icache_coherence::pipeline_flush_mt`] is called before the38/// mappings are used.39pub(crate) fn set_readable_and_executable(40ptr: *mut u8,41len: usize,42branch_protection: BranchProtection,43) -> ModuleResult<()> {44// Clear all the newly allocated code from cache if the processor requires it45//46// Do this before marking the memory as R+X, technically we should be able to do it after47// but there are some CPU's that have had errata about doing this with read only memory.48unsafe {49wasmtime_jit_icache_coherence::clear_cache(ptr as *const libc::c_void, len)50.expect("Failed cache clear")51};5253unsafe {54region::protect(ptr, len, region::Protection::READ_EXECUTE).map_err(|e| {55ModuleError::Backend(56anyhow::Error::new(e).context("unable to make memory readable+executable"),57)58})?;59}6061// If BTI is requested, and the architecture supports it, use mprotect to set the PROT_BTI flag.62if branch_protection == BranchProtection::BTI {63#[cfg(all(target_arch = "aarch64", target_os = "linux"))]64if std::arch::is_aarch64_feature_detected!("bti") {65let prot = libc::PROT_EXEC | libc::PROT_READ | /* PROT_BTI */ 0x10;6667unsafe {68if libc::mprotect(ptr as *mut libc::c_void, len, prot) < 0 {69return Err(ModuleError::Backend(70anyhow::Error::new(io::Error::last_os_error())71.context("unable to make memory readable+executable"),72));73}74}75}76}7778Ok(())79}808182