Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/jit/src/backend.rs
1692 views
1
//! Defines `JITModule`.
2
3
use crate::{
4
compiled_blob::CompiledBlob,
5
memory::{BranchProtection, 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 std::ptr;
23
use target_lexicon::PointerWidth;
24
25
const WRITABLE_DATA_ALIGNMENT: u64 = 0x8;
26
const READONLY_DATA_ALIGNMENT: u64 = 0x1;
27
28
/// A builder for `JITModule`.
29
pub 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
37
impl 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)]
163
struct SendWrapper<T>(T);
164
unsafe 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.
170
pub 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
184
impl 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
417
impl 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))]
717
fn 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)]
729
fn 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
759
fn 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
}
765
766