1use crate::{compiled_blob::CompiledBlob, memory::BranchProtection, memory::Memory};
4use cranelift_codegen::binemit::Reloc;
5use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa};
6use cranelift_codegen::settings::Configurable;
7use cranelift_codegen::{self, ir, settings, FinalizedMachReloc};
8use cranelift_control::ControlPlane;
9use cranelift_entity::SecondaryMap;
10use cranelift_module::{
11 DataDescription, DataId, FuncId, Init, Linkage, Module, ModuleDeclarations, ModuleError,
12 ModuleReloc, ModuleRelocTarget, ModuleResult,
13};
14use log::debug;
15use std::cell::RefCell;
16use std::collections::HashMap;
17use std::convert::{TryFrom, TryInto};
18use std::ffi::CString;
19use std::io::Write;
20use std::ptr;
21use std::ptr::NonNull;
22use std::sync::atomic::{AtomicPtr, Ordering};
23use target_lexicon::PointerWidth;
24
25const WRITABLE_DATA_ALIGNMENT: u64 = 0x8;
26const READONLY_DATA_ALIGNMENT: u64 = 0x1;
27
28pub struct JITBuilder {
30 isa: OwnedTargetIsa,
31 symbols: HashMap<String, *const u8>,
32 lookup_symbols: Vec<Box<dyn Fn(&str) -> Option<*const u8>>>,
33 libcall_names: Box<dyn Fn(ir::LibCall) -> String + Send + Sync>,
34 hotswap_enabled: bool,
35}
36
37impl JITBuilder {
38 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 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 flag_builder.set("use_colocated_libcalls", "false").unwrap();
69 flag_builder.set("is_pic", "true").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 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 hotswap_enabled: false,
99 }
100 }
101
102 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(), ptr);
121 self
122 }
123
124 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(), ptr);
134 }
135 self
136 }
137
138 pub fn symbol_lookup_fn(
143 &mut self,
144 symbol_lookup_fn: Box<dyn Fn(&str) -> Option<*const u8>>,
145 ) -> &mut Self {
146 self.lookup_symbols.push(symbol_lookup_fn);
147 self
148 }
149
150 pub fn hotswap(&mut self, enabled: bool) -> &mut Self {
155 self.hotswap_enabled = enabled;
156 self
157 }
158}
159
160struct GotUpdate {
162 entry: NonNull<AtomicPtr<u8>>,
164
165 ptr: *const u8,
167}
168
169pub struct JITModule {
174 isa: OwnedTargetIsa,
175 hotswap_enabled: bool,
176 symbols: RefCell<HashMap<String, *const u8>>,
177 lookup_symbols: Vec<Box<dyn Fn(&str) -> Option<*const u8>>>,
178 libcall_names: Box<dyn Fn(ir::LibCall) -> String>,
179 memory: MemoryHandle,
180 declarations: ModuleDeclarations,
181 function_got_entries: SecondaryMap<FuncId, Option<NonNull<AtomicPtr<u8>>>>,
182 function_plt_entries: SecondaryMap<FuncId, Option<NonNull<[u8; 16]>>>,
183 data_object_got_entries: SecondaryMap<DataId, Option<NonNull<AtomicPtr<u8>>>>,
184 libcall_got_entries: HashMap<ir::LibCall, NonNull<AtomicPtr<u8>>>,
185 libcall_plt_entries: HashMap<ir::LibCall, NonNull<[u8; 16]>>,
186 compiled_functions: SecondaryMap<FuncId, Option<CompiledBlob>>,
187 compiled_data_objects: SecondaryMap<DataId, Option<CompiledBlob>>,
188 functions_to_finalize: Vec<FuncId>,
189 data_objects_to_finalize: Vec<DataId>,
190
191 pending_got_updates: Vec<GotUpdate>,
193}
194
195struct MemoryHandle {
197 code: Memory,
198 readonly: Memory,
199 writable: Memory,
200}
201
202impl JITModule {
203 pub unsafe fn free_memory(mut self) {
212 self.memory.code.free_memory();
213 self.memory.readonly.free_memory();
214 self.memory.writable.free_memory();
215 }
216
217 fn lookup_symbol(&self, name: &str) -> Option<*const u8> {
218 match self.symbols.borrow_mut().entry(name.to_owned()) {
219 std::collections::hash_map::Entry::Occupied(occ) => Some(*occ.get()),
220 std::collections::hash_map::Entry::Vacant(vac) => {
221 let ptr = self
222 .lookup_symbols
223 .iter()
224 .rev() .find_map(|lookup| lookup(name));
226 if let Some(ptr) = ptr {
227 vac.insert(ptr);
228 }
229 ptr
230 }
231 }
232 }
233
234 fn new_got_entry(&mut self, val: *const u8) -> NonNull<AtomicPtr<u8>> {
235 let got_entry = self
236 .memory
237 .writable
238 .allocate(
239 std::mem::size_of::<AtomicPtr<u8>>(),
240 std::mem::align_of::<AtomicPtr<u8>>().try_into().unwrap(),
241 )
242 .unwrap()
243 .cast::<AtomicPtr<u8>>();
244 unsafe {
245 std::ptr::write(got_entry, AtomicPtr::new(val as *mut _));
246 }
247 NonNull::new(got_entry).unwrap()
248 }
249
250 fn new_plt_entry(&mut self, got_entry: NonNull<AtomicPtr<u8>>) -> NonNull<[u8; 16]> {
251 let plt_entry = self
252 .memory
253 .code
254 .allocate(
255 std::mem::size_of::<[u8; 16]>(),
256 self.isa
257 .symbol_alignment()
258 .max(self.isa.function_alignment().minimum as u64),
259 )
260 .unwrap()
261 .cast::<[u8; 16]>();
262 unsafe {
263 Self::write_plt_entry_bytes(plt_entry, got_entry);
264 }
265 NonNull::new(plt_entry).unwrap()
266 }
267
268 fn new_func_plt_entry(&mut self, id: FuncId, val: *const u8) {
269 let got_entry = self.new_got_entry(val);
270 self.function_got_entries[id] = Some(got_entry);
271 let plt_entry = self.new_plt_entry(got_entry);
272 self.record_function_for_perf(
273 plt_entry.as_ptr().cast(),
274 std::mem::size_of::<[u8; 16]>(),
275 &format!(
276 "{}@plt",
277 self.declarations.get_function_decl(id).linkage_name(id)
278 ),
279 );
280 self.function_plt_entries[id] = Some(plt_entry);
281 }
282
283 fn new_data_got_entry(&mut self, id: DataId, val: *const u8) {
284 let got_entry = self.new_got_entry(val);
285 self.data_object_got_entries[id] = Some(got_entry);
286 }
287
288 unsafe fn write_plt_entry_bytes(plt_ptr: *mut [u8; 16], got_ptr: NonNull<AtomicPtr<u8>>) {
289 assert!(
290 cfg!(target_arch = "x86_64"),
291 "PLT is currently only supported on x86_64"
292 );
293 let mut plt_val = [
295 0xff, 0x25, 0, 0, 0, 0, 0x0f, 0x0b, 0x0f, 0x0b, 0x0f, 0x0b, 0x0f, 0x0b, 0x0f, 0x0b,
296 ];
297 let what = got_ptr.as_ptr() as isize - 4;
298 let at = plt_ptr as isize + 2;
299 plt_val[2..6].copy_from_slice(&i32::to_ne_bytes(i32::try_from(what - at).unwrap()));
300 std::ptr::write(plt_ptr, plt_val);
301 }
302
303 fn get_address(&self, name: &ModuleRelocTarget) -> *const u8 {
304 match *name {
305 ModuleRelocTarget::User { .. } => {
306 let (name, linkage) = if ModuleDeclarations::is_function(name) {
307 if self.hotswap_enabled {
308 return self.get_plt_address(name);
309 } else {
310 let func_id = FuncId::from_name(name);
311 match &self.compiled_functions[func_id] {
312 Some(compiled) => return compiled.ptr,
313 None => {
314 let decl = self.declarations.get_function_decl(func_id);
315 (&decl.name, decl.linkage)
316 }
317 }
318 }
319 } else {
320 let data_id = DataId::from_name(name);
321 match &self.compiled_data_objects[data_id] {
322 Some(compiled) => return compiled.ptr,
323 None => {
324 let decl = self.declarations.get_data_decl(data_id);
325 (&decl.name, decl.linkage)
326 }
327 }
328 };
329 let name = name
330 .as_ref()
331 .expect("anonymous symbol must be defined locally");
332 if let Some(ptr) = self.lookup_symbol(name) {
333 ptr
334 } else if linkage == Linkage::Preemptible {
335 0 as *const u8
336 } else {
337 panic!("can't resolve symbol {}", name);
338 }
339 }
340 ModuleRelocTarget::LibCall(ref libcall) => {
341 let sym = (self.libcall_names)(*libcall);
342 self.lookup_symbol(&sym)
343 .unwrap_or_else(|| panic!("can't resolve libcall {}", sym))
344 }
345 _ => panic!("invalid name"),
346 }
347 }
348
349 pub fn read_got_entry(&self, func_id: FuncId) -> *const u8 {
353 let got_entry = self.function_got_entries[func_id].unwrap();
354 unsafe { got_entry.as_ref() }.load(Ordering::SeqCst)
355 }
356
357 fn get_got_address(&self, name: &ModuleRelocTarget) -> NonNull<AtomicPtr<u8>> {
358 match *name {
359 ModuleRelocTarget::User { .. } => {
360 if ModuleDeclarations::is_function(name) {
361 let func_id = FuncId::from_name(name);
362 self.function_got_entries[func_id].unwrap()
363 } else {
364 let data_id = DataId::from_name(name);
365 self.data_object_got_entries[data_id].unwrap()
366 }
367 }
368 ModuleRelocTarget::LibCall(ref libcall) => *self
369 .libcall_got_entries
370 .get(libcall)
371 .unwrap_or_else(|| panic!("can't resolve libcall {}", libcall)),
372 _ => panic!("invalid name"),
373 }
374 }
375
376 fn get_plt_address(&self, name: &ModuleRelocTarget) -> *const u8 {
377 match *name {
378 ModuleRelocTarget::User { .. } => {
379 if ModuleDeclarations::is_function(name) {
380 let func_id = FuncId::from_name(name);
381 self.function_plt_entries[func_id]
382 .unwrap()
383 .as_ptr()
384 .cast::<u8>()
385 } else {
386 unreachable!("PLT relocations can only have functions as target");
387 }
388 }
389 ModuleRelocTarget::LibCall(ref libcall) => self
390 .libcall_plt_entries
391 .get(libcall)
392 .unwrap_or_else(|| panic!("can't resolve libcall {}", libcall))
393 .as_ptr()
394 .cast::<u8>(),
395 _ => panic!("invalid name"),
396 }
397 }
398
399 pub fn get_finalized_function(&self, func_id: FuncId) -> (*const u8, usize) {
404 let info = &self.compiled_functions[func_id];
405
406 assert!(
407 !self.functions_to_finalize.iter().any(|x| *x == func_id),
408 "function not yet finalized"
409 );
410
411 let blob = info
412 .as_ref()
413 .expect("function must be compiled before it can be finalized");
414
415 (blob.ptr, blob.size)
416 }
417
418 pub fn get_finalized_data(&self, data_id: DataId) -> (*const u8, usize) {
423 let info = &self.compiled_data_objects[data_id];
424 assert!(
425 !self.data_objects_to_finalize.iter().any(|x| *x == data_id),
426 "data object not yet finalized"
427 );
428 let compiled = info
429 .as_ref()
430 .expect("data object must be compiled before it can be finalized");
431
432 (compiled.ptr, compiled.size)
433 }
434
435 fn record_function_for_perf(&self, ptr: *mut u8, size: usize, name: &str) {
436 if cfg!(unix) && ::std::env::var_os("PERF_BUILDID_DIR").is_some() {
442 let mut map_file = ::std::fs::OpenOptions::new()
443 .create(true)
444 .append(true)
445 .open(format!("/tmp/perf-{}.map", ::std::process::id()))
446 .unwrap();
447
448 let _ = writeln!(map_file, "{:x} {:x} {}", ptr as usize, size, name);
449 }
450 }
451
452 pub fn finalize_definitions(&mut self) -> ModuleResult<()> {
461 for func in std::mem::take(&mut self.functions_to_finalize) {
462 let decl = self.declarations.get_function_decl(func);
463 assert!(decl.linkage.is_definable());
464 let func = self.compiled_functions[func]
465 .as_ref()
466 .expect("function must be compiled before it can be finalized");
467 func.perform_relocations(
468 |name| self.get_address(name),
469 |name| self.get_got_address(name).as_ptr().cast(),
470 |name| self.get_plt_address(name),
471 );
472 }
473
474 for data in std::mem::take(&mut self.data_objects_to_finalize) {
475 let decl = self.declarations.get_data_decl(data);
476 assert!(decl.linkage.is_definable());
477 let data = self.compiled_data_objects[data]
478 .as_ref()
479 .expect("data object must be compiled before it can be finalized");
480 data.perform_relocations(
481 |name| self.get_address(name),
482 |name| self.get_got_address(name).as_ptr().cast(),
483 |name| self.get_plt_address(name),
484 );
485 }
486
487 self.memory.readonly.set_readonly()?;
489 self.memory.code.set_readable_and_executable()?;
490
491 for update in self.pending_got_updates.drain(..) {
492 unsafe { update.entry.as_ref() }.store(update.ptr as *mut _, Ordering::SeqCst);
493 }
494 Ok(())
495 }
496
497 pub fn new(builder: JITBuilder) -> Self {
499 if builder.hotswap_enabled {
500 assert!(
501 builder.isa.flags().is_pic(),
502 "Hotswapping requires PIC code"
503 );
504 }
505
506 let branch_protection =
507 if cfg!(target_arch = "aarch64") && use_bti(&builder.isa.isa_flags()) {
508 BranchProtection::BTI
509 } else {
510 BranchProtection::None
511 };
512 let mut module = Self {
513 isa: builder.isa,
514 hotswap_enabled: builder.hotswap_enabled,
515 symbols: RefCell::new(builder.symbols),
516 lookup_symbols: builder.lookup_symbols,
517 libcall_names: builder.libcall_names,
518 memory: MemoryHandle {
519 code: Memory::new(branch_protection),
520 readonly: Memory::new(BranchProtection::None),
522 writable: Memory::new(BranchProtection::None),
523 },
524 declarations: ModuleDeclarations::default(),
525 function_got_entries: SecondaryMap::new(),
526 function_plt_entries: SecondaryMap::new(),
527 data_object_got_entries: SecondaryMap::new(),
528 libcall_got_entries: HashMap::new(),
529 libcall_plt_entries: HashMap::new(),
530 compiled_functions: SecondaryMap::new(),
531 compiled_data_objects: SecondaryMap::new(),
532 functions_to_finalize: Vec::new(),
533 data_objects_to_finalize: Vec::new(),
534 pending_got_updates: Vec::new(),
535 };
536
537 let all_libcalls = if module.isa.flags().is_pic() {
539 ir::LibCall::all_libcalls()
540 } else {
541 &[] };
543 for &libcall in all_libcalls {
544 let sym = (module.libcall_names)(libcall);
545 let addr = if let Some(addr) = module.lookup_symbol(&sym) {
546 addr
547 } else {
548 continue;
549 };
550 let got_entry = module.new_got_entry(addr);
551 module.libcall_got_entries.insert(libcall, got_entry);
552 let plt_entry = module.new_plt_entry(got_entry);
553 module.libcall_plt_entries.insert(libcall, plt_entry);
554 }
555
556 module
557 }
558
559 pub fn prepare_for_function_redefine(&mut self, func_id: FuncId) -> ModuleResult<()> {
564 assert!(self.hotswap_enabled, "Hotswap support is not enabled");
565 let decl = self.declarations.get_function_decl(func_id);
566 if !decl.linkage.is_definable() {
567 return Err(ModuleError::InvalidImportDefinition(
568 decl.linkage_name(func_id).into_owned(),
569 ));
570 }
571
572 if self.compiled_functions[func_id].is_none() {
573 return Err(ModuleError::Backend(anyhow::anyhow!(
574 "Tried to redefine not yet defined function {}",
575 decl.linkage_name(func_id),
576 )));
577 }
578
579 self.compiled_functions[func_id] = None;
580
581 Ok(())
584 }
585}
586
587impl Module for JITModule {
588 fn isa(&self) -> &dyn TargetIsa {
589 &*self.isa
590 }
591
592 fn declarations(&self) -> &ModuleDeclarations {
593 &self.declarations
594 }
595
596 fn declare_function(
597 &mut self,
598 name: &str,
599 linkage: Linkage,
600 signature: &ir::Signature,
601 ) -> ModuleResult<FuncId> {
602 let (id, linkage) = self
603 .declarations
604 .declare_function(name, linkage, signature)?;
605 if self.function_got_entries[id].is_none() && self.isa.flags().is_pic() {
606 let val = if linkage == Linkage::Import {
608 self.lookup_symbol(name).unwrap_or(std::ptr::null())
609 } else {
610 std::ptr::null()
611 };
612 self.new_func_plt_entry(id, val);
613 }
614 Ok(id)
615 }
616
617 fn declare_anonymous_function(&mut self, signature: &ir::Signature) -> ModuleResult<FuncId> {
618 let id = self.declarations.declare_anonymous_function(signature)?;
619 if self.isa.flags().is_pic() {
620 self.new_func_plt_entry(id, std::ptr::null());
621 }
622 Ok(id)
623 }
624
625 fn declare_data(
626 &mut self,
627 name: &str,
628 linkage: Linkage,
629 writable: bool,
630 tls: bool,
631 ) -> ModuleResult<DataId> {
632 assert!(!tls, "JIT doesn't yet support TLS");
633 let (id, linkage) = self
634 .declarations
635 .declare_data(name, linkage, writable, tls)?;
636 if self.data_object_got_entries[id].is_none() && self.isa.flags().is_pic() {
637 let val = if linkage == Linkage::Import {
639 self.lookup_symbol(name).unwrap_or(std::ptr::null())
640 } else {
641 std::ptr::null()
642 };
643 self.new_data_got_entry(id, val);
644 }
645 Ok(id)
646 }
647
648 fn declare_anonymous_data(&mut self, writable: bool, tls: bool) -> ModuleResult<DataId> {
649 assert!(!tls, "JIT doesn't yet support TLS");
650 let id = self.declarations.declare_anonymous_data(writable, tls)?;
651 if self.isa.flags().is_pic() {
652 self.new_data_got_entry(id, std::ptr::null());
653 }
654 Ok(id)
655 }
656
657 fn define_function_with_control_plane(
658 &mut self,
659 id: FuncId,
660 ctx: &mut cranelift_codegen::Context,
661 ctrl_plane: &mut ControlPlane,
662 ) -> ModuleResult<()> {
663 debug!("defining function {}: {}", id, ctx.func.display());
664 let decl = self.declarations.get_function_decl(id);
665 if !decl.linkage.is_definable() {
666 return Err(ModuleError::InvalidImportDefinition(
667 decl.linkage_name(id).into_owned(),
668 ));
669 }
670
671 if !self.compiled_functions[id].is_none() {
672 return Err(ModuleError::DuplicateDefinition(
673 decl.linkage_name(id).into_owned(),
674 ));
675 }
676
677 if self.hotswap_enabled {
678 for func in ctx.func.dfg.ext_funcs.values_mut() {
681 func.colocated = false;
682 }
683
684 for gv in ctx.func.global_values.values_mut() {
685 match gv {
686 ir::GlobalValueData::Symbol { colocated, .. } => *colocated = false,
687 _ => {}
688 }
689 }
690 }
691
692 let res = ctx.compile(self.isa(), ctrl_plane)?;
694 let alignment = res.buffer.alignment as u64;
695 let compiled_code = ctx.compiled_code().unwrap();
696
697 let size = compiled_code.code_info().total_size as usize;
698 let align = alignment
699 .max(self.isa.function_alignment().minimum as u64)
700 .max(self.isa.symbol_alignment());
701 let ptr = self
702 .memory
703 .code
704 .allocate(size, align)
705 .map_err(|e| ModuleError::Allocation {
706 message: "unable to alloc function",
707 err: e,
708 })?;
709
710 {
711 let mem = unsafe { std::slice::from_raw_parts_mut(ptr, size) };
712 mem.copy_from_slice(compiled_code.code_buffer());
713 }
714
715 let relocs = compiled_code
716 .buffer
717 .relocs()
718 .iter()
719 .map(|reloc| ModuleReloc::from_mach_reloc(reloc, &ctx.func))
720 .collect();
721
722 self.record_function_for_perf(ptr, size, &decl.linkage_name(id));
723 self.compiled_functions[id] = Some(CompiledBlob { ptr, size, relocs });
724
725 if self.isa.flags().is_pic() {
726 self.pending_got_updates.push(GotUpdate {
727 entry: self.function_got_entries[id].unwrap(),
728 ptr,
729 })
730 }
731
732 if self.hotswap_enabled {
733 self.compiled_functions[id]
734 .as_ref()
735 .unwrap()
736 .perform_relocations(
737 |name| match *name {
738 ModuleRelocTarget::User { .. } => {
739 unreachable!("non GOT or PLT relocation in function {} to {}", id, name)
740 }
741 ModuleRelocTarget::LibCall(ref libcall) => self
742 .libcall_plt_entries
743 .get(libcall)
744 .unwrap_or_else(|| panic!("can't resolve libcall {}", libcall))
745 .as_ptr()
746 .cast::<u8>(),
747 _ => panic!("invalid name"),
748 },
749 |name| self.get_got_address(name).as_ptr().cast(),
750 |name| self.get_plt_address(name),
751 );
752 } else {
753 self.functions_to_finalize.push(id);
754 }
755
756 Ok(())
757 }
758
759 fn define_function_bytes(
760 &mut self,
761 id: FuncId,
762 func: &ir::Function,
763 alignment: u64,
764 bytes: &[u8],
765 relocs: &[FinalizedMachReloc],
766 ) -> ModuleResult<()> {
767 debug!("defining function {} with bytes", id);
768 let decl = self.declarations.get_function_decl(id);
769 if !decl.linkage.is_definable() {
770 return Err(ModuleError::InvalidImportDefinition(
771 decl.linkage_name(id).into_owned(),
772 ));
773 }
774
775 if !self.compiled_functions[id].is_none() {
776 return Err(ModuleError::DuplicateDefinition(
777 decl.linkage_name(id).into_owned(),
778 ));
779 }
780
781 let size = bytes.len();
782 let align = alignment
783 .max(self.isa.function_alignment().minimum as u64)
784 .max(self.isa.symbol_alignment());
785 let ptr = self
786 .memory
787 .code
788 .allocate(size, align)
789 .map_err(|e| ModuleError::Allocation {
790 message: "unable to alloc function bytes",
791 err: e,
792 })?;
793
794 unsafe {
795 ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, size);
796 }
797
798 self.record_function_for_perf(ptr, size, &decl.linkage_name(id));
799 self.compiled_functions[id] = Some(CompiledBlob {
800 ptr,
801 size,
802 relocs: relocs
803 .iter()
804 .map(|reloc| ModuleReloc::from_mach_reloc(reloc, func))
805 .collect(),
806 });
807
808 if self.isa.flags().is_pic() {
809 self.pending_got_updates.push(GotUpdate {
810 entry: self.function_got_entries[id].unwrap(),
811 ptr,
812 })
813 }
814
815 if self.hotswap_enabled {
816 self.compiled_functions[id]
817 .as_ref()
818 .unwrap()
819 .perform_relocations(
820 |name| unreachable!("non GOT or PLT relocation in function {} to {}", id, name),
821 |name| self.get_got_address(name).as_ptr().cast(),
822 |name| self.get_plt_address(name),
823 );
824 } else {
825 self.functions_to_finalize.push(id);
826 }
827
828 Ok(())
829 }
830
831 fn define_data(&mut self, id: DataId, data: &DataDescription) -> ModuleResult<()> {
832 let decl = self.declarations.get_data_decl(id);
833 if !decl.linkage.is_definable() {
834 return Err(ModuleError::InvalidImportDefinition(
835 decl.linkage_name(id).into_owned(),
836 ));
837 }
838
839 if !self.compiled_data_objects[id].is_none() {
840 return Err(ModuleError::DuplicateDefinition(
841 decl.linkage_name(id).into_owned(),
842 ));
843 }
844
845 assert!(!decl.tls, "JIT doesn't yet support TLS");
846
847 let &DataDescription {
848 ref init,
849 function_decls: _,
850 data_decls: _,
851 function_relocs: _,
852 data_relocs: _,
853 custom_segment_section: _,
854 align,
855 } = data;
856
857 let size = init.size();
858 let ptr = if decl.writable {
859 self.memory
860 .writable
861 .allocate(size, align.unwrap_or(WRITABLE_DATA_ALIGNMENT))
862 .map_err(|e| ModuleError::Allocation {
863 message: "unable to alloc writable data",
864 err: e,
865 })?
866 } else {
867 self.memory
868 .readonly
869 .allocate(size, align.unwrap_or(READONLY_DATA_ALIGNMENT))
870 .map_err(|e| ModuleError::Allocation {
871 message: "unable to alloc readonly data",
872 err: e,
873 })?
874 };
875
876 match *init {
877 Init::Uninitialized => {
878 panic!("data is not initialized yet");
879 }
880 Init::Zeros { .. } => {
881 unsafe { ptr::write_bytes(ptr, 0, size) };
882 }
883 Init::Bytes { ref contents } => {
884 let src = contents.as_ptr();
885 unsafe { ptr::copy_nonoverlapping(src, ptr, size) };
886 }
887 }
888
889 let pointer_reloc = match self.isa.triple().pointer_width().unwrap() {
890 PointerWidth::U16 => panic!(),
891 PointerWidth::U32 => Reloc::Abs4,
892 PointerWidth::U64 => Reloc::Abs8,
893 };
894 let relocs = data.all_relocs(pointer_reloc).collect::<Vec<_>>();
895
896 self.compiled_data_objects[id] = Some(CompiledBlob { ptr, size, relocs });
897 self.data_objects_to_finalize.push(id);
898 if self.isa.flags().is_pic() {
899 self.pending_got_updates.push(GotUpdate {
900 entry: self.data_object_got_entries[id].unwrap(),
901 ptr,
902 })
903 }
904
905 Ok(())
906 }
907
908 fn get_name(&self, name: &str) -> Option<cranelift_module::FuncOrDataId> {
909 self.declarations().get_name(name)
910 }
911
912 fn target_config(&self) -> cranelift_codegen::isa::TargetFrontendConfig {
913 self.isa().frontend_config()
914 }
915
916 fn make_context(&self) -> cranelift_codegen::Context {
917 let mut ctx = cranelift_codegen::Context::new();
918 ctx.func.signature.call_conv = self.isa().default_call_conv();
919 ctx
920 }
921
922 fn clear_context(&self, ctx: &mut cranelift_codegen::Context) {
923 ctx.clear();
924 ctx.func.signature.call_conv = self.isa().default_call_conv();
925 }
926
927 fn make_signature(&self) -> ir::Signature {
928 ir::Signature::new(self.isa().default_call_conv())
929 }
930
931 fn clear_signature(&self, sig: &mut ir::Signature) {
932 sig.clear(self.isa().default_call_conv());
933 }
934}
935
936#[cfg(not(windows))]
937fn lookup_with_dlsym(name: &str) -> Option<*const u8> {
938 let c_str = CString::new(name).unwrap();
939 let c_str_ptr = c_str.as_ptr();
940 let sym = unsafe { libc::dlsym(libc::RTLD_DEFAULT, c_str_ptr) };
941 if sym.is_null() {
942 None
943 } else {
944 Some(sym as *const u8)
945 }
946}
947
948#[cfg(windows)]
949fn lookup_with_dlsym(name: &str) -> Option<*const u8> {
950 use std::os::windows::io::RawHandle;
951 use windows_sys::Win32::Foundation::HMODULE;
952 use windows_sys::Win32::System::LibraryLoader;
953
954 const UCRTBASE: &[u8] = b"ucrtbase.dll\0";
955
956 let c_str = CString::new(name).unwrap();
957 let c_str_ptr = c_str.as_ptr();
958
959 unsafe {
960 let handles = [
961 ptr::null_mut(),
963 LibraryLoader::GetModuleHandleA(UCRTBASE.as_ptr()) as RawHandle,
965 ];
966
967 for handle in &handles {
968 let addr = LibraryLoader::GetProcAddress(*handle as HMODULE, c_str_ptr.cast());
969 match addr {
970 None => continue,
971 Some(addr) => return Some(addr as *const u8),
972 }
973 }
974
975 None
976 }
977}
978
979fn use_bti(isa_flags: &Vec<settings::Value>) -> bool {
980 isa_flags
981 .iter()
982 .find(|&f| f.name == "use_bti")
983 .map_or(false, |f| f.as_bool().unwrap_or(false))
984}