1d4242001SAdam Bratschi-Kaye //! Memory management for executable code. 2d4242001SAdam Bratschi-Kaye 381a89169SAlex Crichton use crate::prelude::*; 44afa86b8SAlex Crichton use crate::runtime::vm::{libcalls, MmapVec}; 55eee6313SChris Fallin use crate::Engine; 65eee6313SChris Fallin use alloc::sync::Arc; 781a89169SAlex Crichton use core::ops::Range; 857cd5a9eSAlex Crichton use object::endian::Endianness; 9f3340930SAlex Crichton use object::read::{elf::ElfFile64, Object, ObjectSection}; 10d3132c9dSAlex Crichton use object::{ObjectSymbol, SectionFlags}; 1166dfa363SJamey Sharp use wasmtime_environ::{lookup_trap_code, obj, Trap}; 12d4242001SAdam Bratschi-Kaye 13d4242001SAdam Bratschi-Kaye /// Management of executable memory within a `MmapVec` 14d4242001SAdam Bratschi-Kaye /// 15d4242001SAdam Bratschi-Kaye /// This type consumes ownership of a region of memory and will manage the 16d4242001SAdam Bratschi-Kaye /// executable permissions of the contained JIT code as necessary. 17d4242001SAdam Bratschi-Kaye pub struct CodeMemory { 18ae3bf36fSSingleAccretion mmap: MmapVec, 194afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 204afa86b8SAlex Crichton unwind_registration: Option<crate::runtime::vm::UnwindRegistration>, 21ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 22ae3bf36fSSingleAccretion debug_registration: Option<crate::runtime::vm::GdbJitImageRegistration>, 23d4242001SAdam Bratschi-Kaye published: bool, 24d4242001SAdam Bratschi-Kaye enable_branch_protection: bool, 25d3132c9dSAlex Crichton needs_executable: bool, 26ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 27ae3bf36fSSingleAccretion has_native_debug_info: bool, 285eee6313SChris Fallin custom_code_memory: Option<Arc<dyn CustomCodeMemory>>, 29d4242001SAdam Bratschi-Kaye 30d4242001SAdam Bratschi-Kaye relocations: Vec<(usize, obj::LibCall)>, 31d4242001SAdam Bratschi-Kaye 32d4242001SAdam Bratschi-Kaye // Ranges within `self.mmap` of where the particular sections lie. 33d4242001SAdam Bratschi-Kaye text: Range<usize>, 34d4242001SAdam Bratschi-Kaye unwind: Range<usize>, 35d4242001SAdam Bratschi-Kaye trap_data: Range<usize>, 36d4242001SAdam Bratschi-Kaye wasm_data: Range<usize>, 37d4242001SAdam Bratschi-Kaye address_map_data: Range<usize>, 38d4242001SAdam Bratschi-Kaye func_name_data: Range<usize>, 39d4242001SAdam Bratschi-Kaye info_data: Range<usize>, 40ae3bf36fSSingleAccretion wasm_dwarf: Range<usize>, 41d4242001SAdam Bratschi-Kaye } 42d4242001SAdam Bratschi-Kaye 43d4242001SAdam Bratschi-Kaye impl Drop for CodeMemory { 44d4242001SAdam Bratschi-Kaye fn drop(&mut self) { 455eee6313SChris Fallin // If there is a custom code memory handler, restore the 465eee6313SChris Fallin // original (non-executable) state of the memory. 475eee6313SChris Fallin if let Some(mem) = self.custom_code_memory.as_ref() { 48*4e8dc9d0SPaul Osborne if self.published && self.needs_executable { 495eee6313SChris Fallin let text = self.text(); 505eee6313SChris Fallin mem.unpublish_executable(text.as_ptr(), text.len()) 515eee6313SChris Fallin .expect("Executable memory unpublish failed"); 525eee6313SChris Fallin } 53*4e8dc9d0SPaul Osborne } 545eee6313SChris Fallin 55ae3bf36fSSingleAccretion // Drop the registrations before `self.mmap` since they (implicitly) refer to it. 564afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 57ae3bf36fSSingleAccretion let _ = self.unwind_registration.take(); 58ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 59ae3bf36fSSingleAccretion let _ = self.debug_registration.take(); 60d4242001SAdam Bratschi-Kaye } 61d4242001SAdam Bratschi-Kaye } 62d4242001SAdam Bratschi-Kaye 63d4242001SAdam Bratschi-Kaye fn _assert() { 64d4242001SAdam Bratschi-Kaye fn _assert_send_sync<T: Send + Sync>() {} 65d4242001SAdam Bratschi-Kaye _assert_send_sync::<CodeMemory>(); 66d4242001SAdam Bratschi-Kaye } 67d4242001SAdam Bratschi-Kaye 685eee6313SChris Fallin /// Interface implemented by an embedder to provide custom 695eee6313SChris Fallin /// implementations of code-memory protection and execute permissions. 705eee6313SChris Fallin pub trait CustomCodeMemory: Send + Sync { 715eee6313SChris Fallin /// The minimal alignment granularity for an address region that 725eee6313SChris Fallin /// can be made executable. 735eee6313SChris Fallin /// 745eee6313SChris Fallin /// Wasmtime does not assume the system page size for this because 755eee6313SChris Fallin /// custom code-memory protection can be used when all other uses 765eee6313SChris Fallin /// of virtual memory are disabled. 775eee6313SChris Fallin fn required_alignment(&self) -> usize; 785eee6313SChris Fallin 795eee6313SChris Fallin /// Publish a region of memory as executable. 805eee6313SChris Fallin /// 815eee6313SChris Fallin /// This should update permissions from the default RW 825eee6313SChris Fallin /// (readable/writable but not executable) to RX 835eee6313SChris Fallin /// (readable/executable but not writable), enforcing W^X 845eee6313SChris Fallin /// discipline. 855eee6313SChris Fallin /// 865eee6313SChris Fallin /// If the platform requires any data/instruction coherence 875eee6313SChris Fallin /// action, that should be performed as part of this hook as well. 885eee6313SChris Fallin /// 895eee6313SChris Fallin /// `ptr` and `ptr.offset(len)` are guaranteed to be aligned as 905eee6313SChris Fallin /// per `required_alignment()`. 915eee6313SChris Fallin fn publish_executable(&self, ptr: *const u8, len: usize) -> anyhow::Result<()>; 925eee6313SChris Fallin 935eee6313SChris Fallin /// Unpublish a region of memory. 945eee6313SChris Fallin /// 955eee6313SChris Fallin /// This should perform the opposite effect of `make_executable`, 965eee6313SChris Fallin /// switching a range of memory back from RX (readable/executable) 975eee6313SChris Fallin /// to RW (readable/writable). It is guaranteed that no code is 985eee6313SChris Fallin /// running anymore from this region. 995eee6313SChris Fallin /// 1005eee6313SChris Fallin /// `ptr` and `ptr.offset(len)` are guaranteed to be aligned as 1015eee6313SChris Fallin /// per `required_alignment()`. 1025eee6313SChris Fallin fn unpublish_executable(&self, ptr: *const u8, len: usize) -> anyhow::Result<()>; 1035eee6313SChris Fallin } 1045eee6313SChris Fallin 105d4242001SAdam Bratschi-Kaye impl CodeMemory { 106d4242001SAdam Bratschi-Kaye /// Creates a new `CodeMemory` by taking ownership of the provided 107d4242001SAdam Bratschi-Kaye /// `MmapVec`. 108d4242001SAdam Bratschi-Kaye /// 109d4242001SAdam Bratschi-Kaye /// The returned `CodeMemory` manages the internal `MmapVec` and the 110d4242001SAdam Bratschi-Kaye /// `publish` method is used to actually make the memory executable. 1115eee6313SChris Fallin pub fn new(engine: &Engine, mmap: MmapVec) -> Result<Self> { 11257cd5a9eSAlex Crichton let obj = ElfFile64::<Endianness>::parse(&mmap[..]) 1139034e101SAlex Crichton .map_err(obj::ObjectCrateErrorWrapper) 114d4242001SAdam Bratschi-Kaye .with_context(|| "failed to parse internal compilation artifact")?; 115d4242001SAdam Bratschi-Kaye 116d4242001SAdam Bratschi-Kaye let mut relocations = Vec::new(); 117d4242001SAdam Bratschi-Kaye let mut text = 0..0; 118d4242001SAdam Bratschi-Kaye let mut unwind = 0..0; 119d4242001SAdam Bratschi-Kaye let mut enable_branch_protection = None; 120d3132c9dSAlex Crichton let mut needs_executable = true; 121ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 122ae3bf36fSSingleAccretion let mut has_native_debug_info = false; 123d4242001SAdam Bratschi-Kaye let mut trap_data = 0..0; 124d4242001SAdam Bratschi-Kaye let mut wasm_data = 0..0; 125d4242001SAdam Bratschi-Kaye let mut address_map_data = 0..0; 126d4242001SAdam Bratschi-Kaye let mut func_name_data = 0..0; 127d4242001SAdam Bratschi-Kaye let mut info_data = 0..0; 128ae3bf36fSSingleAccretion let mut wasm_dwarf = 0..0; 129d4242001SAdam Bratschi-Kaye for section in obj.sections() { 1309034e101SAlex Crichton let data = section.data().map_err(obj::ObjectCrateErrorWrapper)?; 1319034e101SAlex Crichton let name = section.name().map_err(obj::ObjectCrateErrorWrapper)?; 132d4242001SAdam Bratschi-Kaye let range = subslice_range(data, &mmap); 133d4242001SAdam Bratschi-Kaye 134d4242001SAdam Bratschi-Kaye // Double-check that sections are all aligned properly. 135d4242001SAdam Bratschi-Kaye if section.align() != 0 && data.len() != 0 { 136d4242001SAdam Bratschi-Kaye if (data.as_ptr() as u64 - mmap.as_ptr() as u64) % section.align() != 0 { 137d4242001SAdam Bratschi-Kaye bail!( 138d4242001SAdam Bratschi-Kaye "section `{}` isn't aligned to {:#x}", 139d4242001SAdam Bratschi-Kaye section.name().unwrap_or("ERROR"), 140d4242001SAdam Bratschi-Kaye section.align() 141d4242001SAdam Bratschi-Kaye ); 142d4242001SAdam Bratschi-Kaye } 143d4242001SAdam Bratschi-Kaye } 144d4242001SAdam Bratschi-Kaye 145d4242001SAdam Bratschi-Kaye match name { 146d4242001SAdam Bratschi-Kaye obj::ELF_WASM_BTI => match data.len() { 147d4242001SAdam Bratschi-Kaye 1 => enable_branch_protection = Some(data[0] != 0), 148d4242001SAdam Bratschi-Kaye _ => bail!("invalid `{name}` section"), 149d4242001SAdam Bratschi-Kaye }, 150d4242001SAdam Bratschi-Kaye ".text" => { 151d4242001SAdam Bratschi-Kaye text = range; 152d4242001SAdam Bratschi-Kaye 153d3132c9dSAlex Crichton if let SectionFlags::Elf { sh_flags } = section.flags() { 154d3132c9dSAlex Crichton if sh_flags & obj::SH_WASMTIME_NOT_EXECUTED != 0 { 155d3132c9dSAlex Crichton needs_executable = false; 156d3132c9dSAlex Crichton } 157d3132c9dSAlex Crichton } 158d3132c9dSAlex Crichton 159d4242001SAdam Bratschi-Kaye // The text section might have relocations for things like 160d4242001SAdam Bratschi-Kaye // libcalls which need to be applied, so handle those here. 161d4242001SAdam Bratschi-Kaye // 162d4242001SAdam Bratschi-Kaye // Note that only a small subset of possible relocations are 163d4242001SAdam Bratschi-Kaye // handled. Only those required by the compiler side of 164d4242001SAdam Bratschi-Kaye // things are processed. 165d4242001SAdam Bratschi-Kaye for (offset, reloc) in section.relocations() { 166d4242001SAdam Bratschi-Kaye assert_eq!(reloc.kind(), object::RelocationKind::Absolute); 167d4242001SAdam Bratschi-Kaye assert_eq!(reloc.encoding(), object::RelocationEncoding::Generic); 16881a89169SAlex Crichton assert_eq!(usize::from(reloc.size()), core::mem::size_of::<usize>() * 8); 169d4242001SAdam Bratschi-Kaye assert_eq!(reloc.addend(), 0); 170d4242001SAdam Bratschi-Kaye let sym = match reloc.target() { 171d4242001SAdam Bratschi-Kaye object::RelocationTarget::Symbol(id) => id, 172d4242001SAdam Bratschi-Kaye other => panic!("unknown relocation target {other:?}"), 173d4242001SAdam Bratschi-Kaye }; 174d4242001SAdam Bratschi-Kaye let sym = obj.symbol_by_index(sym).unwrap().name().unwrap(); 175d4242001SAdam Bratschi-Kaye let libcall = obj::LibCall::from_str(sym) 176d4242001SAdam Bratschi-Kaye .unwrap_or_else(|| panic!("unknown symbol relocation: {sym}")); 177d4242001SAdam Bratschi-Kaye 178d4242001SAdam Bratschi-Kaye let offset = usize::try_from(offset).unwrap(); 179d4242001SAdam Bratschi-Kaye relocations.push((offset, libcall)); 180d4242001SAdam Bratschi-Kaye } 181d4242001SAdam Bratschi-Kaye } 1824afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 1834afa86b8SAlex Crichton crate::runtime::vm::UnwindRegistration::SECTION_NAME => unwind = range, 184d4242001SAdam Bratschi-Kaye obj::ELF_WASM_DATA => wasm_data = range, 185d4242001SAdam Bratschi-Kaye obj::ELF_WASMTIME_ADDRMAP => address_map_data = range, 186d4242001SAdam Bratschi-Kaye obj::ELF_WASMTIME_TRAPS => trap_data = range, 187d4242001SAdam Bratschi-Kaye obj::ELF_NAME_DATA => func_name_data = range, 188d4242001SAdam Bratschi-Kaye obj::ELF_WASMTIME_INFO => info_data = range, 189ae3bf36fSSingleAccretion obj::ELF_WASMTIME_DWARF => wasm_dwarf = range, 190ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 191ae3bf36fSSingleAccretion ".debug_info" => has_native_debug_info = true, 192d4242001SAdam Bratschi-Kaye 193d4242001SAdam Bratschi-Kaye _ => log::debug!("ignoring section {name}"), 194d4242001SAdam Bratschi-Kaye } 195d4242001SAdam Bratschi-Kaye } 1965eee6313SChris Fallin 1974afa86b8SAlex Crichton // require mutability even when this is turned off 1984afa86b8SAlex Crichton #[cfg(not(has_host_compiler_backend))] 1994afa86b8SAlex Crichton let _ = &mut unwind; 2004afa86b8SAlex Crichton 201d4242001SAdam Bratschi-Kaye Ok(Self { 202ae3bf36fSSingleAccretion mmap, 2034afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 204ae3bf36fSSingleAccretion unwind_registration: None, 205ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 206ae3bf36fSSingleAccretion debug_registration: None, 207d4242001SAdam Bratschi-Kaye published: false, 208d4242001SAdam Bratschi-Kaye enable_branch_protection: enable_branch_protection 209d4242001SAdam Bratschi-Kaye .ok_or_else(|| anyhow!("missing `{}` section", obj::ELF_WASM_BTI))?, 210d3132c9dSAlex Crichton needs_executable, 211ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 212ae3bf36fSSingleAccretion has_native_debug_info, 2135eee6313SChris Fallin custom_code_memory: engine.custom_code_memory().cloned(), 214d4242001SAdam Bratschi-Kaye text, 215d4242001SAdam Bratschi-Kaye unwind, 216d4242001SAdam Bratschi-Kaye trap_data, 217d4242001SAdam Bratschi-Kaye address_map_data, 218d4242001SAdam Bratschi-Kaye func_name_data, 219ae3bf36fSSingleAccretion wasm_dwarf, 220d4242001SAdam Bratschi-Kaye info_data, 221d4242001SAdam Bratschi-Kaye wasm_data, 222d4242001SAdam Bratschi-Kaye relocations, 223d4242001SAdam Bratschi-Kaye }) 224d4242001SAdam Bratschi-Kaye } 225d4242001SAdam Bratschi-Kaye 226d4242001SAdam Bratschi-Kaye /// Returns a reference to the underlying `MmapVec` this memory owns. 227d4242001SAdam Bratschi-Kaye #[inline] 228d4242001SAdam Bratschi-Kaye pub fn mmap(&self) -> &MmapVec { 229d4242001SAdam Bratschi-Kaye &self.mmap 230d4242001SAdam Bratschi-Kaye } 231d4242001SAdam Bratschi-Kaye 232d4242001SAdam Bratschi-Kaye /// Returns the contents of the text section of the ELF executable this 233d4242001SAdam Bratschi-Kaye /// represents. 234d4242001SAdam Bratschi-Kaye #[inline] 235d4242001SAdam Bratschi-Kaye pub fn text(&self) -> &[u8] { 236d4242001SAdam Bratschi-Kaye &self.mmap[self.text.clone()] 237d4242001SAdam Bratschi-Kaye } 238d4242001SAdam Bratschi-Kaye 239d4242001SAdam Bratschi-Kaye /// Returns the contents of the `ELF_WASMTIME_DWARF` section. 240d4242001SAdam Bratschi-Kaye #[inline] 241ae3bf36fSSingleAccretion pub fn wasm_dwarf(&self) -> &[u8] { 242ae3bf36fSSingleAccretion &self.mmap[self.wasm_dwarf.clone()] 243d4242001SAdam Bratschi-Kaye } 244d4242001SAdam Bratschi-Kaye 245d4242001SAdam Bratschi-Kaye /// Returns the data in the `ELF_NAME_DATA` section. 246d4242001SAdam Bratschi-Kaye #[inline] 247d4242001SAdam Bratschi-Kaye pub fn func_name_data(&self) -> &[u8] { 248d4242001SAdam Bratschi-Kaye &self.mmap[self.func_name_data.clone()] 249d4242001SAdam Bratschi-Kaye } 250d4242001SAdam Bratschi-Kaye 251d4242001SAdam Bratschi-Kaye /// Returns the concatenated list of all data associated with this wasm 252d4242001SAdam Bratschi-Kaye /// module. 253d4242001SAdam Bratschi-Kaye /// 254d4242001SAdam Bratschi-Kaye /// This is used for initialization of memories and all data ranges stored 255d4242001SAdam Bratschi-Kaye /// in a `Module` are relative to the slice returned here. 256d4242001SAdam Bratschi-Kaye #[inline] 257d4242001SAdam Bratschi-Kaye pub fn wasm_data(&self) -> &[u8] { 258d4242001SAdam Bratschi-Kaye &self.mmap[self.wasm_data.clone()] 259d4242001SAdam Bratschi-Kaye } 260d4242001SAdam Bratschi-Kaye 261d4242001SAdam Bratschi-Kaye /// Returns the encoded address map section used to pass to 262d4242001SAdam Bratschi-Kaye /// `wasmtime_environ::lookup_file_pos`. 263d4242001SAdam Bratschi-Kaye #[inline] 264d4242001SAdam Bratschi-Kaye pub fn address_map_data(&self) -> &[u8] { 265d4242001SAdam Bratschi-Kaye &self.mmap[self.address_map_data.clone()] 266d4242001SAdam Bratschi-Kaye } 267d4242001SAdam Bratschi-Kaye 268d4242001SAdam Bratschi-Kaye /// Returns the contents of the `ELF_WASMTIME_INFO` section, or an empty 269d4242001SAdam Bratschi-Kaye /// slice if it wasn't found. 270d4242001SAdam Bratschi-Kaye #[inline] 271d4242001SAdam Bratschi-Kaye pub fn wasmtime_info(&self) -> &[u8] { 272d4242001SAdam Bratschi-Kaye &self.mmap[self.info_data.clone()] 273d4242001SAdam Bratschi-Kaye } 274d4242001SAdam Bratschi-Kaye 275d4242001SAdam Bratschi-Kaye /// Returns the contents of the `ELF_WASMTIME_TRAPS` section, or an empty 276d4242001SAdam Bratschi-Kaye /// slice if it wasn't found. 277d4242001SAdam Bratschi-Kaye #[inline] 278d4242001SAdam Bratschi-Kaye pub fn trap_data(&self) -> &[u8] { 279d4242001SAdam Bratschi-Kaye &self.mmap[self.trap_data.clone()] 280d4242001SAdam Bratschi-Kaye } 281d4242001SAdam Bratschi-Kaye 282d4242001SAdam Bratschi-Kaye /// Publishes the internal ELF image to be ready for execution. 283d4242001SAdam Bratschi-Kaye /// 284d4242001SAdam Bratschi-Kaye /// This method can only be called once and will panic if called twice. This 285d4242001SAdam Bratschi-Kaye /// will parse the ELF image from the original `MmapVec` and do everything 286d4242001SAdam Bratschi-Kaye /// necessary to get it ready for execution, including: 287d4242001SAdam Bratschi-Kaye /// 288d4242001SAdam Bratschi-Kaye /// * Change page protections from read/write to read/execute. 289d4242001SAdam Bratschi-Kaye /// * Register unwinding information with the OS 290ae3bf36fSSingleAccretion /// * Register this image with the debugger if native DWARF is present 291d4242001SAdam Bratschi-Kaye /// 292d4242001SAdam Bratschi-Kaye /// After this function executes all JIT code should be ready to execute. 293d4242001SAdam Bratschi-Kaye pub fn publish(&mut self) -> Result<()> { 294d4242001SAdam Bratschi-Kaye assert!(!self.published); 295d4242001SAdam Bratschi-Kaye self.published = true; 296d4242001SAdam Bratschi-Kaye 297d4242001SAdam Bratschi-Kaye if self.text().is_empty() { 298d4242001SAdam Bratschi-Kaye return Ok(()); 299d4242001SAdam Bratschi-Kaye } 300d4242001SAdam Bratschi-Kaye 301d4242001SAdam Bratschi-Kaye // The unsafety here comes from a few things: 302d4242001SAdam Bratschi-Kaye // 303d4242001SAdam Bratschi-Kaye // * We're actually updating some page protections to executable memory. 304d4242001SAdam Bratschi-Kaye // 305d4242001SAdam Bratschi-Kaye // * We're registering unwinding information which relies on the 306d4242001SAdam Bratschi-Kaye // correctness of the information in the first place. This applies to 307d4242001SAdam Bratschi-Kaye // both the actual unwinding tables as well as the validity of the 308d4242001SAdam Bratschi-Kaye // pointers we pass in itself. 309d4242001SAdam Bratschi-Kaye unsafe { 310d4242001SAdam Bratschi-Kaye // First, if necessary, apply relocations. This can happen for 311d4242001SAdam Bratschi-Kaye // things like libcalls which happen late in the lowering process 312d4242001SAdam Bratschi-Kaye // that don't go through the Wasm-based libcalls layer that's 313d4242001SAdam Bratschi-Kaye // indirected through the `VMContext`. Note that most modules won't 314d4242001SAdam Bratschi-Kaye // have relocations, so this typically doesn't do anything. 315d4242001SAdam Bratschi-Kaye self.apply_relocations()?; 316d4242001SAdam Bratschi-Kaye 317d4242001SAdam Bratschi-Kaye // Next freeze the contents of this image by making all of the 318d4242001SAdam Bratschi-Kaye // memory readonly. Nothing after this point should ever be modified 319d4242001SAdam Bratschi-Kaye // so commit everything. For a compiled-in-memory image this will 320d4242001SAdam Bratschi-Kaye // mean IPIs to evict writable mappings from other cores. For 321d4242001SAdam Bratschi-Kaye // loaded-from-disk images this shouldn't result in IPIs so long as 322d4242001SAdam Bratschi-Kaye // there weren't any relocations because nothing should have 323d4242001SAdam Bratschi-Kaye // otherwise written to the image at any point either. 324d3132c9dSAlex Crichton // 325d3132c9dSAlex Crichton // Note that if virtual memory is disabled this is skipped because 326d3132c9dSAlex Crichton // we aren't able to make it readonly, but this is just a 327d3132c9dSAlex Crichton // defense-in-depth measure and isn't required for correctness. 3287f9049b9SAlex Crichton #[cfg(has_virtual_memory)] 32999efc20bSPaul Osborne if self.mmap.supports_virtual_memory() { 330d4242001SAdam Bratschi-Kaye self.mmap.make_readonly(0..self.mmap.len())?; 33199efc20bSPaul Osborne } 332d4242001SAdam Bratschi-Kaye 333d3132c9dSAlex Crichton // Switch the executable portion from readonly to read/execute. 334d3132c9dSAlex Crichton if self.needs_executable { 3355eee6313SChris Fallin if !self.custom_publish()? { 33699efc20bSPaul Osborne if !self.mmap.supports_virtual_memory() { 33799efc20bSPaul Osborne bail!("this target requires virtual memory to be enabled"); 33899efc20bSPaul Osborne } 33999efc20bSPaul Osborne 3407f9049b9SAlex Crichton #[cfg(has_virtual_memory)] 341d3132c9dSAlex Crichton { 342d4242001SAdam Bratschi-Kaye let text = self.text(); 343d4242001SAdam Bratschi-Kaye 344d3132c9dSAlex Crichton use wasmtime_jit_icache_coherence as icache_coherence; 345d3132c9dSAlex Crichton 346d4242001SAdam Bratschi-Kaye // Clear the newly allocated code from cache if the processor requires it 347d4242001SAdam Bratschi-Kaye // 348d4242001SAdam Bratschi-Kaye // Do this before marking the memory as R+X, technically we should be able to do it after 349d4242001SAdam Bratschi-Kaye // but there are some CPU's that have had errata about doing this with read only memory. 350d4242001SAdam Bratschi-Kaye icache_coherence::clear_cache(text.as_ptr().cast(), text.len()) 351d4242001SAdam Bratschi-Kaye .expect("Failed cache clear"); 352d4242001SAdam Bratschi-Kaye 353d4242001SAdam Bratschi-Kaye self.mmap 354d4242001SAdam Bratschi-Kaye .make_executable(self.text.clone(), self.enable_branch_protection) 355d4242001SAdam Bratschi-Kaye .context("unable to make memory executable")?; 356d4242001SAdam Bratschi-Kaye 357d4242001SAdam Bratschi-Kaye // Flush any in-flight instructions from the pipeline 358d4242001SAdam Bratschi-Kaye icache_coherence::pipeline_flush_mt().expect("Failed pipeline flush"); 359d3132c9dSAlex Crichton } 360d3132c9dSAlex Crichton } 3615eee6313SChris Fallin } 362d4242001SAdam Bratschi-Kaye 363d4242001SAdam Bratschi-Kaye // With all our memory set up use the platform-specific 364d4242001SAdam Bratschi-Kaye // `UnwindRegistration` implementation to inform the general 365d4242001SAdam Bratschi-Kaye // runtime that there's unwinding information available for all 366d4242001SAdam Bratschi-Kaye // our just-published JIT functions. 367d4242001SAdam Bratschi-Kaye self.register_unwind_info()?; 368ae3bf36fSSingleAccretion 369ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 370ae3bf36fSSingleAccretion self.register_debug_image()?; 371d4242001SAdam Bratschi-Kaye } 372d4242001SAdam Bratschi-Kaye 373d4242001SAdam Bratschi-Kaye Ok(()) 374d4242001SAdam Bratschi-Kaye } 375d4242001SAdam Bratschi-Kaye 3765eee6313SChris Fallin fn custom_publish(&mut self) -> Result<bool> { 3775eee6313SChris Fallin if let Some(mem) = self.custom_code_memory.as_ref() { 3785eee6313SChris Fallin let text = self.text(); 3795eee6313SChris Fallin // The text section should be aligned to 3805eee6313SChris Fallin // `custom_code_memory.required_alignment()` due to a 3815eee6313SChris Fallin // combination of two invariants: 3825eee6313SChris Fallin // 3835eee6313SChris Fallin // - MmapVec aligns its start address, even in owned-Vec mode; and 3845eee6313SChris Fallin // - The text segment inside the ELF image will be aligned according 3855eee6313SChris Fallin // to the platform's requirements. 3865eee6313SChris Fallin let text_addr = text.as_ptr() as usize; 3875eee6313SChris Fallin assert_eq!(text_addr & (mem.required_alignment() - 1), 0); 3885eee6313SChris Fallin 3895eee6313SChris Fallin // The custom code memory handler will ensure the 3905eee6313SChris Fallin // memory is executable and also handle icache 3915eee6313SChris Fallin // coherence. 3925eee6313SChris Fallin mem.publish_executable(text.as_ptr(), text.len())?; 3935eee6313SChris Fallin Ok(true) 3945eee6313SChris Fallin } else { 3955eee6313SChris Fallin Ok(false) 3965eee6313SChris Fallin } 3975eee6313SChris Fallin } 3985eee6313SChris Fallin 399d4242001SAdam Bratschi-Kaye unsafe fn apply_relocations(&mut self) -> Result<()> { 400d4242001SAdam Bratschi-Kaye if self.relocations.is_empty() { 401d4242001SAdam Bratschi-Kaye return Ok(()); 402d4242001SAdam Bratschi-Kaye } 403d4242001SAdam Bratschi-Kaye 40499efc20bSPaul Osborne if self.mmap.is_always_readonly() { 40599efc20bSPaul Osborne bail!("Unable to apply relocations to readonly MmapVec"); 40699efc20bSPaul Osborne } 40799efc20bSPaul Osborne 408d4242001SAdam Bratschi-Kaye for (offset, libcall) in self.relocations.iter() { 409d4242001SAdam Bratschi-Kaye let offset = self.text.start + offset; 410d4242001SAdam Bratschi-Kaye let libcall = match libcall { 411d4242001SAdam Bratschi-Kaye obj::LibCall::FloorF32 => libcalls::relocs::floorf32 as usize, 412d4242001SAdam Bratschi-Kaye obj::LibCall::FloorF64 => libcalls::relocs::floorf64 as usize, 413d4242001SAdam Bratschi-Kaye obj::LibCall::NearestF32 => libcalls::relocs::nearestf32 as usize, 414d4242001SAdam Bratschi-Kaye obj::LibCall::NearestF64 => libcalls::relocs::nearestf64 as usize, 415d4242001SAdam Bratschi-Kaye obj::LibCall::CeilF32 => libcalls::relocs::ceilf32 as usize, 416d4242001SAdam Bratschi-Kaye obj::LibCall::CeilF64 => libcalls::relocs::ceilf64 as usize, 417d4242001SAdam Bratschi-Kaye obj::LibCall::TruncF32 => libcalls::relocs::truncf32 as usize, 418d4242001SAdam Bratschi-Kaye obj::LibCall::TruncF64 => libcalls::relocs::truncf64 as usize, 419d4242001SAdam Bratschi-Kaye obj::LibCall::FmaF32 => libcalls::relocs::fmaf32 as usize, 420d4242001SAdam Bratschi-Kaye obj::LibCall::FmaF64 => libcalls::relocs::fmaf64 as usize, 421d4242001SAdam Bratschi-Kaye #[cfg(target_arch = "x86_64")] 422d4242001SAdam Bratschi-Kaye obj::LibCall::X86Pshufb => libcalls::relocs::x86_pshufb as usize, 423d4242001SAdam Bratschi-Kaye #[cfg(not(target_arch = "x86_64"))] 424d4242001SAdam Bratschi-Kaye obj::LibCall::X86Pshufb => unreachable!(), 425d4242001SAdam Bratschi-Kaye }; 42699efc20bSPaul Osborne 427d4242001SAdam Bratschi-Kaye self.mmap 428d3132c9dSAlex Crichton .as_mut_slice() 429d4242001SAdam Bratschi-Kaye .as_mut_ptr() 430d4242001SAdam Bratschi-Kaye .add(offset) 431d4242001SAdam Bratschi-Kaye .cast::<usize>() 432d4242001SAdam Bratschi-Kaye .write_unaligned(libcall); 433d4242001SAdam Bratschi-Kaye } 434d4242001SAdam Bratschi-Kaye Ok(()) 435d4242001SAdam Bratschi-Kaye } 436d4242001SAdam Bratschi-Kaye 437d4242001SAdam Bratschi-Kaye unsafe fn register_unwind_info(&mut self) -> Result<()> { 438d4242001SAdam Bratschi-Kaye if self.unwind.len() == 0 { 439d4242001SAdam Bratschi-Kaye return Ok(()); 440d4242001SAdam Bratschi-Kaye } 4414afa86b8SAlex Crichton #[cfg(has_host_compiler_backend)] 4424afa86b8SAlex Crichton { 443d4242001SAdam Bratschi-Kaye let text = self.text(); 444d4242001SAdam Bratschi-Kaye let unwind_info = &self.mmap[self.unwind.clone()]; 4454afa86b8SAlex Crichton let registration = crate::runtime::vm::UnwindRegistration::new( 4464afa86b8SAlex Crichton text.as_ptr(), 4474afa86b8SAlex Crichton unwind_info.as_ptr(), 4484afa86b8SAlex Crichton unwind_info.len(), 4494afa86b8SAlex Crichton ) 450d4242001SAdam Bratschi-Kaye .context("failed to create unwind info registration")?; 451ae3bf36fSSingleAccretion self.unwind_registration = Some(registration); 4524afa86b8SAlex Crichton return Ok(()); 4534afa86b8SAlex Crichton } 4544afa86b8SAlex Crichton #[cfg(not(has_host_compiler_backend))] 4554afa86b8SAlex Crichton { 4564afa86b8SAlex Crichton bail!("should not have unwind info for non-native backend") 4574afa86b8SAlex Crichton } 458ae3bf36fSSingleAccretion } 459ae3bf36fSSingleAccretion 460ae3bf36fSSingleAccretion #[cfg(feature = "debug-builtins")] 461ae3bf36fSSingleAccretion fn register_debug_image(&mut self) -> Result<()> { 462ae3bf36fSSingleAccretion if !self.has_native_debug_info { 463ae3bf36fSSingleAccretion return Ok(()); 464ae3bf36fSSingleAccretion } 465ae3bf36fSSingleAccretion 466ae3bf36fSSingleAccretion // TODO-DebugInfo: we're copying the whole image here, which is pretty wasteful. 467ae3bf36fSSingleAccretion // Use the existing memory by teaching code here about relocations in DWARF sections 468ae3bf36fSSingleAccretion // and anything else necessary that is done in "create_gdbjit_image" right now. 469ae3bf36fSSingleAccretion let image = self.mmap().to_vec(); 470ae3bf36fSSingleAccretion let text: &[u8] = self.text(); 471ae3bf36fSSingleAccretion let bytes = crate::debug::create_gdbjit_image(image, (text.as_ptr(), text.len()))?; 472ae3bf36fSSingleAccretion let reg = crate::runtime::vm::GdbJitImageRegistration::register(bytes); 473ae3bf36fSSingleAccretion self.debug_registration = Some(reg); 474d4242001SAdam Bratschi-Kaye Ok(()) 475d4242001SAdam Bratschi-Kaye } 47666dfa363SJamey Sharp 47766dfa363SJamey Sharp /// Looks up the given offset within this module's text section and returns 47866dfa363SJamey Sharp /// the trap code associated with that instruction, if there is one. 47966dfa363SJamey Sharp pub fn lookup_trap_code(&self, text_offset: usize) -> Option<Trap> { 48066dfa363SJamey Sharp lookup_trap_code(self.trap_data(), text_offset) 48166dfa363SJamey Sharp } 482d4242001SAdam Bratschi-Kaye } 483d4242001SAdam Bratschi-Kaye 484d4242001SAdam Bratschi-Kaye /// Returns the range of `inner` within `outer`, such that `outer[range]` is the 485d4242001SAdam Bratschi-Kaye /// same as `inner`. 486d4242001SAdam Bratschi-Kaye /// 487d4242001SAdam Bratschi-Kaye /// This method requires that `inner` is a sub-slice of `outer`, and if that 488d4242001SAdam Bratschi-Kaye /// isn't true then this method will panic. 489d4242001SAdam Bratschi-Kaye fn subslice_range(inner: &[u8], outer: &[u8]) -> Range<usize> { 490d4242001SAdam Bratschi-Kaye if inner.len() == 0 { 491d4242001SAdam Bratschi-Kaye return 0..0; 492d4242001SAdam Bratschi-Kaye } 493d4242001SAdam Bratschi-Kaye 494d4242001SAdam Bratschi-Kaye assert!(outer.as_ptr() <= inner.as_ptr()); 495d4242001SAdam Bratschi-Kaye assert!((&inner[inner.len() - 1] as *const _) <= (&outer[outer.len() - 1] as *const _)); 496d4242001SAdam Bratschi-Kaye 497d4242001SAdam Bratschi-Kaye let start = inner.as_ptr() as usize - outer.as_ptr() as usize; 498d4242001SAdam Bratschi-Kaye start..start + inner.len() 499d4242001SAdam Bratschi-Kaye } 500