* Remove unused srcloc in MachReloc * Remove unused srcloc in MachTrap * Use `into_iter` on array in bench code to suppress a warning * Remove unused srcloc in MachCallSite
110 lines
4.9 KiB
Rust
110 lines
4.9 KiB
Rust
use cranelift_codegen::binemit::Reloc;
|
|
use cranelift_codegen::ir::ExternalName;
|
|
use cranelift_codegen::MachReloc;
|
|
use std::convert::TryFrom;
|
|
|
|
#[derive(Clone)]
|
|
pub(crate) struct CompiledBlob {
|
|
pub(crate) ptr: *mut u8,
|
|
pub(crate) size: usize,
|
|
pub(crate) relocs: Vec<MachReloc>,
|
|
}
|
|
|
|
impl CompiledBlob {
|
|
pub(crate) fn perform_relocations(
|
|
&self,
|
|
get_address: impl Fn(&ExternalName) -> *const u8,
|
|
get_got_entry: impl Fn(&ExternalName) -> *const u8,
|
|
get_plt_entry: impl Fn(&ExternalName) -> *const u8,
|
|
) {
|
|
use std::ptr::write_unaligned;
|
|
|
|
for &MachReloc {
|
|
kind,
|
|
offset,
|
|
ref name,
|
|
addend,
|
|
} in &self.relocs
|
|
{
|
|
debug_assert!((offset as usize) < self.size);
|
|
let at = unsafe { self.ptr.offset(isize::try_from(offset).unwrap()) };
|
|
match kind {
|
|
Reloc::Abs4 => {
|
|
let base = get_address(name);
|
|
let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
|
|
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
|
|
unsafe {
|
|
write_unaligned(at as *mut u32, u32::try_from(what as usize).unwrap())
|
|
};
|
|
}
|
|
Reloc::Abs8 => {
|
|
let base = get_address(name);
|
|
let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
|
|
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
|
|
unsafe {
|
|
write_unaligned(at as *mut u64, u64::try_from(what as usize).unwrap())
|
|
};
|
|
}
|
|
Reloc::X86PCRel4 | Reloc::X86CallPCRel4 => {
|
|
let base = get_address(name);
|
|
let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
|
|
let pcrel = i32::try_from((what as isize) - (at as isize)).unwrap();
|
|
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
|
|
unsafe {
|
|
write_unaligned(at as *mut i32, pcrel)
|
|
};
|
|
}
|
|
Reloc::X86GOTPCRel4 => {
|
|
let base = get_got_entry(name);
|
|
let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
|
|
let pcrel = i32::try_from((what as isize) - (at as isize)).unwrap();
|
|
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
|
|
unsafe {
|
|
write_unaligned(at as *mut i32, pcrel)
|
|
};
|
|
}
|
|
Reloc::X86CallPLTRel4 => {
|
|
let base = get_plt_entry(name);
|
|
let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
|
|
let pcrel = i32::try_from((what as isize) - (at as isize)).unwrap();
|
|
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
|
|
unsafe {
|
|
write_unaligned(at as *mut i32, pcrel)
|
|
};
|
|
}
|
|
Reloc::S390xPCRel32Dbl => {
|
|
let base = get_address(name);
|
|
let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
|
|
let pcrel = i32::try_from(((what as isize) - (at as isize)) >> 1).unwrap();
|
|
#[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]
|
|
unsafe {
|
|
write_unaligned(at as *mut i32, pcrel)
|
|
};
|
|
}
|
|
Reloc::Arm64Call => {
|
|
let base = get_address(name);
|
|
// The instruction is 32 bits long.
|
|
let iptr = at as *mut u32;
|
|
// The offset encoded in the `bl` instruction is the
|
|
// number of bytes divided by 4.
|
|
let diff = ((base as isize) - (at as isize)) >> 2;
|
|
// Sign propagating right shift disposes of the
|
|
// included bits, so the result is expected to be
|
|
// either all sign bits or 0, depending on if the original
|
|
// value was negative or positive.
|
|
assert!((diff >> 26 == -1) || (diff >> 26 == 0));
|
|
// The lower 26 bits of the `bl` instruction form the
|
|
// immediate offset argument.
|
|
let chop = 32 - 26;
|
|
let imm26 = (diff as u32) << chop >> chop;
|
|
let ins = unsafe { iptr.read_unaligned() } | imm26;
|
|
unsafe {
|
|
iptr.write_unaligned(ins);
|
|
}
|
|
}
|
|
_ => unimplemented!(),
|
|
}
|
|
}
|
|
}
|
|
}
|