Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/jit/src/backend.rs
3063 views
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()`.
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()`.
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()`.
86
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).
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.
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.
141
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`].
152
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.
192
pub unsafe fn free_memory(mut self) {
193
self.memory.free_memory();
194
}
195
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
213
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.
265
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.
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
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
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`.
352
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")]
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 {
416
fn isa(&self) -> &dyn TargetIsa {
417
&*self.isa
418
}
419
420
fn declarations(&self) -> &ModuleDeclarations {
421
&self.declarations
422
}
423
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
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
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
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
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
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
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))]
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)]
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
703
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: () = {
711
const fn assert_is_send<T: Send>() {}
712
assert_is_send::<JITModule>();
713
};
714
715