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::{FunctionIndex, LibCall, LocalFunctionIndex, entity::PrimaryMap};
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
37 PCRel4,
39 PCRel8,
41
42 X86CallPCRel4,
44 X86CallPLTRel4,
46 X86GOTPCRel4,
48
49 Aarch64AdrPrelLo21,
51
52 Aarch64AdrPrelPgHi21,
54
55 Aarch64AddAbsLo12Nc,
57
58 Aarch64Ldst128AbsLo12Nc,
60
61 Aarch64Ldst64AbsLo12Nc,
63
64 Arm32Call,
66 Arm64Call,
68 Arm64Movw0,
70 Arm64Movw1,
72 Arm64Movw2,
74 Arm64Movw3,
76 RiscvPCRelHi20,
78 RiscvPCRelLo12I,
80 RiscvCall,
82 LArchAbsHi20,
84 LArchAbsLo12,
86 LArchAbs64Hi12,
88 LArchAbs64Lo20,
90 LArchCall36,
92 LArchPCAlaHi20,
94 LArchPCAlaLo12,
96 LArchPCAla64Hi12,
98 LArchPCAla64Lo20,
100 ElfX86_64TlsGd,
102 MachoArm64RelocUnsigned,
110 MachoArm64RelocSubtractor,
112 MachoArm64RelocBranch26,
114 MachoArm64RelocPage21,
116 MachoArm64RelocPageoff12,
118 MachoArm64RelocGotLoadPage21,
120 MachoArm64RelocGotLoadPageoff12,
122 MachoArm64RelocPointerToGot,
124 MachoArm64RelocTlvpLoadPage21,
126 MachoArm64RelocTlvpLoadPageoff12,
128 MachoArm64RelocAddend,
130
131 MachoX86_64RelocUnsigned,
134 MachoX86_64RelocSigned,
136 MachoX86_64RelocBranch,
138 MachoX86_64RelocGotLoad,
140 MachoX86_64RelocGot,
142 MachoX86_64RelocSubtractor,
144 MachoX86_64RelocSigned1,
146 MachoX86_64RelocSigned2,
148 MachoX86_64RelocSigned4,
150 MachoX86_64RelocTlv,
152
153 Abs6Bits,
156 Abs,
158 Abs2,
160
161 Add,
163 Add2,
165 Add4,
167 Add8,
169
170 Sub6Bits,
172 Sub,
174 Sub2,
176 Sub4,
178 Sub8,
180}
181
182impl RelocationKind {
183 pub fn needs_got(&self) -> bool {
184 matches!(
185 self,
186 Self::MachoArm64RelocGotLoadPage21
187 | Self::MachoArm64RelocGotLoadPageoff12
188 | Self::MachoArm64RelocPointerToGot
189 | Self::MachoX86_64RelocGotLoad
190 | Self::MachoX86_64RelocGot
191 )
192 }
193}
194
195#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
197#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
198#[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq)]
199#[rkyv(derive(Debug), compare(PartialEq))]
200pub struct Relocation {
201 pub kind: RelocationKind,
203 pub reloc_target: RelocationTarget,
205 pub offset: CodeOffset,
207 pub addend: Addend,
209}
210
211#[allow(missing_docs)]
213pub trait RelocationLike {
214 fn kind(&self) -> RelocationKind;
215 fn reloc_target(&self) -> RelocationTarget;
216 fn offset(&self) -> CodeOffset;
217 fn addend(&self) -> Addend;
218
219 fn for_address(&self, start: usize, target_func_address: u64) -> (usize, u64) {
234 match self.kind() {
235 RelocationKind::Abs6Bits
236 | RelocationKind::Abs
237 | RelocationKind::Abs2
238 | RelocationKind::Abs4
239 | RelocationKind::Abs8
240 | RelocationKind::Arm64Movw0
241 | RelocationKind::Arm64Movw1
242 | RelocationKind::Arm64Movw2
243 | RelocationKind::Arm64Movw3
244 | RelocationKind::RiscvPCRelLo12I
245 | RelocationKind::Aarch64Ldst128AbsLo12Nc
246 | RelocationKind::Aarch64Ldst64AbsLo12Nc
247 | RelocationKind::MachoArm64RelocUnsigned
248 | RelocationKind::MachoX86_64RelocUnsigned
249 | RelocationKind::MachoArm64RelocSubtractor
250 | RelocationKind::MachoX86_64RelocSubtractor
251 | RelocationKind::LArchAbsHi20
252 | RelocationKind::LArchAbsLo12
253 | RelocationKind::LArchAbs64Lo20
254 | RelocationKind::LArchAbs64Hi12
255 | RelocationKind::LArchPCAlaLo12
256 | RelocationKind::Add
257 | RelocationKind::Add2
258 | RelocationKind::Add4
259 | RelocationKind::Add8
260 | RelocationKind::Sub6Bits
261 | RelocationKind::Sub
262 | RelocationKind::Sub2
263 | RelocationKind::Sub4
264 | RelocationKind::Sub8 => {
265 let reloc_address = start + self.offset() as usize;
266 let reloc_addend = self.addend() as isize;
267 let reloc_abs = target_func_address
268 .checked_add(reloc_addend as u64)
269 .unwrap();
270 (reloc_address, reloc_abs)
271 }
272 RelocationKind::PCRel4 => {
273 let reloc_address = start + self.offset() as usize;
274 let reloc_addend = self.addend() as isize;
275 let reloc_delta_u32 = (target_func_address as u32)
276 .wrapping_sub(reloc_address as u32)
277 .checked_add(reloc_addend as u32)
278 .unwrap();
279 (reloc_address, reloc_delta_u32 as u64)
280 }
281 RelocationKind::PCRel8 => {
282 let reloc_address = start + self.offset() as usize;
283 let reloc_addend = self.addend() as isize;
284 let reloc_delta = target_func_address
285 .wrapping_sub(reloc_address as u64)
286 .checked_add(reloc_addend as u64)
287 .unwrap();
288 (reloc_address, reloc_delta)
289 }
290 RelocationKind::X86CallPCRel4 | RelocationKind::X86CallPLTRel4 => {
291 let reloc_address = start + self.offset() as usize;
292 let reloc_addend = self.addend() as isize;
293 let reloc_delta_u32 = (target_func_address as u32)
294 .wrapping_sub(reloc_address as u32)
295 .wrapping_add(reloc_addend as u32);
296 (reloc_address, reloc_delta_u32 as u64)
297 }
298 RelocationKind::Aarch64AdrPrelLo21 => {
299 let s = target_func_address;
300 let p = start + self.offset() as usize;
301 let a = self.addend() as u64;
302
303 (p, s.wrapping_add(a).wrapping_sub(p as u64))
304 }
305
306 RelocationKind::Aarch64AddAbsLo12Nc => {
307 let s = target_func_address;
308 let p = start + self.offset() as usize;
309 let a = self.addend() as u64;
310
311 (p, s.wrapping_add(a))
312 }
313 RelocationKind::Arm64Call
314 | RelocationKind::RiscvCall
315 | RelocationKind::RiscvPCRelHi20 => {
316 let reloc_address = start + self.offset() as usize;
317 let reloc_addend = self.addend() as isize;
318 let reloc_delta_u32 = target_func_address
319 .wrapping_sub(reloc_address as u64)
320 .wrapping_add(reloc_addend as u64);
321 (reloc_address, reloc_delta_u32)
322 }
323 RelocationKind::Aarch64AdrPrelPgHi21
324 | RelocationKind::MachoArm64RelocGotLoadPage21
325 | RelocationKind::MachoArm64RelocPage21 => {
326 let reloc_address = start + self.offset() as usize;
327 let reloc_addend = self.addend() as isize;
328 let target_page =
329 (target_func_address.wrapping_add(reloc_addend as u64) & !(0xFFF)) as usize;
330 let pc_page = reloc_address & !(0xFFF);
331 (reloc_address, target_page.wrapping_sub(pc_page) as u64)
332 }
333 RelocationKind::MachoArm64RelocGotLoadPageoff12
334 | RelocationKind::MachoArm64RelocPageoff12 => {
335 let reloc_address = start + self.offset() as usize;
336 let reloc_addend = self.addend() as isize;
337 let target_offset =
338 (target_func_address.wrapping_add(reloc_addend as u64) & (0xFFF)) as usize;
339 (reloc_address, target_offset as u64)
340 }
341 RelocationKind::LArchCall36 => {
342 let reloc_address = start + self.offset() as usize;
343 let reloc_addend = self.addend() as isize;
344 let reloc_delta = target_func_address
345 .wrapping_sub(reloc_address as u64)
346 .wrapping_add(reloc_addend as u64);
347 (
348 reloc_address,
349 reloc_delta.wrapping_add((reloc_delta & 0x20000) << 1),
350 )
351 }
352 RelocationKind::LArchPCAlaHi20 => {
353 let reloc_address = start + self.offset() as usize;
354 let reloc_addend = self.addend() as isize;
355 let target_page = (target_func_address
356 .wrapping_add(reloc_addend as u64)
357 .wrapping_add(0x800)
358 & !(0xFFF)) as usize;
359 let pc_page = reloc_address & !(0xFFF);
360 (reloc_address, target_page.wrapping_sub(pc_page) as u64)
361 }
362 RelocationKind::LArchPCAla64Hi12 | RelocationKind::LArchPCAla64Lo20 => {
363 let reloc_address = start + self.offset() as usize;
364 let reloc_addend = self.addend() as isize;
365 let reloc_offset = match self.kind() {
366 RelocationKind::LArchPCAla64Lo20 => 8,
367 RelocationKind::LArchPCAla64Hi12 => 12,
368 _ => 0,
369 };
370 let target_func_address = target_func_address.wrapping_add(reloc_addend as u64);
371 let target_page = (target_func_address & !(0xFFF)) as usize;
372 let pc_page = (reloc_address - reloc_offset) & !(0xFFF);
373 let mut reloc_delta = target_page.wrapping_sub(pc_page) as u64;
374 reloc_delta = reloc_delta
375 .wrapping_add((target_func_address & 0x800) << 1)
376 .wrapping_sub((target_func_address & 0x800) << 21);
377 reloc_delta = reloc_delta.wrapping_add((reloc_delta & 0x80000000) << 1);
378 (reloc_address, reloc_delta)
379 }
380 RelocationKind::MachoArm64RelocPointerToGot => {
381 let reloc_address = start + self.offset() as usize;
382 let reloc_delta =
383 (target_func_address as isize).wrapping_sub(reloc_address as isize);
384 (reloc_address, reloc_delta as u64)
385 }
386 _ => panic!("Relocation kind unsupported"),
387 }
388 }
389}
390
391impl RelocationLike for Relocation {
392 fn kind(&self) -> RelocationKind {
393 self.kind
394 }
395
396 fn reloc_target(&self) -> RelocationTarget {
397 self.reloc_target
398 }
399
400 fn offset(&self) -> CodeOffset {
401 self.offset
402 }
403
404 fn addend(&self) -> Addend {
405 self.addend
406 }
407}
408
409impl RelocationLike for ArchivedRelocation {
410 fn kind(&self) -> RelocationKind {
411 rkyv::deserialize::<_, String>(&self.kind).unwrap()
412 }
413
414 fn reloc_target(&self) -> RelocationTarget {
415 rkyv::deserialize::<_, String>(&self.reloc_target).unwrap()
416 }
417
418 fn offset(&self) -> CodeOffset {
419 self.offset.into()
420 }
421
422 fn addend(&self) -> Addend {
423 self.addend.into()
424 }
425}
426
427#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
429#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
430#[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Copy, Clone, PartialEq, Eq, Hash)]
431#[rkyv(derive(Debug, Hash, PartialEq, Eq), compare(PartialEq))]
432#[repr(u8)]
433pub enum RelocationTarget {
434 LocalFunc(LocalFunctionIndex),
436 DynamicTrampoline(FunctionIndex),
438 LibCall(LibCall),
440 CustomSection(SectionIndex),
442}
443
444pub type Relocations = PrimaryMap<LocalFunctionIndex, Vec<Relocation>>;