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 #[cfg(feature = "wasmtime-unwinder")]
19 pub(crate) exception_data: Option<Vec<u8>>,
20}
21
22unsafe impl Send for CompiledBlob {}
23
24impl CompiledBlob {
25 pub(crate) fn perform_relocations(
26 &self,
27 get_address: impl Fn(&ModuleRelocTarget) -> *const u8,
28 ) {
29 use std::ptr::write_unaligned;
30
31 for (
32 i,
33 &ModuleReloc {
34 kind,
35 offset,
36 ref name,
37 addend,
38 },
39 ) in self.relocs.iter().enumerate()
40 {
41 debug_assert!((offset as usize) < self.size);
42 let at = unsafe { self.ptr.offset(isize::try_from(offset).unwrap()) };
43 match kind {
44 Reloc::Abs4 => {
45 let base = get_address(name);
46 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
47 unsafe {
48 write_unaligned(at as *mut u32, u32::try_from(what as usize).unwrap())
49 };
50 }
51 Reloc::Abs8 => {
52 let base = get_address(name);
53 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
54 unsafe {
55 write_unaligned(at as *mut u64, u64::try_from(what as usize).unwrap())
56 };
57 }
58 Reloc::X86PCRel4 | Reloc::X86CallPCRel4 => {
59 let base = get_address(name);
60 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
61 let pcrel = i32::try_from((what as isize) - (at as isize)).unwrap();
62 unsafe { write_unaligned(at as *mut i32, pcrel) };
63 }
64 Reloc::X86GOTPCRel4 => {
65 panic!("GOT relocation shouldn't be generated when !is_pic");
66 }
67 Reloc::X86CallPLTRel4 => {
68 panic!("PLT relocation shouldn't be generated when !is_pic");
69 }
70 Reloc::S390xPCRel32Dbl | Reloc::S390xPLTRel32Dbl => {
71 let base = get_address(name);
72 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
73 let pcrel = i32::try_from(((what as isize) - (at as isize)) >> 1).unwrap();
74 unsafe { write_unaligned(at as *mut i32, pcrel) };
75 }
76 Reloc::Arm64Call => {
77 let base = get_address(name);
78 let iptr = at as *mut u32;
80 let diff = ((base as isize) - (at as isize)) >> 2;
83 assert!((diff >> 26 == -1) || (diff >> 26 == 0));
88 let chop = 32 - 26;
91 let imm26 = (diff as u32) << chop >> chop;
92 unsafe { modify_inst32(iptr, |inst| inst | imm26) };
93 }
94 Reloc::Aarch64AdrGotPage21 => {
95 panic!("GOT relocation shouldn't be generated when !is_pic");
96 }
97 Reloc::Aarch64Ld64GotLo12Nc => {
98 panic!("GOT relocation shouldn't be generated when !is_pic");
99 }
100 Reloc::Aarch64AdrPrelPgHi21 => {
101 let base = get_address(name);
102 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
103 let get_page = |x| x & (!0xfff);
104 let pcrel = i32::try_from(get_page(what as isize) - get_page(at as isize))
105 .unwrap()
106 .cast_unsigned();
107 let iptr = at as *mut u32;
108 let hi21 = pcrel >> 12;
109 let lo = (hi21 & 0x3) << 29;
110 let hi = (hi21 & 0x1ffffc) << 3;
111 unsafe { modify_inst32(iptr, |inst| inst | lo | hi) };
112 }
113 Reloc::Aarch64AddAbsLo12Nc => {
114 let base = get_address(name);
115 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
116 let iptr = at as *mut u32;
117 let imm12 = (what.addr() as u32 & 0xfff) << 10;
118 unsafe { modify_inst32(iptr, |inst| inst | imm12) };
119 }
120 Reloc::RiscvCallPlt => {
121 let base = get_address(name);
127 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
128 let pcrel = i32::try_from((what as isize) - (at as isize)).unwrap() as u32;
129
130 let hi20 = pcrel.wrapping_add(0x800) & 0xFFFFF000;
144 let lo12 = pcrel.wrapping_sub(hi20) & 0xFFF;
145
146 unsafe {
147 let auipc_addr = at as *mut u32;
149 modify_inst32(auipc_addr, |auipc| (auipc & 0xFFF) | hi20);
150
151 let jalr_addr = at.offset(4) as *mut u32;
153 modify_inst32(jalr_addr, |jalr| (jalr & 0xFFFFF) | (lo12 << 20));
154 }
155 }
156 Reloc::PulleyPcRel => {
157 let base = get_address(name);
158 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
159 let pcrel = i32::try_from((what as isize) - (at as isize)).unwrap();
160 let at = at as *mut i32;
161 unsafe {
162 at.write_unaligned(at.read_unaligned().wrapping_add(pcrel));
163 }
164 }
165
166 Reloc::RiscvPCRelHi20 => {
169 let base = get_address(name);
170 let what = unsafe { base.offset(isize::try_from(addend).unwrap()) };
171 let pcrel = i32::try_from((what as isize) - (at as isize) + 0x800)
172 .unwrap()
173 .cast_unsigned();
174 let at = at as *mut u32;
175 unsafe {
176 modify_inst32(at, |i| i | (pcrel & 0xfffff000));
177 }
178 }
179
180 Reloc::RiscvPCRelLo12I => {
186 let prev_reloc = &self.relocs[i - 1];
187 assert_eq!(prev_reloc.kind, Reloc::RiscvPCRelHi20);
188 let lo_target = get_address(name);
189 let hi_address =
190 unsafe { self.ptr.offset(isize::try_from(prev_reloc.offset).unwrap()) };
191 assert_eq!(lo_target, hi_address);
192 let hi_target = get_address(&prev_reloc.name);
193 let pcrel = i32::try_from((hi_target as isize) - (hi_address as isize))
194 .unwrap()
195 .cast_unsigned();
196 let at = at as *mut u32;
197 unsafe {
198 modify_inst32(at, |i| i | ((pcrel & 0xfff) << 20));
199 }
200 }
201
202 other => unimplemented!("unimplemented reloc {other:?}"),
203 }
204 }
205 }
206}