cranelift_jit/
compiled_blob.rs1use cranelift_codegen::binemit::Reloc;
2use cranelift_module::ModuleReloc;
3use cranelift_module::ModuleRelocTarget;
4
5unsafe fn modify_inst32(iptr: *mut u32, modifier: impl FnOnce(u32) -> u32) {
8 let inst = iptr.read_unaligned();
9 let new_inst = modifier(inst);
10 iptr.write_unaligned(new_inst);
11}
12
13#[derive(Clone)]
14pub(crate) struct CompiledBlob {
15 pub(crate) ptr: *mut u8,
16 pub(crate) size: usize,
17 pub(crate) relocs: Vec<ModuleReloc>,
18}
19
20unsafe impl Send for CompiledBlob {}
21
22impl CompiledBlob {
23 pub(crate) fn perform_relocations(
24 &self,
25 get_address: impl Fn(&ModuleRelocTarget) -> *const u8,
26 get_got_entry: impl Fn(&ModuleRelocTarget) -> *const u8,
27 get_plt_entry: impl Fn(&ModuleRelocTarget) -> *const u8,
28 ) {
29 use std::ptr::write_unaligned;
30
31 for &ModuleReloc {
32 kind,
33 offset,
34 ref name,
35 addend,
36 } in &self.relocs
37 {
38 debug_assert!((offset as usize) < self.size);
39 let at = unsafe { self.ptr.offset(isize::try_from(offset).unwrap()) };
40 match kind {
41 Reloc::Abs4 => {
42 let base = get_address(name);
43 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
44 unsafe {
45 write_unaligned(at as *mut u32, u32::try_from(what as usize).unwrap())
46 };
47 }
48 Reloc::Abs8 => {
49 let base = get_address(name);
50 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
51 unsafe {
52 write_unaligned(at as *mut u64, u64::try_from(what as usize).unwrap())
53 };
54 }
55 Reloc::X86PCRel4 | Reloc::X86CallPCRel4 => {
56 let base = get_address(name);
57 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
58 let pcrel = i32::try_from((what as isize) - (at as isize)).unwrap();
59 unsafe { write_unaligned(at as *mut i32, pcrel) };
60 }
61 Reloc::X86GOTPCRel4 => {
62 let base = get_got_entry(name);
63 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
64 let pcrel = i32::try_from((what as isize) - (at as isize)).unwrap();
65 unsafe { write_unaligned(at as *mut i32, pcrel) };
66 }
67 Reloc::X86CallPLTRel4 => {
68 let base = get_plt_entry(name);
69 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
70 let pcrel = i32::try_from((what as isize) - (at as isize)).unwrap();
71 unsafe { write_unaligned(at as *mut i32, pcrel) };
72 }
73 Reloc::S390xPCRel32Dbl | Reloc::S390xPLTRel32Dbl => {
74 let base = get_address(name);
75 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
76 let pcrel = i32::try_from(((what as isize) - (at as isize)) >> 1).unwrap();
77 unsafe { write_unaligned(at as *mut i32, pcrel) };
78 }
79 Reloc::Arm64Call => {
80 let base = get_address(name);
81 let iptr = at as *mut u32;
83 let diff = ((base as isize) - (at as isize)) >> 2;
86 assert!((diff >> 26 == -1) || (diff >> 26 == 0));
91 let chop = 32 - 26;
94 let imm26 = (diff as u32) << chop >> chop;
95 unsafe { modify_inst32(iptr, |inst| inst | imm26) };
96 }
97 Reloc::Aarch64AdrGotPage21 => {
98 assert_eq!(addend, 0, "addend affects the address looked up in get_got_entry, which is currently only called with a symbol");
100 let what = get_got_entry(name);
101 let what_page = (what as usize) & !0xfff;
102 let at_page = (at as usize) & !0xfff;
103 let pcrel = (what_page as isize).checked_sub(at_page as isize).unwrap();
104 assert!(
105 (-1 << 32) <= (pcrel as i64) && (pcrel as i64) < (1 << 32),
106 "can't reach GOT page with ±4GB `adrp` instruction"
107 );
108 let val = pcrel >> 12;
109
110 let immlo = ((val as u32) & 0b11) << 29;
111 let immhi = (((val as u32) >> 2) & &0x7ffff) << 5;
112 let mask = !((0x7ffff << 5) | (0b11 << 29));
113 unsafe { modify_inst32(at as *mut u32, |adrp| (adrp & mask) | immlo | immhi) };
114 }
115 Reloc::Aarch64Ld64GotLo12Nc => {
116 assert_eq!(addend, 0);
118 let base = get_got_entry(name);
119 let what = base as u32;
120 assert_eq!(what & 0b111, 0);
121 let val = what >> 3;
122 let imm9 = (val & 0x1ff) << 10;
123 let mask = !(0x1ff << 10);
124 unsafe { modify_inst32(at as *mut u32, |ldr| (ldr & mask) | imm9) };
125 }
126 Reloc::RiscvCallPlt => {
127 let base = get_address(name);
133 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
134 let pcrel = i32::try_from((what as isize) - (at as isize)).unwrap() as u32;
135
136 let hi20 = pcrel.wrapping_add(0x800) & 0xFFFFF000;
150 let lo12 = pcrel.wrapping_sub(hi20) & 0xFFF;
151
152 unsafe {
153 let auipc_addr = at as *mut u32;
155 modify_inst32(auipc_addr, |auipc| (auipc & 0xFFF) | hi20);
156
157 let jalr_addr = at.offset(4) as *mut u32;
159 modify_inst32(jalr_addr, |jalr| (jalr & 0xFFFFF) | (lo12 << 20));
160 }
161 }
162 _ => unimplemented!(),
163 }
164 }
165 }
166}