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 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 LibCall(LibCall),
454 CustomSection(SectionIndex),
456}
457
458pub type Relocations = PrimaryMap<LocalFunctionIndex, Vec<Relocation>>;