use cranelift_module::{ModuleError, ModuleResult};
use std::io;
mod arena;
mod system;
pub use arena::ArenaMemoryProvider;
pub use system::SystemMemoryProvider;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum BranchProtection {
None,
BTI,
}
pub enum JITMemoryKind {
Executable,
Writable,
ReadOnly,
}
pub trait JITMemoryProvider {
fn allocate(&mut self, size: usize, align: u64, kind: JITMemoryKind) -> io::Result<*mut u8>;
unsafe fn free_memory(&mut self);
fn finalize(&mut self, branch_protection: BranchProtection) -> ModuleResult<()>;
}
pub(crate) fn set_readable_and_executable(
ptr: *mut u8,
len: usize,
branch_protection: BranchProtection,
) -> ModuleResult<()> {
unsafe {
wasmtime_jit_icache_coherence::clear_cache(ptr as *const libc::c_void, len)
.expect("Failed cache clear")
};
unsafe {
region::protect(ptr, len, region::Protection::READ_EXECUTE).map_err(|e| {
ModuleError::Backend(
anyhow::Error::new(e).context("unable to make memory readable+executable"),
)
})?;
}
if branch_protection == BranchProtection::BTI {
#[cfg(all(target_arch = "aarch64", target_os = "linux"))]
if std::arch::is_aarch64_feature_detected!("bti") {
let prot = libc::PROT_EXEC | libc::PROT_READ | 0x10;
unsafe {
if libc::mprotect(ptr as *mut libc::c_void, len, prot) < 0 {
return Err(ModuleError::Backend(
anyhow::Error::new(io::Error::last_os_error())
.context("unable to make memory readable+executable"),
));
}
}
}
}
Ok(())
}