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