cranelift_jit/
backend.rs

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