1#![allow(missing_docs)]
6
7use super::section::SectionIndex;
19use crate::{Addend, CodeOffset};
20use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
21#[cfg(feature = "enable-serde")]
22use serde::{Deserialize, Serialize};
23use wasmer_types::{entity::PrimaryMap, lib::std::fmt, LibCall, LocalFunctionIndex};
24
25#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
27#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
28#[derive(RkyvSerialize, RkyvDeserialize, Archive, Copy, Clone, Debug, PartialEq, Eq)]
29#[rkyv(derive(Debug), compare(PartialEq))]
30#[repr(u8)]
31pub enum RelocationKind {
32 Abs4,
34 Abs8,
36 X86PCRel4,
38 X86PCRel8,
40 X86CallPCRel4,
42 X86CallPLTRel4,
44 X86GOTPCRel4,
46
47 Aarch64AdrPrelLo21,
49
50 Aarch64AdrPrelPgHi21,
52
53 Aarch64AddAbsLo12Nc,
55
56 Aarch64Ldst128AbsLo12Nc,
58
59 Aarch64Ldst64AbsLo12Nc,
61
62 Arm32Call,
64 Arm64Call,
66 Arm64Movw0,
68 Arm64Movw1,
70 Arm64Movw2,
72 Arm64Movw3,
74 RiscvPCRelHi20,
76 RiscvPCRelLo12I,
78 RiscvCall,
80 LArchAbsHi20,
82 LArchAbsLo12,
84 LArchAbs64Hi12,
86 LArchAbs64Lo20,
88 LArchCall36,
90 LArchPCAlaHi20,
92 LArchPCAlaLo12,
94 LArchPCAla64Hi12,
96 LArchPCAla64Lo20,
98 ElfX86_64TlsGd,
100 }
103
104impl fmt::Display for RelocationKind {
105 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 match *self {
109 Self::Abs4 => write!(f, "Abs4"),
110 Self::Abs8 => write!(f, "Abs8"),
111 Self::X86PCRel4 => write!(f, "PCRel4"),
112 Self::X86PCRel8 => write!(f, "PCRel8"),
113 Self::X86CallPCRel4 => write!(f, "CallPCRel4"),
114 Self::X86CallPLTRel4 => write!(f, "CallPLTRel4"),
115 Self::X86GOTPCRel4 => write!(f, "GOTPCRel4"),
116 Self::Arm32Call | Self::Arm64Call | Self::RiscvCall => write!(f, "Call"),
117 Self::Arm64Movw0 => write!(f, "Arm64MovwG0"),
118 Self::Arm64Movw1 => write!(f, "Arm64MovwG1"),
119 Self::Arm64Movw2 => write!(f, "Arm64MovwG2"),
120 Self::Arm64Movw3 => write!(f, "Arm64MovwG3"),
121 Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"),
122 Self::RiscvPCRelHi20 => write!(f, "RiscvPCRelHi20"),
123 Self::RiscvPCRelLo12I => write!(f, "RiscvPCRelLo12I"),
124 Self::LArchAbsHi20 => write!(f, "LArchAbsHi20"),
125 Self::LArchAbsLo12 => write!(f, "LArchAbsLo12"),
126 Self::LArchAbs64Hi12 => write!(f, "LArchAbs64Hi12"),
127 Self::LArchAbs64Lo20 => write!(f, "LArchAbs64Lo20"),
128 Self::LArchCall36 => write!(f, "LArchCall36"),
129 Self::LArchPCAlaHi20 => write!(f, "LArchPCAlaHi20"),
130 Self::LArchPCAlaLo12 => write!(f, "LArchPCAlaLo12"),
131 Self::LArchPCAla64Hi12 => write!(f, "LArchPCAla64Hi12"),
132 Self::LArchPCAla64Lo20 => write!(f, "LArchPCAla64Lo20"),
133 Self::Aarch64AdrPrelLo21 => write!(f, "Aarch64AdrPrelLo21"),
134 Self::Aarch64AdrPrelPgHi21 => write!(f, "Aarch64AdrPrelPgHi21"),
135 Self::Aarch64AddAbsLo12Nc => write!(f, "Aarch64AddAbsLo12Nc"),
136 Self::Aarch64Ldst128AbsLo12Nc => write!(f, "Aarch64Ldst128AbsLo12Nc"),
137 Self::Aarch64Ldst64AbsLo12Nc => write!(f, "Aarch64Ldst64AbsLo12Nc"),
138 }
140 }
141}
142
143#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
145#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
146#[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq)]
147#[rkyv(derive(Debug), compare(PartialEq))]
148pub struct Relocation {
149 pub kind: RelocationKind,
151 pub reloc_target: RelocationTarget,
153 pub offset: CodeOffset,
155 pub addend: Addend,
157}
158
159#[allow(missing_docs)]
161pub trait RelocationLike {
162 fn kind(&self) -> RelocationKind;
163 fn reloc_target(&self) -> RelocationTarget;
164 fn offset(&self) -> CodeOffset;
165 fn addend(&self) -> Addend;
166
167 fn for_address(&self, start: usize, target_func_address: u64) -> (usize, u64) {
182 match self.kind() {
183 RelocationKind::Abs8
184 | RelocationKind::Arm64Movw0
185 | RelocationKind::Arm64Movw1
186 | RelocationKind::Arm64Movw2
187 | RelocationKind::Arm64Movw3
188 | RelocationKind::RiscvPCRelLo12I
189 | RelocationKind::Aarch64Ldst128AbsLo12Nc
190 | RelocationKind::Aarch64Ldst64AbsLo12Nc
191 | RelocationKind::LArchAbsHi20
192 | RelocationKind::LArchAbsLo12
193 | RelocationKind::LArchAbs64Lo20
194 | RelocationKind::LArchAbs64Hi12
195 | RelocationKind::LArchPCAlaLo12 => {
196 let reloc_address = start + self.offset() as usize;
197 let reloc_addend = self.addend() as isize;
198 let reloc_abs = target_func_address
199 .checked_add(reloc_addend as u64)
200 .unwrap();
201 (reloc_address, reloc_abs)
202 }
203 RelocationKind::X86PCRel4 => {
204 let reloc_address = start + self.offset() as usize;
205 let reloc_addend = self.addend() as isize;
206 let reloc_delta_u32 = (target_func_address as u32)
207 .wrapping_sub(reloc_address as u32)
208 .checked_add(reloc_addend as u32)
209 .unwrap();
210 (reloc_address, reloc_delta_u32 as u64)
211 }
212 RelocationKind::X86PCRel8 => {
213 let reloc_address = start + self.offset() as usize;
214 let reloc_addend = self.addend() as isize;
215 let reloc_delta = target_func_address
216 .wrapping_sub(reloc_address as u64)
217 .checked_add(reloc_addend as u64)
218 .unwrap();
219 (reloc_address, reloc_delta)
220 }
221 RelocationKind::X86CallPCRel4 | RelocationKind::X86CallPLTRel4 => {
222 let reloc_address = start + self.offset() as usize;
223 let reloc_addend = self.addend() as isize;
224 let reloc_delta_u32 = (target_func_address as u32)
225 .wrapping_sub(reloc_address as u32)
226 .wrapping_add(reloc_addend as u32);
227 (reloc_address, reloc_delta_u32 as u64)
228 }
229 RelocationKind::Aarch64AdrPrelLo21 => {
230 let s = target_func_address;
231 let p = start + self.offset() as usize;
232 let a = self.addend() as u64;
233
234 (p, s.wrapping_add(a).wrapping_sub(p as u64))
235 }
236
237 RelocationKind::Aarch64AddAbsLo12Nc => {
238 let s = target_func_address;
239 let p = start + self.offset() as usize;
240 let a = self.addend() as u64;
241
242 (p, s.wrapping_add(a))
243 }
244 RelocationKind::Arm64Call
245 | RelocationKind::RiscvCall
246 | RelocationKind::RiscvPCRelHi20 => {
247 let reloc_address = start + self.offset() as usize;
248 let reloc_addend = self.addend() as isize;
249 let reloc_delta_u32 = target_func_address
250 .wrapping_sub(reloc_address as u64)
251 .wrapping_add(reloc_addend as u64);
252 (reloc_address, reloc_delta_u32)
253 }
254 RelocationKind::Aarch64AdrPrelPgHi21 => {
255 let reloc_address = start + self.offset() as usize;
256 let reloc_addend = self.addend() as isize;
257 let target_page =
258 (target_func_address.wrapping_add(reloc_addend as u64) & !(0xFFF)) as usize;
259 let pc_page = reloc_address & !(0xFFF);
260 (reloc_address, target_page.wrapping_sub(pc_page) as u64)
261 }
262 RelocationKind::LArchCall36 => {
263 let reloc_address = start + self.offset() as usize;
264 let reloc_addend = self.addend() as isize;
265 let reloc_delta = target_func_address
266 .wrapping_sub(reloc_address as u64)
267 .wrapping_add(reloc_addend as u64);
268 (
269 reloc_address,
270 reloc_delta.wrapping_add((reloc_delta & 0x20000) << 1),
271 )
272 }
273 RelocationKind::LArchPCAlaHi20 => {
274 let reloc_address = start + self.offset() as usize;
275 let reloc_addend = self.addend() as isize;
276 let target_page = (target_func_address
277 .wrapping_add(reloc_addend as u64)
278 .wrapping_add(0x800)
279 & !(0xFFF)) as usize;
280 let pc_page = reloc_address & !(0xFFF);
281 (reloc_address, target_page.wrapping_sub(pc_page) as u64)
282 }
283 RelocationKind::LArchPCAla64Hi12 | RelocationKind::LArchPCAla64Lo20 => {
284 let reloc_address = start + self.offset() as usize;
285 let reloc_addend = self.addend() as isize;
286 let reloc_offset = match self.kind() {
287 RelocationKind::LArchPCAla64Lo20 => 8,
288 RelocationKind::LArchPCAla64Hi12 => 12,
289 _ => 0,
290 };
291 let target_func_address = target_func_address.wrapping_add(reloc_addend as u64);
292 let target_page = (target_func_address & !(0xFFF)) as usize;
293 let pc_page = (reloc_address - reloc_offset) & !(0xFFF);
294 let mut reloc_delta = target_page.wrapping_sub(pc_page) as u64;
295 reloc_delta = reloc_delta
296 .wrapping_add((target_func_address & 0x800) << 1)
297 .wrapping_sub((target_func_address & 0x800) << 21);
298 reloc_delta = reloc_delta.wrapping_add((reloc_delta & 0x80000000) << 1);
299 (reloc_address, reloc_delta)
300 }
301 _ => panic!("Relocation kind unsupported"),
302 }
303 }
304}
305
306impl RelocationLike for Relocation {
307 fn kind(&self) -> RelocationKind {
308 self.kind
309 }
310
311 fn reloc_target(&self) -> RelocationTarget {
312 self.reloc_target
313 }
314
315 fn offset(&self) -> CodeOffset {
316 self.offset
317 }
318
319 fn addend(&self) -> Addend {
320 self.addend
321 }
322}
323
324impl RelocationLike for ArchivedRelocation {
325 fn kind(&self) -> RelocationKind {
326 rkyv::deserialize::<_, String>(&self.kind).unwrap()
327 }
328
329 fn reloc_target(&self) -> RelocationTarget {
330 rkyv::deserialize::<_, String>(&self.reloc_target).unwrap()
331 }
332
333 fn offset(&self) -> CodeOffset {
334 self.offset.into()
335 }
336
337 fn addend(&self) -> Addend {
338 self.addend.into()
339 }
340}
341
342#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
344#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
345#[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Copy, Clone, PartialEq, Eq)]
346#[rkyv(derive(Debug), compare(PartialEq))]
347#[repr(u8)]
348pub enum RelocationTarget {
349 LocalFunc(LocalFunctionIndex),
351 LibCall(LibCall),
353 CustomSection(SectionIndex),
355}
356
357pub type Relocations = PrimaryMap<LocalFunctionIndex, Vec<Relocation>>;