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, lib::std::fmt};
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    MachoArm64RelocUnsigned,
108    MachoArm64RelocSubtractor,
110    MachoArm64RelocBranch26,
112    MachoArm64RelocPage21,
114    MachoArm64RelocPageoff12,
116    MachoArm64RelocGotLoadPage21,
118    MachoArm64RelocGotLoadPageoff12,
120    MachoArm64RelocPointerToGot,
122    MachoArm64RelocTlvpLoadPage21,
124    MachoArm64RelocTlvpLoadPageoff12,
126    MachoArm64RelocAddend,
128
129    MachoX86_64RelocUnsigned,
132    MachoX86_64RelocSigned,
134    MachoX86_64RelocBranch,
136    MachoX86_64RelocGotLoad,
138    MachoX86_64RelocGot,
140    MachoX86_64RelocSubtractor,
142    MachoX86_64RelocSigned1,
144    MachoX86_64RelocSigned2,
146    MachoX86_64RelocSigned4,
148    MachoX86_64RelocTlv,
150}
151
152impl RelocationKind {
153    pub fn needs_got(&self) -> bool {
154        matches!(
155            self,
156            Self::MachoArm64RelocGotLoadPage21
157                | Self::MachoArm64RelocGotLoadPageoff12
158                | Self::MachoArm64RelocPointerToGot
159                | Self::MachoX86_64RelocGotLoad
160                | Self::MachoX86_64RelocGot
161        )
162    }
163}
164
165impl fmt::Display for RelocationKind {
166    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169        match *self {
170            Self::Abs4 => write!(f, "Abs4"),
171            Self::Abs8 => write!(f, "Abs8"),
172            Self::X86PCRel4 => write!(f, "PCRel4"),
173            Self::X86PCRel8 => write!(f, "PCRel8"),
174            Self::X86CallPCRel4 => write!(f, "CallPCRel4"),
175            Self::X86CallPLTRel4 => write!(f, "CallPLTRel4"),
176            Self::X86GOTPCRel4 => write!(f, "GOTPCRel4"),
177            Self::Arm32Call | Self::Arm64Call | Self::RiscvCall => write!(f, "Call"),
178            Self::Arm64Movw0 => write!(f, "Arm64MovwG0"),
179            Self::Arm64Movw1 => write!(f, "Arm64MovwG1"),
180            Self::Arm64Movw2 => write!(f, "Arm64MovwG2"),
181            Self::Arm64Movw3 => write!(f, "Arm64MovwG3"),
182            Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"),
183            Self::RiscvPCRelHi20 => write!(f, "RiscvPCRelHi20"),
184            Self::RiscvPCRelLo12I => write!(f, "RiscvPCRelLo12I"),
185            Self::LArchAbsHi20 => write!(f, "LArchAbsHi20"),
186            Self::LArchAbsLo12 => write!(f, "LArchAbsLo12"),
187            Self::LArchAbs64Hi12 => write!(f, "LArchAbs64Hi12"),
188            Self::LArchAbs64Lo20 => write!(f, "LArchAbs64Lo20"),
189            Self::LArchCall36 => write!(f, "LArchCall36"),
190            Self::LArchPCAlaHi20 => write!(f, "LArchPCAlaHi20"),
191            Self::LArchPCAlaLo12 => write!(f, "LArchPCAlaLo12"),
192            Self::LArchPCAla64Hi12 => write!(f, "LArchPCAla64Hi12"),
193            Self::LArchPCAla64Lo20 => write!(f, "LArchPCAla64Lo20"),
194            Self::Aarch64AdrPrelLo21 => write!(f, "Aarch64AdrPrelLo21"),
195            Self::Aarch64AdrPrelPgHi21 => write!(f, "Aarch64AdrPrelPgHi21"),
196            Self::Aarch64AddAbsLo12Nc => write!(f, "Aarch64AddAbsLo12Nc"),
197            Self::Aarch64Ldst128AbsLo12Nc => write!(f, "Aarch64Ldst128AbsLo12Nc"),
198            Self::Aarch64Ldst64AbsLo12Nc => write!(f, "Aarch64Ldst64AbsLo12Nc"),
199            Self::MachoArm64RelocUnsigned => write!(f, "MachoArm64RelocUnsigned"),
200            Self::MachoArm64RelocSubtractor => write!(f, "MachoArm64RelocSubtractor"),
201            Self::MachoArm64RelocBranch26 => write!(f, "MachoArm64RelocBranch26"),
202            Self::MachoArm64RelocPage21 => write!(f, "MachoArm64RelocPage21"),
203            Self::MachoArm64RelocPageoff12 => write!(f, "MachoArm64RelocPageoff12"),
204            Self::MachoArm64RelocGotLoadPage21 => write!(f, "MachoArm64RelocGotLoadPage21"),
205            Self::MachoArm64RelocGotLoadPageoff12 => write!(f, "MachoArm64RelocGotLoadPageoff12"),
206            Self::MachoArm64RelocPointerToGot => write!(f, "MachoArm64RelocPointerToGot"),
207            Self::MachoArm64RelocTlvpLoadPage21 => write!(f, "MachoArm64RelocTlvpLoadPage21"),
208            Self::MachoArm64RelocTlvpLoadPageoff12 => write!(f, "MachoArm64RelocTlvpLoadPageoff12"),
209            Self::MachoArm64RelocAddend => write!(f, "MachoArm64RelocAddend"),
210            Self::MachoX86_64RelocUnsigned => write!(f, "MachoX86_64RelocUnsigned"),
211            Self::MachoX86_64RelocSigned => write!(f, "MachoX86_64RelocSigned"),
212            Self::MachoX86_64RelocBranch => write!(f, "MachoX86_64RelocBranch"),
213            Self::MachoX86_64RelocGotLoad => write!(f, "MachoX86_64RelocGotLoad"),
214            Self::MachoX86_64RelocGot => write!(f, "MachoX86_64RelocGot"),
215            Self::MachoX86_64RelocSubtractor => write!(f, "MachoX86_64RelocSubtractor"),
216            Self::MachoX86_64RelocSigned1 => write!(f, "MachoX86_64RelocSigned1"),
217            Self::MachoX86_64RelocSigned2 => write!(f, "MachoX86_64RelocSigned2"),
218            Self::MachoX86_64RelocSigned4 => write!(f, "MachoX86_64RelocSigned4"),
219            Self::MachoX86_64RelocTlv => write!(f, "MachoX86_64RelocTlv"),
220        }
221    }
222}
223
224#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
226#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
227#[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq)]
228#[rkyv(derive(Debug), compare(PartialEq))]
229pub struct Relocation {
230    pub kind: RelocationKind,
232    pub reloc_target: RelocationTarget,
234    pub offset: CodeOffset,
236    pub addend: Addend,
238}
239
240#[allow(missing_docs)]
242pub trait RelocationLike {
243    fn kind(&self) -> RelocationKind;
244    fn reloc_target(&self) -> RelocationTarget;
245    fn offset(&self) -> CodeOffset;
246    fn addend(&self) -> Addend;
247
248    fn for_address(&self, start: usize, target_func_address: u64) -> (usize, u64) {
263        match self.kind() {
264            RelocationKind::Abs8
265            | RelocationKind::Arm64Movw0
266            | RelocationKind::Arm64Movw1
267            | RelocationKind::Arm64Movw2
268            | RelocationKind::Arm64Movw3
269            | RelocationKind::RiscvPCRelLo12I
270            | RelocationKind::Aarch64Ldst128AbsLo12Nc
271            | RelocationKind::Aarch64Ldst64AbsLo12Nc
272            | RelocationKind::MachoArm64RelocUnsigned
273            | RelocationKind::MachoX86_64RelocUnsigned
274            | RelocationKind::MachoArm64RelocSubtractor
275            | RelocationKind::MachoX86_64RelocSubtractor
276            | RelocationKind::LArchAbsHi20
277            | RelocationKind::LArchAbsLo12
278            | RelocationKind::LArchAbs64Lo20
279            | RelocationKind::LArchAbs64Hi12
280            | RelocationKind::LArchPCAlaLo12 => {
281                let reloc_address = start + self.offset() as usize;
282                let reloc_addend = self.addend() as isize;
283                let reloc_abs = target_func_address
284                    .checked_add(reloc_addend as u64)
285                    .unwrap();
286                (reloc_address, reloc_abs)
287            }
288            RelocationKind::X86PCRel4 => {
289                let reloc_address = start + self.offset() as usize;
290                let reloc_addend = self.addend() as isize;
291                let reloc_delta_u32 = (target_func_address as u32)
292                    .wrapping_sub(reloc_address as u32)
293                    .checked_add(reloc_addend as u32)
294                    .unwrap();
295                (reloc_address, reloc_delta_u32 as u64)
296            }
297            RelocationKind::X86PCRel8 => {
298                let reloc_address = start + self.offset() as usize;
299                let reloc_addend = self.addend() as isize;
300                let reloc_delta = target_func_address
301                    .wrapping_sub(reloc_address as u64)
302                    .checked_add(reloc_addend as u64)
303                    .unwrap();
304                (reloc_address, reloc_delta)
305            }
306            RelocationKind::X86CallPCRel4 | RelocationKind::X86CallPLTRel4 => {
307                let reloc_address = start + self.offset() as usize;
308                let reloc_addend = self.addend() as isize;
309                let reloc_delta_u32 = (target_func_address as u32)
310                    .wrapping_sub(reloc_address as u32)
311                    .wrapping_add(reloc_addend as u32);
312                (reloc_address, reloc_delta_u32 as u64)
313            }
314            RelocationKind::Aarch64AdrPrelLo21 => {
315                let s = target_func_address;
316                let p = start + self.offset() as usize;
317                let a = self.addend() as u64;
318
319                (p, s.wrapping_add(a).wrapping_sub(p as u64))
320            }
321
322            RelocationKind::Aarch64AddAbsLo12Nc => {
323                let s = target_func_address;
324                let p = start + self.offset() as usize;
325                let a = self.addend() as u64;
326
327                (p, s.wrapping_add(a))
328            }
329            RelocationKind::Arm64Call
330            | RelocationKind::RiscvCall
331            | RelocationKind::RiscvPCRelHi20 => {
332                let reloc_address = start + self.offset() as usize;
333                let reloc_addend = self.addend() as isize;
334                let reloc_delta_u32 = target_func_address
335                    .wrapping_sub(reloc_address as u64)
336                    .wrapping_add(reloc_addend as u64);
337                (reloc_address, reloc_delta_u32)
338            }
339            RelocationKind::Aarch64AdrPrelPgHi21
340            | RelocationKind::MachoArm64RelocGotLoadPage21
341            | RelocationKind::MachoArm64RelocPage21 => {
342                let reloc_address = start + self.offset() as usize;
343                let reloc_addend = self.addend() as isize;
344                let target_page =
345                    (target_func_address.wrapping_add(reloc_addend as u64) & !(0xFFF)) as usize;
346                let pc_page = reloc_address & !(0xFFF);
347                (reloc_address, target_page.wrapping_sub(pc_page) as u64)
348            }
349            RelocationKind::MachoArm64RelocGotLoadPageoff12
350            | RelocationKind::MachoArm64RelocPageoff12 => {
351                let reloc_address = start + self.offset() as usize;
352                let reloc_addend = self.addend() as isize;
353                let target_offset =
354                    (target_func_address.wrapping_add(reloc_addend as u64) & (0xFFF)) as usize;
355                (reloc_address, target_offset as u64)
356            }
357            RelocationKind::LArchCall36 => {
358                let reloc_address = start + self.offset() as usize;
359                let reloc_addend = self.addend() as isize;
360                let reloc_delta = target_func_address
361                    .wrapping_sub(reloc_address as u64)
362                    .wrapping_add(reloc_addend as u64);
363                (
364                    reloc_address,
365                    reloc_delta.wrapping_add((reloc_delta & 0x20000) << 1),
366                )
367            }
368            RelocationKind::LArchPCAlaHi20 => {
369                let reloc_address = start + self.offset() as usize;
370                let reloc_addend = self.addend() as isize;
371                let target_page = (target_func_address
372                    .wrapping_add(reloc_addend as u64)
373                    .wrapping_add(0x800)
374                    & !(0xFFF)) as usize;
375                let pc_page = reloc_address & !(0xFFF);
376                (reloc_address, target_page.wrapping_sub(pc_page) as u64)
377            }
378            RelocationKind::LArchPCAla64Hi12 | RelocationKind::LArchPCAla64Lo20 => {
379                let reloc_address = start + self.offset() as usize;
380                let reloc_addend = self.addend() as isize;
381                let reloc_offset = match self.kind() {
382                    RelocationKind::LArchPCAla64Lo20 => 8,
383                    RelocationKind::LArchPCAla64Hi12 => 12,
384                    _ => 0,
385                };
386                let target_func_address = target_func_address.wrapping_add(reloc_addend as u64);
387                let target_page = (target_func_address & !(0xFFF)) as usize;
388                let pc_page = (reloc_address - reloc_offset) & !(0xFFF);
389                let mut reloc_delta = target_page.wrapping_sub(pc_page) as u64;
390                reloc_delta = reloc_delta
391                    .wrapping_add((target_func_address & 0x800) << 1)
392                    .wrapping_sub((target_func_address & 0x800) << 21);
393                reloc_delta = reloc_delta.wrapping_add((reloc_delta & 0x80000000) << 1);
394                (reloc_address, reloc_delta)
395            }
396            RelocationKind::MachoArm64RelocPointerToGot => {
397                let reloc_address = start + self.offset() as usize;
398                let reloc_delta =
399                    (target_func_address as isize).wrapping_sub(reloc_address as isize);
400                (reloc_address, reloc_delta as u64)
401            }
402            _ => panic!("Relocation kind unsupported"),
403        }
404    }
405}
406
407impl RelocationLike for Relocation {
408    fn kind(&self) -> RelocationKind {
409        self.kind
410    }
411
412    fn reloc_target(&self) -> RelocationTarget {
413        self.reloc_target
414    }
415
416    fn offset(&self) -> CodeOffset {
417        self.offset
418    }
419
420    fn addend(&self) -> Addend {
421        self.addend
422    }
423}
424
425impl RelocationLike for ArchivedRelocation {
426    fn kind(&self) -> RelocationKind {
427        rkyv::deserialize::<_, String>(&self.kind).unwrap()
428    }
429
430    fn reloc_target(&self) -> RelocationTarget {
431        rkyv::deserialize::<_, String>(&self.reloc_target).unwrap()
432    }
433
434    fn offset(&self) -> CodeOffset {
435        self.offset.into()
436    }
437
438    fn addend(&self) -> Addend {
439        self.addend.into()
440    }
441}
442
443#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
445#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
446#[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Copy, Clone, PartialEq, Eq, Hash)]
447#[rkyv(derive(Debug, Hash, PartialEq, Eq), compare(PartialEq))]
448#[repr(u8)]
449pub enum RelocationTarget {
450    LocalFunc(LocalFunctionIndex),
452    DynamicTrampoline(FunctionIndex),
454    LibCall(LibCall),
456    CustomSection(SectionIndex),
458}
459
460pub type Relocations = PrimaryMap<LocalFunctionIndex, Vec<Relocation>>;