1 //! Defines `JITModule`.
2 
3 use crate::{
4     compiled_blob::CompiledBlob,
5     memory::{BranchProtection, JITMemoryKind, JITMemoryProvider, SystemMemoryProvider},
6 };
7 use cranelift_codegen::binemit::Reloc;
8 use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa};
9 use cranelift_codegen::settings::Configurable;
10 use cranelift_codegen::{ir, settings};
11 use cranelift_control::ControlPlane;
12 use cranelift_entity::SecondaryMap;
13 use cranelift_module::{
14     DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleDeclarations, ModuleError,
15     ModuleReloc, ModuleRelocTarget, ModuleResult,
16 };
17 use log::info;
18 use std::cell::RefCell;
19 use std::collections::HashMap;
20 use std::ffi::CString;
21 use std::io::Write;
22 use target_lexicon::PointerWidth;
23 
24 const WRITABLE_DATA_ALIGNMENT: u64 = 0x8;
25 const READONLY_DATA_ALIGNMENT: u64 = 0x1;
26 
27 /// A builder for `JITModule`.
28 pub struct JITBuilder {
29     isa: OwnedTargetIsa,
30     symbols: HashMap<String, SendWrapper<*const u8>>,
31     lookup_symbols: Vec<Box<dyn Fn(&str) -> Option<*const u8> + Send>>,
32     libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
33     memory: Option<Box<dyn JITMemoryProvider + Send>>,
34 }
35 
36 impl JITBuilder {
37     /// Create a new `JITBuilder`.
38     ///
39     /// The `libcall_names` function provides a way to translate `cranelift_codegen`'s `ir::LibCall`
40     /// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain
41     /// floating point instructions, and for stack probes. If you don't know what to use for this
42     /// argument, use `cranelift_module::default_libcall_names()`.
new( libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>, ) -> ModuleResult<Self>43     pub fn new(
44         libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
45     ) -> ModuleResult<Self> {
46         Self::with_flags(&[], libcall_names)
47     }
48 
49     /// Create a new `JITBuilder` with the given flags.
50     ///
51     /// The `libcall_names` function provides a way to translate `cranelift_codegen`'s `ir::LibCall`
52     /// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain
53     /// floating point instructions, and for stack probes. If you don't know what to use for this
54     /// argument, use `cranelift_module::default_libcall_names()`.
with_flags( flags: &[(&str, &str)], libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>, ) -> ModuleResult<Self>55     pub fn with_flags(
56         flags: &[(&str, &str)],
57         libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
58     ) -> ModuleResult<Self> {
59         let mut flag_builder = settings::builder();
60         for (name, value) in flags {
61             flag_builder.set(name, value)?;
62         }
63 
64         // On at least AArch64, "colocated" calls use shorter-range relocations,
65         // which might not reach all definitions; we can't handle that here, so
66         // we require long-range relocation types.
67         flag_builder.set("use_colocated_libcalls", "false").unwrap();
68         flag_builder.set("is_pic", "false").unwrap();
69         let isa_builder = cranelift_native::builder().unwrap_or_else(|msg| {
70             panic!("host machine is not supported: {msg}");
71         });
72         let isa = isa_builder.finish(settings::Flags::new(flag_builder))?;
73         Ok(Self::with_isa(isa, libcall_names))
74     }
75 
76     /// Create a new `JITBuilder` with an arbitrary target. This is mainly
77     /// useful for testing.
78     ///
79     /// To create a `JITBuilder` for native use, use the `new` or `with_flags`
80     /// constructors instead.
81     ///
82     /// The `libcall_names` function provides a way to translate `cranelift_codegen`'s `ir::LibCall`
83     /// enum to symbols. LibCalls are inserted in the IR as part of the legalization for certain
84     /// floating point instructions, and for stack probes. If you don't know what to use for this
85     /// argument, use `cranelift_module::default_libcall_names()`.
with_isa( isa: OwnedTargetIsa, libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>, ) -> Self86     pub fn with_isa(
87         isa: OwnedTargetIsa,
88         libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
89     ) -> Self {
90         let symbols = HashMap::new();
91         let lookup_symbols = vec![Box::new(lookup_with_dlsym) as Box<_>];
92         Self {
93             isa,
94             symbols,
95             lookup_symbols,
96             libcall_names,
97             memory: None,
98         }
99     }
100 
101     /// Define a symbol in the internal symbol table.
102     ///
103     /// The JIT will use the symbol table to resolve names that are declared,
104     /// but not defined, in the module being compiled.  A common example is
105     /// external functions.  With this method, functions and data can be exposed
106     /// to the code being compiled which are defined by the host.
107     ///
108     /// If a symbol is defined more than once, the most recent definition will
109     /// be retained.
110     ///
111     /// If the JIT fails to find a symbol in its internal table, it will fall
112     /// back to a platform-specific search (this typically involves searching
113     /// the current process for public symbols, followed by searching the
114     /// platform's C runtime).
symbol<K>(&mut self, name: K, ptr: *const u8) -> &mut Self where K: Into<String>,115     pub fn symbol<K>(&mut self, name: K, ptr: *const u8) -> &mut Self
116     where
117         K: Into<String>,
118     {
119         self.symbols.insert(name.into(), SendWrapper(ptr));
120         self
121     }
122 
123     /// Define multiple symbols in the internal symbol table.
124     ///
125     /// Using this is equivalent to calling `symbol` on each element.
symbols<It, K>(&mut self, symbols: It) -> &mut Self where It: IntoIterator<Item = (K, *const u8)>, K: Into<String>,126     pub fn symbols<It, K>(&mut self, symbols: It) -> &mut Self
127     where
128         It: IntoIterator<Item = (K, *const u8)>,
129         K: Into<String>,
130     {
131         for (name, ptr) in symbols {
132             self.symbols.insert(name.into(), SendWrapper(ptr));
133         }
134         self
135     }
136 
137     /// Add a symbol lookup fn.
138     ///
139     /// Symbol lookup fn's are used to lookup symbols when they couldn't be found in the internal
140     /// symbol table. Symbol lookup fn's are called in reverse of the order in which they were added.
symbol_lookup_fn( &mut self, symbol_lookup_fn: Box<dyn Fn(&str) -> Option<*const u8> + Send>, ) -> &mut Self141     pub fn symbol_lookup_fn(
142         &mut self,
143         symbol_lookup_fn: Box<dyn Fn(&str) -> Option<*const u8> + Send>,
144     ) -> &mut Self {
145         self.lookup_symbols.push(symbol_lookup_fn);
146         self
147     }
148 
149     /// Set the memory provider for the module.
150     ///
151     /// If unset, defaults to [`SystemMemoryProvider`].
memory_provider(&mut self, provider: Box<dyn JITMemoryProvider + Send>) -> &mut Self152     pub fn memory_provider(&mut self, provider: Box<dyn JITMemoryProvider + Send>) -> &mut Self {
153         self.memory = Some(provider);
154         self
155     }
156 }
157 
158 /// A wrapper that impls Send for the contents.
159 ///
160 /// SAFETY: This must not be used for any types where it would be UB for them to be Send
161 #[derive(Copy, Clone)]
162 struct SendWrapper<T>(T);
163 unsafe impl<T> Send for SendWrapper<T> {}
164 
165 /// A `JITModule` implements `Module` and emits code and data into memory where it can be
166 /// directly called and accessed.
167 ///
168 /// See the `JITBuilder` for a convenient way to construct `JITModule` instances.
169 pub struct JITModule {
170     isa: OwnedTargetIsa,
171     symbols: RefCell<HashMap<String, SendWrapper<*const u8>>>,
172     lookup_symbols: Vec<Box<dyn Fn(&str) -> Option<*const u8> + Send>>,
173     libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
174     memory: Box<dyn JITMemoryProvider + Send>,
175     declarations: ModuleDeclarations,
176     compiled_functions: SecondaryMap<FuncId, Option<CompiledBlob>>,
177     compiled_data_objects: SecondaryMap<DataId, Option<CompiledBlob>>,
178     code_ranges: Vec<(usize, usize, FuncId)>,
179     functions_to_finalize: Vec<FuncId>,
180     data_objects_to_finalize: Vec<DataId>,
181 }
182 
183 impl JITModule {
184     /// Free memory allocated for code and data segments of compiled functions.
185     ///
186     /// # Safety
187     ///
188     /// Because this function invalidates any pointers retrieved from the
189     /// corresponding module, it should only be used when none of the functions
190     /// from that module are currently executing and none of the `fn` pointers
191     /// are called afterwards.
free_memory(mut self)192     pub unsafe fn free_memory(mut self) {
193         self.memory.free_memory();
194     }
195 
lookup_symbol(&self, name: &str) -> Option<*const u8>196     fn lookup_symbol(&self, name: &str) -> Option<*const u8> {
197         match self.symbols.borrow_mut().entry(name.to_owned()) {
198             std::collections::hash_map::Entry::Occupied(occ) => Some(occ.get().0),
199             std::collections::hash_map::Entry::Vacant(vac) => {
200                 let ptr = self
201                     .lookup_symbols
202                     .iter()
203                     .rev() // Try last lookup function first
204                     .find_map(|lookup| lookup(name));
205                 if let Some(ptr) = ptr {
206                     vac.insert(SendWrapper(ptr));
207                 }
208                 ptr
209             }
210         }
211     }
212 
get_address(&self, name: &ModuleRelocTarget) -> *const u8213     fn get_address(&self, name: &ModuleRelocTarget) -> *const u8 {
214         match name {
215             ModuleRelocTarget::User { .. } => {
216                 let (name, linkage) = if ModuleDeclarations::is_function(name) {
217                     let func_id = FuncId::from_name(name);
218                     match &self.compiled_functions[func_id] {
219                         Some(compiled) => return compiled.ptr(),
220                         None => {
221                             let decl = self.declarations.get_function_decl(func_id);
222                             (&decl.name, decl.linkage)
223                         }
224                     }
225                 } else {
226                     let data_id = DataId::from_name(name);
227                     match &self.compiled_data_objects[data_id] {
228                         Some(compiled) => return compiled.ptr(),
229                         None => {
230                             let decl = self.declarations.get_data_decl(data_id);
231                             (&decl.name, decl.linkage)
232                         }
233                     }
234                 };
235                 let name = name
236                     .as_ref()
237                     .expect("anonymous symbol must be defined locally");
238                 if let Some(ptr) = self.lookup_symbol(name) {
239                     ptr
240                 } else if linkage == Linkage::Preemptible {
241                     0 as *const u8
242                 } else {
243                     panic!("can't resolve symbol {name}");
244                 }
245             }
246             ModuleRelocTarget::LibCall(libcall) => {
247                 let sym = (self.libcall_names)(*libcall);
248                 self.lookup_symbol(&sym)
249                     .unwrap_or_else(|| panic!("can't resolve libcall {sym}"))
250             }
251             ModuleRelocTarget::FunctionOffset(func_id, offset) => {
252                 match &self.compiled_functions[*func_id] {
253                     Some(compiled) => return compiled.ptr().wrapping_add(*offset as usize),
254                     None => todo!(),
255                 }
256             }
257             name => panic!("invalid name {name:?}"),
258         }
259     }
260 
261     /// Returns the address of a finalized function.
262     ///
263     /// The pointer remains valid until either [`JITModule::free_memory`] is called or in the future
264     /// some way of deallocating this individual function is used.
get_finalized_function(&self, func_id: FuncId) -> *const u8265     pub fn get_finalized_function(&self, func_id: FuncId) -> *const u8 {
266         let info = &self.compiled_functions[func_id];
267         assert!(
268             !self.functions_to_finalize.iter().any(|x| *x == func_id),
269             "function not yet finalized"
270         );
271         info.as_ref()
272             .expect("function must be compiled before it can be finalized")
273             .ptr()
274     }
275 
276     /// Returns the address and size of a finalized data object.
277     ///
278     /// The pointer remains valid until either [`JITModule::free_memory`] is called or in the future
279     /// some way of deallocating this individual data object is used.
get_finalized_data(&self, data_id: DataId) -> (*const u8, usize)280     pub fn get_finalized_data(&self, data_id: DataId) -> (*const u8, usize) {
281         let info = &self.compiled_data_objects[data_id];
282         assert!(
283             !self.data_objects_to_finalize.iter().any(|x| *x == data_id),
284             "data object not yet finalized"
285         );
286         let compiled = info
287             .as_ref()
288             .expect("data object must be compiled before it can be finalized");
289 
290         (compiled.ptr(), compiled.size())
291     }
292 
record_function_for_perf(&self, ptr: *const u8, size: usize, name: &str)293     fn record_function_for_perf(&self, ptr: *const u8, size: usize, name: &str) {
294         // The Linux perf tool supports JIT code via a /tmp/perf-$PID.map file,
295         // which contains memory regions and their associated names.  If we
296         // are profiling with perf and saving binaries to PERF_BUILDID_DIR
297         // for post-profile analysis, write information about each function
298         // we define.
299         if cfg!(unix) && ::std::env::var_os("PERF_BUILDID_DIR").is_some() {
300             let mut map_file = ::std::fs::OpenOptions::new()
301                 .create(true)
302                 .append(true)
303                 .open(format!("/tmp/perf-{}.map", ::std::process::id()))
304                 .unwrap();
305 
306             let _ = writeln!(map_file, "{:x} {:x} {}", ptr as usize, size, name);
307         }
308     }
309 
310     /// Finalize all functions and data objects that are defined but not yet finalized.
311     /// All symbols referenced in their bodies that are declared as needing a definition
312     /// must be defined by this point.
313     ///
314     /// Use `get_finalized_function` and `get_finalized_data` to obtain the final
315     /// artifacts.
316     ///
317     /// Returns ModuleError in case of allocation or syscall failure
finalize_definitions(&mut self) -> ModuleResult<()>318     pub fn finalize_definitions(&mut self) -> ModuleResult<()> {
319         for func in std::mem::take(&mut self.functions_to_finalize) {
320             let decl = self.declarations.get_function_decl(func);
321             assert!(decl.linkage.is_definable());
322             let func = self.compiled_functions[func]
323                 .as_ref()
324                 .expect("function must be compiled before it can be finalized");
325             func.perform_relocations(|name| self.get_address(name));
326         }
327 
328         for data in std::mem::take(&mut self.data_objects_to_finalize) {
329             let decl = self.declarations.get_data_decl(data);
330             assert!(decl.linkage.is_definable());
331             let data = self.compiled_data_objects[data]
332                 .as_ref()
333                 .expect("data object must be compiled before it can be finalized");
334             data.perform_relocations(|name| self.get_address(name));
335         }
336 
337         self.code_ranges
338             .sort_unstable_by_key(|(start, _end, _)| *start);
339 
340         // Now that we're done patching, prepare the memory for execution!
341         let branch_protection = if cfg!(target_arch = "aarch64") && use_bti(&self.isa.isa_flags()) {
342             BranchProtection::BTI
343         } else {
344             BranchProtection::None
345         };
346         self.memory.finalize(branch_protection)?;
347 
348         Ok(())
349     }
350 
351     /// Create a new `JITModule`.
new(builder: JITBuilder) -> Self352     pub fn new(builder: JITBuilder) -> Self {
353         assert!(
354             !builder.isa.flags().is_pic(),
355             "cranelift-jit needs is_pic=false"
356         );
357 
358         let memory = builder
359             .memory
360             .unwrap_or_else(|| Box::new(SystemMemoryProvider::new()));
361         Self {
362             isa: builder.isa,
363             symbols: RefCell::new(builder.symbols),
364             lookup_symbols: builder.lookup_symbols,
365             libcall_names: builder.libcall_names,
366             memory,
367             declarations: ModuleDeclarations::default(),
368             compiled_functions: SecondaryMap::new(),
369             compiled_data_objects: SecondaryMap::new(),
370             code_ranges: Vec::new(),
371             functions_to_finalize: Vec::new(),
372             data_objects_to_finalize: Vec::new(),
373         }
374     }
375 
376     /// Look up the Wasmtime unwind ExceptionTable and corresponding
377     /// base PC, if any, for a given PC that may be within one of the
378     /// CompiledBlobs in this module.
379     #[cfg(feature = "wasmtime-unwinder")]
lookup_wasmtime_exception_data<'a>( &'a self, pc: usize, ) -> Option<(usize, wasmtime_unwinder::ExceptionTable<'a>)>380     pub fn lookup_wasmtime_exception_data<'a>(
381         &'a self,
382         pc: usize,
383     ) -> Option<(usize, wasmtime_unwinder::ExceptionTable<'a>)> {
384         // Search the sorted code-ranges for the PC.
385         let idx = match self
386             .code_ranges
387             .binary_search_by_key(&pc, |(start, _end, _func)| *start)
388         {
389             Ok(exact_start_match) => Some(exact_start_match),
390             Err(least_upper_bound) if least_upper_bound > 0 => {
391                 let last_range_before_pc = &self.code_ranges[least_upper_bound - 1];
392                 if last_range_before_pc.0 <= pc && pc < last_range_before_pc.1 {
393                     Some(least_upper_bound - 1)
394                 } else {
395                     None
396                 }
397             }
398             _ => None,
399         }?;
400 
401         let (start, _, func) = self.code_ranges[idx];
402 
403         // Get the ExceptionTable. The "parse" here simply reads two
404         // u32s for lengths and constructs borrowed slices, so it's
405         // cheap.
406         let data = self.compiled_functions[func]
407             .as_ref()
408             .unwrap()
409             .wasmtime_exception_data()?;
410         let exception_table = wasmtime_unwinder::ExceptionTable::parse(data).ok()?;
411         Some((start, exception_table))
412     }
413 }
414 
415 impl Module for JITModule {
isa(&self) -> &dyn TargetIsa416     fn isa(&self) -> &dyn TargetIsa {
417         &*self.isa
418     }
419 
declarations(&self) -> &ModuleDeclarations420     fn declarations(&self) -> &ModuleDeclarations {
421         &self.declarations
422     }
423 
declare_function( &mut self, name: &str, linkage: Linkage, signature: &ir::Signature, ) -> ModuleResult<FuncId>424     fn declare_function(
425         &mut self,
426         name: &str,
427         linkage: Linkage,
428         signature: &ir::Signature,
429     ) -> ModuleResult<FuncId> {
430         let (id, _linkage) = self
431             .declarations
432             .declare_function(name, linkage, signature)?;
433         Ok(id)
434     }
435 
declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId>436     fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId> {
437         let id = self.declarations.declare_anonymous_function(signature)?;
438         Ok(id)
439     }
440 
declare_data( &mut self, name: &str, linkage: Linkage, writable: bool, tls: bool, ) -> ModuleResult<DataId>441     fn declare_data(
442         &mut self,
443         name: &str,
444         linkage: Linkage,
445         writable: bool,
446         tls: bool,
447     ) -> ModuleResult<DataId> {
448         assert!(!tls, "JIT doesn't yet support TLS");
449         let (id, _linkage) = self
450             .declarations
451             .declare_data(name, linkage, writable, tls)?;
452         Ok(id)
453     }
454 
declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId>455     fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
456         assert!(!tls, "JIT doesn't yet support TLS");
457         let id = self.declarations.declare_anonymous_data(writable, tls)?;
458         Ok(id)
459     }
460 
define_function_with_control_plane( &mut self, id: FuncId, ctx: &mut cranelift_codegen::Context, ctrl_plane: &mut ControlPlane, ) -> ModuleResult<()>461     fn define_function_with_control_plane(
462         &mut self,
463         id: FuncId,
464         ctx: &mut cranelift_codegen::Context,
465         ctrl_plane: &mut ControlPlane,
466     ) -> ModuleResult<()> {
467         info!("defining function {}: {}", id, ctx.func.display());
468         let decl = self.declarations.get_function_decl(id);
469         if !decl.linkage.is_definable() {
470             return Err(ModuleError::InvalidImportDefinition(
471                 decl.linkage_name(id).into_owned(),
472             ));
473         }
474 
475         if !self.compiled_functions[id].is_none() {
476             return Err(ModuleError::DuplicateDefinition(
477                 decl.linkage_name(id).into_owned(),
478             ));
479         }
480 
481         // work around borrow-checker to allow reuse of ctx below
482         let res = ctx.compile(self.isa(), ctrl_plane)?;
483         let alignment = res.buffer.alignment as u64;
484         let compiled_code = ctx.compiled_code().unwrap();
485 
486         let align = alignment
487             .max(self.isa.function_alignment().minimum as u64)
488             .max(self.isa.symbol_alignment());
489 
490         let relocs = compiled_code
491             .buffer
492             .relocs()
493             .iter()
494             .map(|reloc| ModuleReloc::from_mach_reloc(reloc, &ctx.func, id))
495             .collect();
496 
497         #[cfg(feature = "wasmtime-unwinder")]
498         let wasmtime_exception_data = {
499             let mut exception_builder = wasmtime_unwinder::ExceptionTableBuilder::default();
500             exception_builder
501                 .add_func(0, compiled_code.buffer.call_sites())
502                 .map_err(|_| {
503                     ModuleError::Compilation(cranelift_codegen::CodegenError::Unsupported(
504                         "Invalid exception data".into(),
505                     ))
506                 })?;
507             Some(exception_builder.to_vec())
508         };
509 
510         let blob = self.compiled_functions[id].insert(CompiledBlob::new(
511             &mut *self.memory,
512             compiled_code.code_buffer(),
513             align,
514             relocs,
515             #[cfg(feature = "wasmtime-unwinder")]
516             wasmtime_exception_data,
517             JITMemoryKind::Executable,
518         )?);
519         let (ptr, size) = (blob.ptr(), blob.size());
520         self.record_function_for_perf(ptr, size, &decl.linkage_name(id));
521 
522         let range_start = ptr.addr();
523         let range_end = range_start + size;
524         // These will be sorted when we finalize.
525         self.code_ranges.push((range_start, range_end, id));
526 
527         self.functions_to_finalize.push(id);
528 
529         Ok(())
530     }
531 
define_function_bytes( &mut self, id: FuncId, alignment: u64, bytes: &[u8], relocs: &[ModuleReloc], ) -> ModuleResult<()>532     fn define_function_bytes(
533         &mut self,
534         id: FuncId,
535         alignment: u64,
536         bytes: &[u8],
537         relocs: &[ModuleReloc],
538     ) -> ModuleResult<()> {
539         info!("defining function {id} with bytes");
540         let decl = self.declarations.get_function_decl(id);
541         if !decl.linkage.is_definable() {
542             return Err(ModuleError::InvalidImportDefinition(
543                 decl.linkage_name(id).into_owned(),
544             ));
545         }
546 
547         if !self.compiled_functions[id].is_none() {
548             return Err(ModuleError::DuplicateDefinition(
549                 decl.linkage_name(id).into_owned(),
550             ));
551         }
552 
553         let align = alignment
554             .max(self.isa.function_alignment().minimum as u64)
555             .max(self.isa.symbol_alignment());
556 
557         let blob = self.compiled_functions[id].insert(CompiledBlob::new(
558             &mut *self.memory,
559             bytes,
560             align,
561             relocs.to_owned(),
562             #[cfg(feature = "wasmtime-unwinder")]
563             None,
564             JITMemoryKind::Executable,
565         )?);
566         let (ptr, size) = (blob.ptr(), blob.size());
567         self.record_function_for_perf(ptr, size, &decl.linkage_name(id));
568 
569         self.functions_to_finalize.push(id);
570 
571         Ok(())
572     }
573 
define_data(&mut self, id: DataId, data: &DataDescription) -> ModuleResult<()>574     fn define_data(&mut self, id: DataId, data: &DataDescription) -> ModuleResult<()> {
575         let decl = self.declarations.get_data_decl(id);
576         if !decl.linkage.is_definable() {
577             return Err(ModuleError::InvalidImportDefinition(
578                 decl.linkage_name(id).into_owned(),
579             ));
580         }
581 
582         if !self.compiled_data_objects[id].is_none() {
583             return Err(ModuleError::DuplicateDefinition(
584                 decl.linkage_name(id).into_owned(),
585             ));
586         }
587 
588         assert!(!decl.tls, "JIT doesn't yet support TLS");
589 
590         let &DataDescription {
591             ref init,
592             function_decls: _,
593             data_decls: _,
594             function_relocs: _,
595             data_relocs: _,
596             custom_segment_section: _,
597             align,
598             used: _,
599         } = data;
600 
601         let (align, kind) = if decl.writable {
602             (
603                 align.unwrap_or(WRITABLE_DATA_ALIGNMENT),
604                 JITMemoryKind::Writable,
605             )
606         } else {
607             (
608                 align.unwrap_or(READONLY_DATA_ALIGNMENT),
609                 JITMemoryKind::ReadOnly,
610             )
611         };
612 
613         let pointer_reloc = match self.isa.triple().pointer_width().unwrap() {
614             PointerWidth::U16 => panic!(),
615             PointerWidth::U32 => Reloc::Abs4,
616             PointerWidth::U64 => Reloc::Abs8,
617         };
618         let relocs = data.all_relocs(pointer_reloc).collect::<Vec<_>>();
619 
620         self.compiled_data_objects[id] = Some(match *init {
621             Init::Uninitialized => {
622                 panic!("data is not initialized yet");
623             }
624             Init::Zeros { size } => CompiledBlob::new_zeroed(
625                 &mut *self.memory,
626                 size.max(1),
627                 align,
628                 relocs,
629                 #[cfg(feature = "wasmtime-unwinder")]
630                 None,
631                 kind,
632             )?,
633             Init::Bytes { ref contents } => CompiledBlob::new(
634                 &mut *self.memory,
635                 if contents.is_empty() {
636                     // Make sure to allocate at least 1 byte. Allocating 0 bytes is UB. Previously
637                     // a dummy value was used, however as it turns out this will cause pc-relative
638                     // relocations to fail on architectures where pc-relative offsets are range
639                     // restricted as the dummy value is not close enough to the code that has the
640                     // pc-relative relocation.
641                     &[0]
642                 } else {
643                     &contents[..]
644                 },
645                 align,
646                 relocs,
647                 #[cfg(feature = "wasmtime-unwinder")]
648                 None,
649                 kind,
650             )?,
651         });
652 
653         self.data_objects_to_finalize.push(id);
654 
655         Ok(())
656     }
657 }
658 
659 #[cfg(not(windows))]
lookup_with_dlsym(name: &str) -> Option<*const u8>660 fn lookup_with_dlsym(name: &str) -> Option<*const u8> {
661     let c_str = CString::new(name).unwrap();
662     let c_str_ptr = c_str.as_ptr();
663     let sym = unsafe { libc::dlsym(libc::RTLD_DEFAULT, c_str_ptr) };
664     if sym.is_null() {
665         None
666     } else {
667         Some(sym as *const u8)
668     }
669 }
670 
671 #[cfg(windows)]
lookup_with_dlsym(name: &str) -> Option<*const u8>672 fn lookup_with_dlsym(name: &str) -> Option<*const u8> {
673     use std::os::windows::io::RawHandle;
674     use std::ptr;
675     use windows_sys::Win32::Foundation::HMODULE;
676     use windows_sys::Win32::System::LibraryLoader;
677 
678     const UCRTBASE: &[u8] = b"ucrtbase.dll\0";
679 
680     let c_str = CString::new(name).unwrap();
681     let c_str_ptr = c_str.as_ptr();
682 
683     unsafe {
684         let handles = [
685             // try to find the searched symbol in the currently running executable
686             ptr::null_mut(),
687             // try to find the searched symbol in local c runtime
688             LibraryLoader::GetModuleHandleA(UCRTBASE.as_ptr()) as RawHandle,
689         ];
690 
691         for handle in &handles {
692             let addr = LibraryLoader::GetProcAddress(*handle as HMODULE, c_str_ptr.cast());
693             match addr {
694                 None => continue,
695                 Some(addr) => return Some(addr as *const u8),
696             }
697         }
698 
699         None
700     }
701 }
702 
use_bti(isa_flags: &Vec<settings::Value>) -> bool703 fn use_bti(isa_flags: &Vec<settings::Value>) -> bool {
704     isa_flags
705         .iter()
706         .find(|&f| f.name == "use_bti")
707         .map_or(false, |f| f.as_bool().unwrap_or(false))
708 }
709 
710 const _ASSERT_JIT_MODULE_IS_SEND: () = {
assert_is_send<T: Send>()711     const fn assert_is_send<T: Send>() {}
712     assert_is_send::<JITModule>();
713 };
714