Skip to content

Commit 136cd76

Browse files
committed
Insert veneers on arm64 in cranelift-jit where necessary (#12239)
* Remove unnecessary methods from JITModule Module impl * Fix range assertion in cranelift-jit Arm64Call reloc handling * Rename exception_data to wasmtime_exception_data It is a wasmtime specific format that doesn't match what cranelift-jit could register with the system unwinder in the future. * Move memory allocation into CompiledBlob In preparation for inserting veneers on arm64. * Respect addend for Arm64Call relocs * Insert veneers on arm64 in cranelift-jit where necessary * Rename const item
1 parent 9656606 commit 136cd76

File tree

6 files changed

+252
-199
lines changed

6 files changed

+252
-199
lines changed

cranelift/jit/src/backend.rs

Lines changed: 84 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use crate::{
44
compiled_blob::CompiledBlob,
5-
memory::{BranchProtection, JITMemoryProvider, SystemMemoryProvider},
5+
memory::{BranchProtection, JITMemoryKind, JITMemoryProvider, SystemMemoryProvider},
66
};
77
use cranelift_codegen::binemit::Reloc;
88
use cranelift_codegen::isa::{OwnedTargetIsa, TargetIsa};
@@ -19,7 +19,6 @@ use std::cell::RefCell;
1919
use std::collections::HashMap;
2020
use std::ffi::CString;
2121
use std::io::Write;
22-
use std::ptr;
2322
use target_lexicon::PointerWidth;
2423

2524
const WRITABLE_DATA_ALIGNMENT: u64 = 0x8;
@@ -217,7 +216,7 @@ impl JITModule {
217216
let (name, linkage) = if ModuleDeclarations::is_function(name) {
218217
let func_id = FuncId::from_name(name);
219218
match &self.compiled_functions[func_id] {
220-
Some(compiled) => return compiled.ptr,
219+
Some(compiled) => return compiled.ptr(),
221220
None => {
222221
let decl = self.declarations.get_function_decl(func_id);
223222
(&decl.name, decl.linkage)
@@ -226,7 +225,7 @@ impl JITModule {
226225
} else {
227226
let data_id = DataId::from_name(name);
228227
match &self.compiled_data_objects[data_id] {
229-
Some(compiled) => return compiled.ptr,
228+
Some(compiled) => return compiled.ptr(),
230229
None => {
231230
let decl = self.declarations.get_data_decl(data_id);
232231
(&decl.name, decl.linkage)
@@ -251,7 +250,7 @@ impl JITModule {
251250
}
252251
ModuleRelocTarget::FunctionOffset(func_id, offset) => {
253252
match &self.compiled_functions[*func_id] {
254-
Some(compiled) => return compiled.ptr.wrapping_add(*offset as usize),
253+
Some(compiled) => return compiled.ptr().wrapping_add(*offset as usize),
255254
None => todo!(),
256255
}
257256
}
@@ -271,7 +270,7 @@ impl JITModule {
271270
);
272271
info.as_ref()
273272
.expect("function must be compiled before it can be finalized")
274-
.ptr
273+
.ptr()
275274
}
276275

277276
/// Returns the address and size of a finalized data object.
@@ -288,10 +287,10 @@ impl JITModule {
288287
.as_ref()
289288
.expect("data object must be compiled before it can be finalized");
290289

291-
(compiled.ptr, compiled.size)
290+
(compiled.ptr(), compiled.size())
292291
}
293292

294-
fn record_function_for_perf(&self, ptr: *mut u8, size: usize, name: &str) {
293+
fn record_function_for_perf(&self, ptr: *const u8, size: usize, name: &str) {
295294
// The Linux perf tool supports JIT code via a /tmp/perf-$PID.map file,
296295
// which contains memory regions and their associated names. If we
297296
// are profiling with perf and saving binaries to PERF_BUILDID_DIR
@@ -407,8 +406,7 @@ impl JITModule {
407406
let data = self.compiled_functions[func]
408407
.as_ref()
409408
.unwrap()
410-
.exception_data
411-
.as_ref()?;
409+
.wasmtime_exception_data()?;
412410
let exception_table = wasmtime_unwinder::ExceptionTable::parse(data).ok()?;
413411
Some((start, exception_table))
414412
}
@@ -485,22 +483,9 @@ impl Module for JITModule {
485483
let alignment = res.buffer.alignment as u64;
486484
let compiled_code = ctx.compiled_code().unwrap();
487485

488-
let size = compiled_code.code_info().total_size as usize;
489486
let align = alignment
490487
.max(self.isa.function_alignment().minimum as u64)
491488
.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-
}
504489

505490
let relocs = compiled_code
506491
.buffer
@@ -509,22 +494,8 @@ impl Module for JITModule {
509494
.map(|reloc| ModuleReloc::from_mach_reloc(reloc, &ctx.func, id))
510495
.collect();
511496

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-
526497
#[cfg(feature = "wasmtime-unwinder")]
527-
{
498+
let wasmtime_exception_data = {
528499
let mut exception_builder = wasmtime_unwinder::ExceptionTableBuilder::default();
529500
exception_builder
530501
.add_func(0, compiled_code.buffer.call_sites())
@@ -533,9 +504,25 @@ impl Module for JITModule {
533504
"Invalid exception data".into(),
534505
))
535506
})?;
536-
self.compiled_functions[id].as_mut().unwrap().exception_data =
537-
Some(exception_builder.to_vec());
538-
}
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));
539526

540527
self.functions_to_finalize.push(id);
541528

@@ -563,30 +550,21 @@ impl Module for JITModule {
563550
));
564551
}
565552

566-
let size = bytes.len();
567553
let align = alignment
568554
.max(self.isa.function_alignment().minimum as u64)
569555
.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-
}
581556

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(),
557+
let blob = self.compiled_functions[id].insert(CompiledBlob::new(
558+
&mut *self.memory,
559+
bytes,
560+
align,
561+
relocs.to_owned(),
587562
#[cfg(feature = "wasmtime-unwinder")]
588-
exception_data: None,
589-
});
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));
590568

591569
self.functions_to_finalize.push(id);
592570

@@ -620,97 +598,62 @@ impl Module for JITModule {
620598
used: _,
621599
} = data;
622600

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-
})?
601+
let (align, kind) = if decl.writable {
602+
(
603+
align.unwrap_or(WRITABLE_DATA_ALIGNMENT),
604+
JITMemoryKind::Writable,
605+
)
636606
} 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-
})?
607+
(
608+
align.unwrap_or(READONLY_DATA_ALIGNMENT),
609+
JITMemoryKind::ReadOnly,
610+
)
643611
};
644612

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-
669613
let pointer_reloc = match self.isa.triple().pointer_width().unwrap() {
670614
PointerWidth::U16 => panic!(),
671615
PointerWidth::U32 => Reloc::Abs4,
672616
PointerWidth::U64 => Reloc::Abs8,
673617
};
674618
let relocs = data.all_relocs(pointer_reloc).collect::<Vec<_>>();
675619

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,
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+
)?,
682651
});
652+
683653
self.data_objects_to_finalize.push(id);
684654

685655
Ok(())
686656
}
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-
}
714657
}
715658

716659
#[cfg(not(windows))]
@@ -728,6 +671,7 @@ fn lookup_with_dlsym(name: &str) -> Option<*const u8> {
728671
#[cfg(windows)]
729672
fn lookup_with_dlsym(name: &str) -> Option<*const u8> {
730673
use std::os::windows::io::RawHandle;
674+
use std::ptr;
731675
use windows_sys::Win32::Foundation::HMODULE;
732676
use windows_sys::Win32::System::LibraryLoader;
733677

@@ -763,13 +707,7 @@ fn use_bti(isa_flags: &Vec<settings::Value>) -> bool {
763707
.map_or(false, |f| f.as_bool().unwrap_or(false))
764708
}
765709

766-
#[cfg(test)]
767-
mod tests {
768-
use super::*;
769-
770-
#[test]
771-
fn test_jit_module_is_send() {
772-
fn assert_is_send<T: Send>() {}
773-
assert_is_send::<JITModule>();
774-
}
775-
}
710+
const _ASSERT_JIT_MODULE_IS_SEND: () = {
711+
const fn assert_is_send<T: Send>() {}
712+
assert_is_send::<JITModule>();
713+
};

0 commit comments

Comments
 (0)