1use crate::bit_misc::BitRange;
2use anyhow::Result;
3use object::LittleEndian;
4use object::read::elf::ProgramHeader as _;
5use object::read::elf::SectionHeader;
6use std::borrow::Cow;
7use std::fmt;
8
9macro_rules! const_name_by_value {
10 ($needle: expr, $( $const:ident ),* $(,)?) => {
11 match $needle {
12 $(object::elf::$const => Some(stringify!($const)),)*
13 _ => None
14 }
15 };
16}
17
18macro_rules! const_or_literal {
19 ($prefix:ident $const:ident = $value:expr) => {
20 $value
21 };
22 ($prefix:ident $const:ident) => {
23 ::paste::paste! {
24 ::object::elf::[<$prefix _ $const>]
25 }
26 };
27}
28
29macro_rules! elf_constant_newtype {
33 (
34 $name:ident,
35 $inner_type:ident,
36 $constants_module:ident,
37 $prefix:ident,
38 $(
39 $const:ident $(= $value:expr)?
40 ),* $(,)?
41 ) => {
42 #[derive(Clone, Copy, derive_more::Debug, PartialEq, Eq, PartialOrd, Ord)]
43 #[debug("{}", self.as_str())]
44 pub struct $name($inner_type);
45
46 impl $name {
47 #[must_use]
48 pub fn raw(&self) -> $inner_type {
49 self.0
50 }
51
52 #[allow(unreachable_patterns)] #[must_use]
54 pub fn as_str(&self) -> Cow<'static, str> {
55 match self.0 {
56 $(
57 const_or_literal!($prefix $const $(= $value )?)
58 => ::std::borrow::Cow::Borrowed(stringify!($const)),
59 )*
60 r => Cow::Owned(format!("Unknown({r})")),
61 }
62 }
63
64 ::paste::paste! {
65 #[must_use]
66 pub const fn [<from_ $inner_type>](value: $inner_type) -> Self {
67 Self(value)
68 }
69 }
70 }
71
72 impl From < $inner_type > for $name {
73 fn from(value: $inner_type) -> Self {
74 Self(value)
75 }
76 }
77
78 impl std::fmt::Display for $name {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 write!(f, "{}", self.as_str())
81 }
82 }
83
84 pub mod $constants_module {
85 #![allow(non_upper_case_globals)]
86 use super::$name;
87
88 $(pub const $const: $name = $name(const_or_literal!($prefix $const $(= $value)?));)*
89 }
90 };
91}
92
93elf_constant_newtype!(
94 SegmentType,
95 u32,
96 pt,
97 PT,
98 NULL,
99 LOAD,
100 DYNAMIC,
101 INTERP,
102 NOTE,
103 SHLIB,
104 PHDR,
105 TLS,
106 GNU_EH_FRAME,
107 GNU_STACK,
108 GNU_RELRO,
109 GNU_PROPERTY,
110 GNU_SFRAME,
111 RISCV_ATTRIBUTES = 0x70000003,
112);
113
114impl SegmentType {
115 #[must_use]
116 pub fn from_header(header: &object::elf::ProgramHeader64<LittleEndian>) -> Self {
117 Self(header.p_type(LittleEndian))
118 }
119}
120
121elf_constant_newtype!(
122 SectionType,
123 u32,
124 sht,
125 SHT,
126 NULL,
127 PROGBITS,
128 SYMTAB,
129 STRTAB,
130 RELA,
131 HASH,
132 DYNAMIC,
133 NOTE,
134 NOBITS,
135 REL,
136 SHLIB,
137 DYNSYM,
138 INIT_ARRAY,
139 FINI_ARRAY,
140 PREINIT_ARRAY,
141 GROUP,
142 SYMTAB_SHNDX,
143 LOOS,
144 GNU_SFRAME,
145 GNU_ATTRIBUTES,
146 GNU_HASH,
147 GNU_LIBLIST,
148 CHECKSUM,
149 LOSUNW,
150 SUNW_COMDAT,
151 SUNW_syminfo,
152 GNU_VERDEF,
153 GNU_VERNEED,
154 GNU_VERSYM,
155 HISUNW,
156 HIOS,
157 LOPROC,
158 HIPROC,
159 LOUSER,
160 HIUSER,
161 RISCV_ATTRIBUTES,
162);
163
164impl SectionType {
165 #[must_use]
166 pub fn from_header(header: &object::elf::SectionHeader64<LittleEndian>) -> Self {
167 Self(header.sh_type(LittleEndian))
168 }
169}
170
171elf_constant_newtype!(SymbolType, u8, stt, STT, NOTYPE, TLS);
172
173#[must_use]
174pub fn x86_64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
175 if let Some(name) = const_name_by_value![
176 r_type,
177 R_X86_64_NONE,
178 R_X86_64_64,
179 R_X86_64_PC32,
180 R_X86_64_GOT32,
181 R_X86_64_PLT32,
182 R_X86_64_COPY,
183 R_X86_64_GLOB_DAT,
184 R_X86_64_JUMP_SLOT,
185 R_X86_64_RELATIVE,
186 R_X86_64_GOTPCREL,
187 R_X86_64_32,
188 R_X86_64_32S,
189 R_X86_64_16,
190 R_X86_64_PC16,
191 R_X86_64_8,
192 R_X86_64_PC8,
193 R_X86_64_DTPMOD64,
194 R_X86_64_DTPOFF64,
195 R_X86_64_TPOFF64,
196 R_X86_64_TLSGD,
197 R_X86_64_TLSLD,
198 R_X86_64_DTPOFF32,
199 R_X86_64_GOTTPOFF,
200 R_X86_64_TPOFF32,
201 R_X86_64_PC64,
202 R_X86_64_GOTOFF64,
203 R_X86_64_GOTPC32,
204 R_X86_64_GOT64,
205 R_X86_64_GOTPCREL64,
206 R_X86_64_GOTPC64,
207 R_X86_64_GOTPLT64,
208 R_X86_64_PLTOFF64,
209 R_X86_64_SIZE32,
210 R_X86_64_SIZE64,
211 R_X86_64_GOTPC32_TLSDESC,
212 R_X86_64_TLSDESC_CALL,
213 R_X86_64_TLSDESC,
214 R_X86_64_IRELATIVE,
215 R_X86_64_RELATIVE64,
216 R_X86_64_GOTPCRELX,
217 R_X86_64_REX_GOTPCRELX,
218 ] {
219 Cow::Borrowed(name)
220 } else {
221 Cow::Owned(format!("Unknown x86_64 relocation type 0x{r_type:x}"))
222 }
223}
224
225#[must_use]
226pub fn aarch64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
227 if let Some(name) = const_name_by_value![
228 r_type,
229 R_AARCH64_NONE,
230 R_AARCH64_P32_ABS32,
231 R_AARCH64_P32_COPY,
232 R_AARCH64_P32_GLOB_DAT,
233 R_AARCH64_P32_JUMP_SLOT,
234 R_AARCH64_P32_RELATIVE,
235 R_AARCH64_P32_TLS_DTPMOD,
236 R_AARCH64_P32_TLS_DTPREL,
237 R_AARCH64_P32_TLS_TPREL,
238 R_AARCH64_P32_TLSDESC,
239 R_AARCH64_P32_IRELATIVE,
240 R_AARCH64_ABS64,
241 R_AARCH64_ABS32,
242 R_AARCH64_ABS16,
243 R_AARCH64_PREL64,
244 R_AARCH64_PREL32,
245 R_AARCH64_PREL16,
246 R_AARCH64_MOVW_UABS_G0,
247 R_AARCH64_MOVW_UABS_G0_NC,
248 R_AARCH64_MOVW_UABS_G1,
249 R_AARCH64_MOVW_UABS_G1_NC,
250 R_AARCH64_MOVW_UABS_G2,
251 R_AARCH64_MOVW_UABS_G2_NC,
252 R_AARCH64_MOVW_UABS_G3,
253 R_AARCH64_MOVW_SABS_G0,
254 R_AARCH64_MOVW_SABS_G1,
255 R_AARCH64_MOVW_SABS_G2,
256 R_AARCH64_LD_PREL_LO19,
257 R_AARCH64_ADR_PREL_LO21,
258 R_AARCH64_ADR_PREL_PG_HI21,
259 R_AARCH64_ADR_PREL_PG_HI21_NC,
260 R_AARCH64_ADD_ABS_LO12_NC,
261 R_AARCH64_LDST8_ABS_LO12_NC,
262 R_AARCH64_TSTBR14,
263 R_AARCH64_CONDBR19,
264 R_AARCH64_JUMP26,
265 R_AARCH64_CALL26,
266 R_AARCH64_LDST16_ABS_LO12_NC,
267 R_AARCH64_LDST32_ABS_LO12_NC,
268 R_AARCH64_LDST64_ABS_LO12_NC,
269 R_AARCH64_MOVW_PREL_G0,
270 R_AARCH64_MOVW_PREL_G0_NC,
271 R_AARCH64_MOVW_PREL_G1,
272 R_AARCH64_MOVW_PREL_G1_NC,
273 R_AARCH64_MOVW_PREL_G2,
274 R_AARCH64_MOVW_PREL_G2_NC,
275 R_AARCH64_MOVW_PREL_G3,
276 R_AARCH64_LDST128_ABS_LO12_NC,
277 R_AARCH64_MOVW_GOTOFF_G0,
278 R_AARCH64_MOVW_GOTOFF_G0_NC,
279 R_AARCH64_MOVW_GOTOFF_G1,
280 R_AARCH64_MOVW_GOTOFF_G1_NC,
281 R_AARCH64_MOVW_GOTOFF_G2,
282 R_AARCH64_MOVW_GOTOFF_G2_NC,
283 R_AARCH64_MOVW_GOTOFF_G3,
284 R_AARCH64_GOTREL64,
285 R_AARCH64_GOTREL32,
286 R_AARCH64_GOT_LD_PREL19,
287 R_AARCH64_LD64_GOTOFF_LO15,
288 R_AARCH64_ADR_GOT_PAGE,
289 R_AARCH64_LD64_GOT_LO12_NC,
290 R_AARCH64_LD64_GOTPAGE_LO15,
291 R_AARCH64_TLSGD_ADR_PREL21,
292 R_AARCH64_TLSGD_ADR_PAGE21,
293 R_AARCH64_TLSGD_ADD_LO12_NC,
294 R_AARCH64_TLSGD_MOVW_G1,
295 R_AARCH64_TLSGD_MOVW_G0_NC,
296 R_AARCH64_TLSLD_ADR_PREL21,
297 R_AARCH64_TLSLD_ADR_PAGE21,
298 R_AARCH64_TLSLD_ADD_LO12_NC,
299 R_AARCH64_TLSLD_MOVW_G1,
300 R_AARCH64_TLSLD_MOVW_G0_NC,
301 R_AARCH64_TLSLD_LD_PREL19,
302 R_AARCH64_TLSLD_MOVW_DTPREL_G2,
303 R_AARCH64_TLSLD_MOVW_DTPREL_G1,
304 R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC,
305 R_AARCH64_TLSLD_MOVW_DTPREL_G0,
306 R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC,
307 R_AARCH64_TLSLD_ADD_DTPREL_HI12,
308 R_AARCH64_TLSLD_ADD_DTPREL_LO12,
309 R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC,
310 R_AARCH64_TLSLD_LDST8_DTPREL_LO12,
311 R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC,
312 R_AARCH64_TLSLD_LDST16_DTPREL_LO12,
313 R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC,
314 R_AARCH64_TLSLD_LDST32_DTPREL_LO12,
315 R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC,
316 R_AARCH64_TLSLD_LDST64_DTPREL_LO12,
317 R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC,
318 R_AARCH64_TLSIE_MOVW_GOTTPREL_G1,
319 R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC,
320 R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21,
321 R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC,
322 R_AARCH64_TLSIE_LD_GOTTPREL_PREL19,
323 R_AARCH64_TLSLE_MOVW_TPREL_G2,
324 R_AARCH64_TLSLE_MOVW_TPREL_G1,
325 R_AARCH64_TLSLE_MOVW_TPREL_G1_NC,
326 R_AARCH64_TLSLE_MOVW_TPREL_G0,
327 R_AARCH64_TLSLE_MOVW_TPREL_G0_NC,
328 R_AARCH64_TLSLE_ADD_TPREL_HI12,
329 R_AARCH64_TLSLE_ADD_TPREL_LO12,
330 R_AARCH64_TLSLE_ADD_TPREL_LO12_NC,
331 R_AARCH64_TLSLE_LDST8_TPREL_LO12,
332 R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC,
333 R_AARCH64_TLSLE_LDST16_TPREL_LO12,
334 R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC,
335 R_AARCH64_TLSLE_LDST32_TPREL_LO12,
336 R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC,
337 R_AARCH64_TLSLE_LDST64_TPREL_LO12,
338 R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC,
339 R_AARCH64_TLSDESC_LD_PREL19,
340 R_AARCH64_TLSDESC_ADR_PREL21,
341 R_AARCH64_TLSDESC_ADR_PAGE21,
342 R_AARCH64_TLSDESC_LD64_LO12,
343 R_AARCH64_TLSDESC_ADD_LO12,
344 R_AARCH64_TLSDESC_OFF_G1,
345 R_AARCH64_TLSDESC_OFF_G0_NC,
346 R_AARCH64_TLSDESC_LDR,
347 R_AARCH64_TLSDESC_ADD,
348 R_AARCH64_TLSDESC_CALL,
349 R_AARCH64_TLSLE_LDST128_TPREL_LO12,
350 R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC,
351 R_AARCH64_TLSLD_LDST128_DTPREL_LO12,
352 R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC,
353 R_AARCH64_COPY,
354 R_AARCH64_GLOB_DAT,
355 R_AARCH64_JUMP_SLOT,
356 R_AARCH64_RELATIVE,
357 R_AARCH64_TLS_DTPMOD,
358 R_AARCH64_TLS_DTPREL,
359 R_AARCH64_TLS_TPREL,
360 R_AARCH64_TLSDESC,
361 R_AARCH64_IRELATIVE,
362 ] {
363 Cow::Borrowed(name)
364 } else {
365 Cow::Owned(format!("Unknown aarch64 relocation type 0x{r_type:x}"))
366 }
367}
368
369#[must_use]
370pub fn riscv64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
371 if let Some(name) = const_name_by_value![
372 r_type,
373 R_RISCV_NONE,
374 R_RISCV_32,
375 R_RISCV_64,
376 R_RISCV_RELATIVE,
377 R_RISCV_COPY,
378 R_RISCV_JUMP_SLOT,
379 R_RISCV_TLS_DTPMOD32,
380 R_RISCV_TLS_DTPMOD64,
381 R_RISCV_TLS_DTPREL32,
382 R_RISCV_TLS_DTPREL64,
383 R_RISCV_TLS_TPREL32,
384 R_RISCV_TLS_TPREL64,
385 R_RISCV_TLSDESC,
386 R_RISCV_BRANCH,
387 R_RISCV_JAL,
388 R_RISCV_CALL,
389 R_RISCV_CALL_PLT,
390 R_RISCV_GOT_HI20,
391 R_RISCV_TLS_GOT_HI20,
392 R_RISCV_TLS_GD_HI20,
393 R_RISCV_PCREL_HI20,
394 R_RISCV_PCREL_LO12_I,
395 R_RISCV_PCREL_LO12_S,
396 R_RISCV_HI20,
397 R_RISCV_LO12_I,
398 R_RISCV_LO12_S,
399 R_RISCV_TPREL_HI20,
400 R_RISCV_TPREL_LO12_I,
401 R_RISCV_TPREL_LO12_S,
402 R_RISCV_TPREL_ADD,
403 R_RISCV_ADD8,
404 R_RISCV_ADD16,
405 R_RISCV_ADD32,
406 R_RISCV_ADD64,
407 R_RISCV_SUB8,
408 R_RISCV_SUB16,
409 R_RISCV_SUB32,
410 R_RISCV_SUB64,
411 R_RISCV_GOT32_PCREL,
412 R_RISCV_ALIGN,
413 R_RISCV_RVC_BRANCH,
414 R_RISCV_RVC_JUMP,
415 R_RISCV_RVC_LUI,
416 R_RISCV_GPREL_I,
417 R_RISCV_GPREL_S,
418 R_RISCV_TPREL_I,
419 R_RISCV_TPREL_S,
420 R_RISCV_RELAX,
421 R_RISCV_SUB6,
422 R_RISCV_SET6,
423 R_RISCV_SET8,
424 R_RISCV_SET16,
425 R_RISCV_SET32,
426 R_RISCV_32_PCREL,
427 R_RISCV_IRELATIVE,
428 R_RISCV_PLT32,
429 R_RISCV_SET_ULEB128,
430 R_RISCV_SUB_ULEB128,
431 R_RISCV_TLSDESC_HI20,
432 R_RISCV_TLSDESC_LOAD_LO12,
433 R_RISCV_TLSDESC_ADD_LO12,
434 R_RISCV_TLSDESC_CALL,
435 ] {
436 Cow::Borrowed(name)
437 } else {
438 Cow::Owned(format!("Unknown riscv64 relocation type 0x{r_type:x}"))
439 }
440}
441
442pub mod shf {
444 use super::SectionFlags;
445
446 pub const WRITE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_WRITE);
447 pub const ALLOC: SectionFlags = SectionFlags::from_u32(object::elf::SHF_ALLOC);
448 pub const EXECINSTR: SectionFlags = SectionFlags::from_u32(object::elf::SHF_EXECINSTR);
449 pub const MERGE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_MERGE);
450 pub const STRINGS: SectionFlags = SectionFlags::from_u32(object::elf::SHF_STRINGS);
451 pub const INFO_LINK: SectionFlags = SectionFlags::from_u32(object::elf::SHF_INFO_LINK);
452 pub const LINK_ORDER: SectionFlags = SectionFlags::from_u32(object::elf::SHF_LINK_ORDER);
453 pub const OS_NONCONFORMING: SectionFlags =
454 SectionFlags::from_u32(object::elf::SHF_OS_NONCONFORMING);
455 pub const GROUP: SectionFlags = SectionFlags::from_u32(object::elf::SHF_GROUP);
456 pub const TLS: SectionFlags = SectionFlags::from_u32(object::elf::SHF_TLS);
457 pub const COMPRESSED: SectionFlags = SectionFlags::from_u32(object::elf::SHF_COMPRESSED);
458 pub const GNU_RETAIN: SectionFlags = SectionFlags::from_u32(object::elf::SHF_GNU_RETAIN);
459 pub const EXCLUDE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_EXCLUDE);
460}
461
462#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
463pub struct SectionFlags(u32);
464
465impl SectionFlags {
466 #[must_use]
467 pub const fn empty() -> Self {
468 Self(0)
469 }
470
471 #[must_use]
472 pub fn from_header(header: &object::elf::SectionHeader64<LittleEndian>) -> Self {
473 Self(header.sh_flags(LittleEndian) as u32)
474 }
475
476 #[must_use]
477 pub fn contains(self, flag: SectionFlags) -> bool {
478 self.0 & flag.0 != 0
479 }
480
481 #[must_use]
482 pub const fn from_u32(raw: u32) -> SectionFlags {
483 SectionFlags(raw)
484 }
485
486 #[must_use]
488 pub const fn with(self, flags: SectionFlags) -> SectionFlags {
489 SectionFlags(self.0 | flags.0)
490 }
491
492 #[must_use]
494 pub const fn without(self, flags: SectionFlags) -> SectionFlags {
495 SectionFlags(self.0 & !flags.0)
496 }
497
498 #[must_use]
499 pub const fn raw(self) -> u64 {
500 self.0 as u64
501 }
502
503 #[must_use]
504 pub fn should_retain(&self) -> bool {
505 self.contains(shf::GNU_RETAIN)
506 }
507
508 #[must_use]
509 pub fn should_exclude(&self) -> bool {
510 self.contains(shf::EXCLUDE)
511 }
512}
513
514impl From<u64> for SectionFlags {
515 fn from(value: u64) -> Self {
516 Self(value as u32)
517 }
518}
519
520impl std::fmt::Display for SectionFlags {
521 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
522 for (flag, ch) in [
523 (shf::WRITE, "W"),
524 (shf::ALLOC, "A"),
525 (shf::EXECINSTR, "X"),
526 (shf::MERGE, "M"),
527 (shf::STRINGS, "S"),
528 (shf::INFO_LINK, "I"),
529 (shf::LINK_ORDER, "L"),
530 (shf::OS_NONCONFORMING, "O"),
531 (shf::GROUP, "G"),
532 (shf::TLS, "T"),
533 (shf::COMPRESSED, "C"),
534 (shf::EXCLUDE, "E"),
535 ] {
538 if self.contains(flag) {
539 f.write_str(ch)?;
540 }
541 }
542 Ok(())
543 }
544}
545
546impl std::fmt::Debug for SectionFlags {
547 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
548 std::fmt::Display::fmt(&self, f)
549 }
550}
551
552impl std::ops::BitOrAssign for SectionFlags {
553 fn bitor_assign(&mut self, rhs: Self) {
554 self.0 |= rhs.0;
555 }
556}
557
558impl std::ops::BitAnd for SectionFlags {
559 type Output = SectionFlags;
560
561 fn bitand(self, rhs: Self) -> Self::Output {
562 Self(self.0 & rhs.0)
563 }
564}
565
566pub mod secnames {
567 pub const FILEHEADER_SECTION_NAME_STR: &str = "";
568 pub const FILEHEADER_SECTION_NAME: &[u8] = FILEHEADER_SECTION_NAME_STR.as_bytes();
569 pub const RODATA_SECTION_NAME_STR: &str = ".rodata";
570 pub const RODATA_SECTION_NAME: &[u8] = RODATA_SECTION_NAME_STR.as_bytes();
571 pub const TEXT_SECTION_NAME_STR: &str = ".text";
572 pub const TEXT_SECTION_NAME: &[u8] = TEXT_SECTION_NAME_STR.as_bytes();
573 pub const INIT_ARRAY_SECTION_NAME_STR: &str = ".init_array";
574 pub const INIT_ARRAY_SECTION_NAME: &[u8] = INIT_ARRAY_SECTION_NAME_STR.as_bytes();
575 pub const FINI_ARRAY_SECTION_NAME_STR: &str = ".fini_array";
576 pub const FINI_ARRAY_SECTION_NAME: &[u8] = FINI_ARRAY_SECTION_NAME_STR.as_bytes();
577 pub const PREINIT_ARRAY_SECTION_NAME_STR: &str = ".preinit_array";
578 pub const PREINIT_ARRAY_SECTION_NAME: &[u8] = PREINIT_ARRAY_SECTION_NAME_STR.as_bytes();
579 pub const DATA_SECTION_NAME_STR: &str = ".data";
580 pub const DATA_SECTION_NAME: &[u8] = DATA_SECTION_NAME_STR.as_bytes();
581 pub const EH_FRAME_SECTION_NAME_STR: &str = ".eh_frame";
582 pub const EH_FRAME_SECTION_NAME: &[u8] = EH_FRAME_SECTION_NAME_STR.as_bytes();
583 pub const EH_FRAME_HDR_SECTION_NAME_STR: &str = ".eh_frame_hdr";
584 pub const EH_FRAME_HDR_SECTION_NAME: &[u8] = EH_FRAME_HDR_SECTION_NAME_STR.as_bytes();
585 pub const SHSTRTAB_SECTION_NAME_STR: &str = ".shstrtab";
586 pub const SHSTRTAB_SECTION_NAME: &[u8] = SHSTRTAB_SECTION_NAME_STR.as_bytes();
587 pub const SYMTAB_SECTION_NAME_STR: &str = ".symtab";
588 pub const SYMTAB_SECTION_NAME: &[u8] = SYMTAB_SECTION_NAME_STR.as_bytes();
589 pub const STRTAB_SECTION_NAME_STR: &str = ".strtab";
590 pub const STRTAB_SECTION_NAME: &[u8] = STRTAB_SECTION_NAME_STR.as_bytes();
591 pub const TDATA_SECTION_NAME_STR: &str = ".tdata";
592 pub const TDATA_SECTION_NAME: &[u8] = TDATA_SECTION_NAME_STR.as_bytes();
593 pub const TBSS_SECTION_NAME_STR: &str = ".tbss";
594 pub const TBSS_SECTION_NAME: &[u8] = TBSS_SECTION_NAME_STR.as_bytes();
595 pub const BSS_SECTION_NAME_STR: &str = ".bss";
596 pub const BSS_SECTION_NAME: &[u8] = BSS_SECTION_NAME_STR.as_bytes();
597 pub const GOT_SECTION_NAME_STR: &str = ".got";
598 pub const GOT_SECTION_NAME: &[u8] = GOT_SECTION_NAME_STR.as_bytes();
599 pub const INIT_SECTION_NAME_STR: &str = ".init";
600 pub const INIT_SECTION_NAME: &[u8] = INIT_SECTION_NAME_STR.as_bytes();
601 pub const FINI_SECTION_NAME_STR: &str = ".fini";
602 pub const FINI_SECTION_NAME: &[u8] = FINI_SECTION_NAME_STR.as_bytes();
603 pub const RELA_PLT_SECTION_NAME_STR: &str = ".rela.plt";
604 pub const RELA_PLT_SECTION_NAME: &[u8] = RELA_PLT_SECTION_NAME_STR.as_bytes();
605 pub const COMMENT_SECTION_NAME_STR: &str = ".comment";
606 pub const COMMENT_SECTION_NAME: &[u8] = COMMENT_SECTION_NAME_STR.as_bytes();
607 pub const DYNAMIC_SECTION_NAME_STR: &str = ".dynamic";
608 pub const DYNAMIC_SECTION_NAME: &[u8] = DYNAMIC_SECTION_NAME_STR.as_bytes();
609 pub const DYNSYM_SECTION_NAME_STR: &str = ".dynsym";
610 pub const DYNSYM_SECTION_NAME: &[u8] = DYNSYM_SECTION_NAME_STR.as_bytes();
611 pub const DYNSTR_SECTION_NAME_STR: &str = ".dynstr";
612 pub const DYNSTR_SECTION_NAME: &[u8] = DYNSTR_SECTION_NAME_STR.as_bytes();
613 pub const RELA_DYN_SECTION_NAME_STR: &str = ".rela.dyn";
614 pub const RELA_DYN_SECTION_NAME: &[u8] = RELA_DYN_SECTION_NAME_STR.as_bytes();
615 pub const GCC_EXCEPT_TABLE_SECTION_NAME_STR: &str = ".gcc_except_table";
616 pub const GCC_EXCEPT_TABLE_SECTION_NAME: &[u8] = GCC_EXCEPT_TABLE_SECTION_NAME_STR.as_bytes();
617 pub const INTERP_SECTION_NAME_STR: &str = ".interp";
618 pub const INTERP_SECTION_NAME: &[u8] = INTERP_SECTION_NAME_STR.as_bytes();
619 pub const GNU_VERSION_SECTION_NAME_STR: &str = ".gnu.version";
620 pub const GNU_VERSION_SECTION_NAME: &[u8] = GNU_VERSION_SECTION_NAME_STR.as_bytes();
621 pub const GNU_VERSION_D_SECTION_NAME_STR: &str = ".gnu.version_d";
622 pub const GNU_VERSION_D_SECTION_NAME: &[u8] = GNU_VERSION_D_SECTION_NAME_STR.as_bytes();
623 pub const GNU_VERSION_R_SECTION_NAME_STR: &str = ".gnu.version_r";
624 pub const GNU_VERSION_R_SECTION_NAME: &[u8] = GNU_VERSION_R_SECTION_NAME_STR.as_bytes();
625 pub const PROGRAM_HEADERS_SECTION_NAME_STR: &str = ".phdr";
626 pub const PROGRAM_HEADERS_SECTION_NAME: &[u8] = PROGRAM_HEADERS_SECTION_NAME_STR.as_bytes();
627 pub const SECTION_HEADERS_SECTION_NAME_STR: &str = ".shdr";
628 pub const SECTION_HEADERS_SECTION_NAME: &[u8] = SECTION_HEADERS_SECTION_NAME_STR.as_bytes();
629 pub const GNU_HASH_SECTION_NAME_STR: &str = ".gnu.hash";
630 pub const GNU_HASH_SECTION_NAME: &[u8] = GNU_HASH_SECTION_NAME_STR.as_bytes();
631 pub const PLT_SECTION_NAME_STR: &str = ".plt";
632 pub const PLT_SECTION_NAME: &[u8] = PLT_SECTION_NAME_STR.as_bytes();
633 pub const IPLT_SECTION_NAME_STR: &str = ".iplt";
634 pub const IPLT_SECTION_NAME: &[u8] = IPLT_SECTION_NAME_STR.as_bytes();
635 pub const PLT_GOT_SECTION_NAME_STR: &str = ".plt.got";
636 pub const PLT_GOT_SECTION_NAME: &[u8] = PLT_GOT_SECTION_NAME_STR.as_bytes();
637 pub const GOT_PLT_SECTION_NAME_STR: &str = ".got.plt";
638 pub const GOT_PLT_SECTION_NAME: &[u8] = GOT_PLT_SECTION_NAME_STR.as_bytes();
639 pub const PLT_SEC_SECTION_NAME_STR: &str = ".plt.sec";
640 pub const PLT_SEC_SECTION_NAME: &[u8] = PLT_SEC_SECTION_NAME_STR.as_bytes();
641 pub const NOTE_ABI_TAG_SECTION_NAME_STR: &str = ".note.ABI-tag";
642 pub const NOTE_ABI_TAG_SECTION_NAME: &[u8] = NOTE_ABI_TAG_SECTION_NAME_STR.as_bytes();
643 pub const NOTE_GNU_PROPERTY_SECTION_NAME_STR: &str = ".note.gnu.property";
644 pub const NOTE_GNU_PROPERTY_SECTION_NAME: &[u8] = NOTE_GNU_PROPERTY_SECTION_NAME_STR.as_bytes();
645 pub const NOTE_GNU_BUILD_ID_SECTION_NAME_STR: &str = ".note.gnu.build-id";
646 pub const NOTE_GNU_BUILD_ID_SECTION_NAME: &[u8] = NOTE_GNU_BUILD_ID_SECTION_NAME_STR.as_bytes();
647 pub const DEBUG_LOC_SECTION_NAME_STR: &str = ".debug_loc";
648 pub const DEBUG_LOC_SECTION_NAME: &[u8] = DEBUG_LOC_SECTION_NAME_STR.as_bytes();
649 pub const DEBUG_RANGES_SECTION_NAME_STR: &str = ".debug_ranges";
650 pub const DEBUG_RANGES_SECTION_NAME: &[u8] = DEBUG_RANGES_SECTION_NAME_STR.as_bytes();
651 pub const GROUP_SECTION_NAME_STR: &str = ".group";
652 pub const GROUP_SECTION_NAME: &[u8] = GROUP_SECTION_NAME_STR.as_bytes();
653 pub const DATA_REL_RO_SECTION_NAME_STR: &str = ".data.rel.ro";
654 pub const DATA_REL_RO_SECTION_NAME: &[u8] = DATA_REL_RO_SECTION_NAME_STR.as_bytes();
655 pub const RISCV_ATTRIBUTES_SECTION_NAME_STR: &str = ".riscv.attributes";
656 pub const RISCV_ATTRIBUTES_SECTION_NAME: &[u8] = RISCV_ATTRIBUTES_SECTION_NAME_STR.as_bytes();
657
658 pub const GNU_LTO_SYMTAB_PREFIX: &str = ".gnu.lto_.symtab";
659}
660
661#[derive(Clone, Copy, PartialEq, Eq)]
662pub struct SegmentFlags(u32);
663
664impl SegmentFlags {
665 #[must_use]
666 pub const fn empty() -> Self {
667 Self(0)
668 }
669
670 #[must_use]
671 pub fn from_header(header: &object::elf::ProgramHeader64<LittleEndian>) -> Self {
672 Self(header.p_flags(LittleEndian))
673 }
674
675 #[must_use]
676 pub fn contains(self, flag: SegmentFlags) -> bool {
677 self.0 & flag.0 != 0
678 }
679
680 #[must_use]
681 pub const fn from_u32(raw: u32) -> SegmentFlags {
682 SegmentFlags(raw)
683 }
684
685 #[must_use]
687 pub const fn with(self, flags: SegmentFlags) -> SegmentFlags {
688 SegmentFlags(self.0 | flags.0)
689 }
690
691 #[must_use]
693 pub const fn without(self, flags: SegmentFlags) -> SegmentFlags {
694 SegmentFlags(self.0 & !flags.0)
695 }
696
697 #[must_use]
698 pub const fn raw(self) -> u32 {
699 self.0
700 }
701}
702
703pub mod pf {
704 use super::SegmentFlags;
705
706 pub const EXECUTABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_X);
707 pub const WRITABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_W);
708 pub const READABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_R);
709}
710
711impl std::fmt::Display for SegmentFlags {
712 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
713 if self.contains(pf::WRITABLE) {
714 f.write_str("W")?;
715 }
716 if self.contains(pf::READABLE) {
717 f.write_str("R")?;
718 }
719 if self.contains(pf::EXECUTABLE) {
720 f.write_str("X")?;
721 }
722 Ok(())
723 }
724}
725
726impl std::fmt::Debug for SegmentFlags {
727 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
728 std::fmt::Display::fmt(&self, f)
729 }
730}
731
732impl std::ops::BitOrAssign for SegmentFlags {
733 fn bitor_assign(&mut self, rhs: Self) {
734 self.0 |= rhs.0;
735 }
736}
737
738impl std::ops::BitAnd for SegmentFlags {
739 type Output = SegmentFlags;
740
741 fn bitand(self, rhs: Self) -> Self::Output {
742 Self(self.0 & rhs.0)
743 }
744}
745
746pub const RISCV_TLS_DTV_OFFSET: u64 = 0x800;
750
751pub const RISCV_ATTRIBUTE_VENDOR_NAME: &str = "riscv";
752
753pub mod riscvattr {
755 pub const TAG_RISCV_WHOLE_FILE: u64 = 1;
757 pub const TAG_RISCV_STACK_ALIGN: u64 = 4;
759 pub const TAG_RISCV_ARCH: u64 = 5;
761 pub const TAG_RISCV_UNALIGNED_ACCESS: u64 = 6;
763 pub const TAG_RISCV_PRIV_SPEC: u64 = 8;
765 pub const TAG_RISCV_PRIV_SPEC_MINOR: u64 = 10;
767 pub const TAG_RISCV_PRIV_SPEC_REVISION: u64 = 12;
769 pub const TAG_RISCV_ATOMIC_ABI: u64 = 14;
771 pub const TAG_RISCV_X3_REG_USAGE: u64 = 16;
773}
774
775#[derive(Clone, Copy, Debug, PartialEq, Eq)]
776pub enum Sign {
777 Signed,
778 Unsigned,
779}
780
781#[derive(Clone, Copy, Debug, PartialEq, Eq)]
785pub enum RelocationKind {
786 Absolute,
788
789 AbsoluteSet,
791
792 AbsoluteSetWord6,
794
795 AbsoluteAddition,
798
799 AbsoluteSubtraction,
802
803 AbsoluteSubtractionWord6,
806
807 AbsoluteAArch64,
810
811 PairSubtraction,
813
814 Relative,
816
817 RelativeRiscVLow12,
821
822 SymRelGotBase,
824
825 GotRelGotBase,
827
828 Got,
830
831 PltRelGotBase,
833
834 PltRelative,
836
837 GotRelative,
839
840 TlsGd,
844
845 TlsGdGot,
847
848 TlsGdGotBase,
850
851 TlsLd,
855
856 TlsLdGot,
858
859 TlsLdGotBase,
862
863 DtpOff,
865
866 GotTpOff,
869
870 GotTpOffGot,
873
874 GotTpOffGotBase,
877
878 TpOff,
880
881 TlsDesc,
883
884 TlsDescGot,
886
887 TlsDescGotBase,
889
890 TlsDescCall,
892
893 None,
896
897 Alignment,
899}
900
901impl RelocationKind {
902 #[must_use]
903 pub fn is_tls(self) -> bool {
904 matches!(
905 self,
906 Self::DtpOff
907 | Self::GotTpOff
908 | Self::GotTpOffGotBase
909 | Self::TlsDesc
910 | Self::TlsDescCall
911 | Self::TlsDescGot
912 | Self::TlsDescGotBase
913 | Self::TlsGd
914 | Self::TlsGdGot
915 | Self::TlsGdGotBase
916 | Self::TlsLd
917 | Self::TlsLdGot
918 | Self::TlsLdGotBase
919 | Self::TpOff
920 )
921 }
922}
923
924#[derive(Copy, Clone, Debug, PartialEq, Eq)]
925pub enum DynamicRelocationKind {
926 Copy,
927 Irelative,
928 DtpMod,
929 DtpOff,
930 TlsDesc,
931 TpOff,
932 Relative,
933 Absolute,
934 GotEntry,
935 JumpSlot,
936}
937
938impl DynamicRelocationKind {
939 #[must_use]
940 pub fn from_x86_64_r_type(r_type: u32) -> Option<Self> {
941 let kind = match r_type {
942 object::elf::R_X86_64_COPY => DynamicRelocationKind::Copy,
943 object::elf::R_X86_64_IRELATIVE => DynamicRelocationKind::Irelative,
944 object::elf::R_X86_64_DTPMOD64 => DynamicRelocationKind::DtpMod,
945 object::elf::R_X86_64_DTPOFF64 => DynamicRelocationKind::DtpOff,
946 object::elf::R_X86_64_TPOFF64 => DynamicRelocationKind::TpOff,
947 object::elf::R_X86_64_RELATIVE => DynamicRelocationKind::Relative,
948 object::elf::R_X86_64_GLOB_DAT => DynamicRelocationKind::GotEntry,
949 object::elf::R_X86_64_64 => DynamicRelocationKind::Absolute,
950 object::elf::R_X86_64_TLSDESC => DynamicRelocationKind::TlsDesc,
951 object::elf::R_X86_64_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
952 _ => return None,
953 };
954
955 Some(kind)
956 }
957
958 #[must_use]
959 pub fn x86_64_r_type(self) -> u32 {
960 match self {
961 DynamicRelocationKind::Copy => object::elf::R_X86_64_COPY,
962 DynamicRelocationKind::Irelative => object::elf::R_X86_64_IRELATIVE,
963 DynamicRelocationKind::DtpMod => object::elf::R_X86_64_DTPMOD64,
964 DynamicRelocationKind::DtpOff => object::elf::R_X86_64_DTPOFF64,
965 DynamicRelocationKind::TpOff => object::elf::R_X86_64_TPOFF64,
966 DynamicRelocationKind::Relative => object::elf::R_X86_64_RELATIVE,
967 DynamicRelocationKind::Absolute => object::elf::R_X86_64_64,
968 DynamicRelocationKind::GotEntry => object::elf::R_X86_64_GLOB_DAT,
969 DynamicRelocationKind::TlsDesc => object::elf::R_X86_64_TLSDESC,
970 DynamicRelocationKind::JumpSlot => object::elf::R_X86_64_JUMP_SLOT,
971 }
972 }
973
974 #[must_use]
975 pub fn from_aarch64_r_type(r_type: u32) -> Option<Self> {
976 let kind = match r_type {
977 object::elf::R_AARCH64_COPY => DynamicRelocationKind::Copy,
978 object::elf::R_AARCH64_IRELATIVE => DynamicRelocationKind::Irelative,
979 object::elf::R_AARCH64_TLS_DTPMOD => DynamicRelocationKind::DtpMod,
980 object::elf::R_AARCH64_TLS_DTPREL => DynamicRelocationKind::DtpOff,
981 object::elf::R_AARCH64_TLS_TPREL => DynamicRelocationKind::TpOff,
982 object::elf::R_AARCH64_RELATIVE => DynamicRelocationKind::Relative,
983 object::elf::R_AARCH64_ABS64 => DynamicRelocationKind::Absolute,
984 object::elf::R_AARCH64_GLOB_DAT => DynamicRelocationKind::GotEntry,
985 object::elf::R_AARCH64_TLSDESC => DynamicRelocationKind::TlsDesc,
986 object::elf::R_AARCH64_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
987 _ => return None,
988 };
989
990 Some(kind)
991 }
992
993 #[must_use]
994 pub fn aarch64_r_type(&self) -> u32 {
995 match self {
996 DynamicRelocationKind::Copy => object::elf::R_AARCH64_COPY,
997 DynamicRelocationKind::Irelative => object::elf::R_AARCH64_IRELATIVE,
998 DynamicRelocationKind::DtpMod => object::elf::R_AARCH64_TLS_DTPMOD,
999 DynamicRelocationKind::DtpOff => object::elf::R_AARCH64_TLS_DTPREL,
1000 DynamicRelocationKind::TpOff => object::elf::R_AARCH64_TLS_TPREL,
1001 DynamicRelocationKind::Relative => object::elf::R_AARCH64_RELATIVE,
1002 DynamicRelocationKind::Absolute => object::elf::R_AARCH64_ABS64,
1003 DynamicRelocationKind::GotEntry => object::elf::R_AARCH64_GLOB_DAT,
1004 DynamicRelocationKind::TlsDesc => object::elf::R_AARCH64_TLSDESC,
1005 DynamicRelocationKind::JumpSlot => object::elf::R_AARCH64_JUMP_SLOT,
1006 }
1007 }
1008
1009 #[must_use]
1010 pub fn from_riscv64_r_type(r_type: u32) -> Option<Self> {
1011 let kind = match r_type {
1012 object::elf::R_RISCV_COPY => DynamicRelocationKind::Copy,
1013 object::elf::R_RISCV_IRELATIVE => DynamicRelocationKind::Irelative,
1014 object::elf::R_RISCV_TLS_DTPMOD64 => DynamicRelocationKind::DtpMod,
1015 object::elf::R_RISCV_TLS_DTPREL64 => DynamicRelocationKind::DtpOff,
1016 object::elf::R_RISCV_TLS_TPREL64 => DynamicRelocationKind::TpOff,
1017 object::elf::R_RISCV_RELATIVE => DynamicRelocationKind::Relative,
1018 object::elf::R_RISCV_64 => DynamicRelocationKind::Absolute,
1019 object::elf::R_RISCV_TLSDESC => DynamicRelocationKind::TlsDesc,
1020 object::elf::R_RISCV_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1021 _ => return None,
1022 };
1023 Some(kind)
1024 }
1025
1026 #[must_use]
1027 pub fn riscv64_r_type(&self) -> u32 {
1028 match self {
1029 DynamicRelocationKind::Copy => object::elf::R_RISCV_COPY,
1030 DynamicRelocationKind::Irelative => object::elf::R_RISCV_IRELATIVE,
1031 DynamicRelocationKind::DtpMod => object::elf::R_RISCV_TLS_DTPMOD64,
1032 DynamicRelocationKind::DtpOff => object::elf::R_RISCV_TLS_DTPREL64,
1033 DynamicRelocationKind::TpOff => object::elf::R_RISCV_TLS_TPREL64,
1034 DynamicRelocationKind::Relative => object::elf::R_RISCV_RELATIVE,
1035 DynamicRelocationKind::Absolute => object::elf::R_RISCV_64,
1036 DynamicRelocationKind::GotEntry => object::elf::R_RISCV_64,
1037 DynamicRelocationKind::TlsDesc => object::elf::R_RISCV_TLSDESC,
1038 DynamicRelocationKind::JumpSlot => object::elf::R_RISCV_JUMP_SLOT,
1039 }
1040 }
1041}
1042
1043#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1044pub enum AArch64Instruction {
1045 Adr,
1046 Movkz,
1047 Movnz,
1048 Ldr,
1049 LdrRegister,
1050 Add,
1051 LdSt,
1052 TstBr,
1053 Bcond,
1054 JumpCall,
1055}
1056
1057#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1058pub enum RiscVInstruction {
1059 UiType,
1066
1067 UType,
1069
1070 IType,
1072
1073 SType,
1075
1076 BType,
1081
1082 JType,
1084
1085 CbType,
1088
1089 CjType,
1091
1092 Uleb128,
1094}
1095
1096#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1097pub enum RelocationInstruction {
1098 AArch64(AArch64Instruction),
1099 RiscV(RiscVInstruction),
1100}
1101
1102impl RelocationInstruction {
1103 #[must_use]
1104 pub fn bit_mask(&self, range: BitRange) -> [u8; 4] {
1105 let mut mask = [0; 4];
1106
1107 let all_ones = (1 << (range.end - range.start)) - 1;
1110 self.write_to_value(all_ones, false, &mut mask);
1111
1112 for b in &mut mask {
1114 *b = !*b;
1115 }
1116
1117 mask
1118 }
1119
1120 pub fn write_to_value(self, extracted_value: u64, negative: bool, dest: &mut [u8]) {
1121 match self {
1122 Self::AArch64(insn) => insn.write_to_value(extracted_value, negative, dest),
1123 Self::RiscV(insn) => insn.write_to_value(extracted_value, negative, dest),
1124 }
1125 }
1126
1127 #[must_use]
1130 pub fn read_value(self, bytes: &[u8]) -> (u64, bool) {
1131 match self {
1132 Self::AArch64(insn) => insn.read_value(bytes),
1133 Self::RiscV(insn) => insn.read_value(bytes),
1134 }
1135 }
1136
1137 #[must_use]
1139 pub fn write_windows_size(self) -> usize {
1140 match self {
1141 Self::AArch64(..) => 4,
1142 Self::RiscV(..) => 10,
1143 }
1144 }
1145}
1146
1147#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1148pub enum RelocationSize {
1149 ByteSize(usize),
1150 BitMasking(BitMask),
1151}
1152
1153impl fmt::Display for RelocationSize {
1154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1155 match self {
1156 Self::ByteSize(bytes) => f.write_fmt(format_args!("{bytes}B")),
1157 Self::BitMasking(mask) => {
1158 f.write_fmt(format_args!("{}..{}", mask.range.start, mask.range.end))
1159 }
1160 }
1161 }
1162}
1163
1164impl RelocationSize {
1165 pub(crate) const fn bit_mask_aarch64(
1166 bit_start: u32,
1167 bit_end: u32,
1168 instruction: AArch64Instruction,
1169 ) -> RelocationSize {
1170 Self::BitMasking(BitMask::new(
1171 RelocationInstruction::AArch64(instruction),
1172 bit_start,
1173 bit_end,
1174 ))
1175 }
1176
1177 pub(crate) const fn bit_mask_riscv(
1178 bit_start: u32,
1179 bit_end: u32,
1180 instruction: RiscVInstruction,
1181 ) -> RelocationSize {
1182 Self::BitMasking(BitMask::new(
1183 RelocationInstruction::RiscV(instruction),
1184 bit_start,
1185 bit_end,
1186 ))
1187 }
1188}
1189
1190#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1191pub struct BitMask {
1192 pub instruction: RelocationInstruction,
1193 pub range: BitRange,
1194}
1195
1196#[derive(Debug, Clone, Copy)]
1197pub enum PageMask {
1198 SymbolPlusAddendAndPosition,
1199 GotEntryAndPosition,
1200 GotBase,
1201}
1202
1203#[derive(Clone, Debug, Copy, PartialEq)]
1205pub struct AllowedRange {
1206 pub min: i64,
1207 pub max: i64,
1208}
1209
1210impl AllowedRange {
1211 #[must_use]
1212 pub const fn new(min: i64, max: i64) -> Self {
1213 Self { min, max }
1214 }
1215
1216 #[must_use]
1217 pub const fn no_check() -> Self {
1218 Self::new(i64::MIN, i64::MAX)
1219 }
1220
1221 #[must_use]
1222 pub const fn from_byte_size(n_bytes: usize, sign: Sign) -> Self {
1225 match n_bytes {
1226 0 | 8 => Self::no_check(),
1227 1..=7 => {
1228 let bits = n_bytes * 8;
1229 let half_range = 1i64 << (bits - 1);
1230 match sign {
1231 Sign::Unsigned => Self::new(0, half_range * 2 - 1),
1232 Sign::Signed => Self::new(-half_range, half_range - 1),
1233 }
1234 }
1235 _ => panic!("Only sizes up to 8 bytes are supported"),
1236 }
1237 }
1238}
1239
1240#[derive(Clone, Debug, Copy)]
1241pub struct RelocationKindInfo {
1242 pub kind: RelocationKind,
1243 pub size: RelocationSize,
1244 pub mask: Option<PageMask>,
1245 pub range: AllowedRange,
1246 pub alignment: usize,
1247}
1248
1249impl RelocationKindInfo {
1250 #[inline(always)]
1251 pub fn verify(&self, value: i64) -> Result<()> {
1252 anyhow::ensure!(
1253 (value as usize) & (self.alignment - 1) == 0,
1254 "Relocation {value} not aligned to {} bytes",
1255 self.alignment
1256 );
1257 anyhow::ensure!(
1258 self.range.min <= value && value < self.range.max,
1259 format!(
1260 "Relocation {value} outside of bounds [{}, {})",
1261 self.range.min, self.range.max
1262 )
1263 );
1264 Ok(())
1265 }
1266}
1267
1268impl BitMask {
1269 #[must_use]
1270 pub const fn new(instruction: RelocationInstruction, bit_start: u32, bit_end: u32) -> Self {
1271 Self {
1272 instruction,
1273 range: BitRange {
1274 start: bit_start,
1275 end: bit_end,
1276 },
1277 }
1278 }
1279}
1280
1281#[cfg(test)]
1282mod tests {
1283 use super::*;
1284 use object::elf::*;
1285
1286 #[test]
1287 fn test_rel_type_to_string() {
1288 assert_eq!(
1289 &x86_64_rel_type_to_string(R_X86_64_32),
1290 stringify!(R_X86_64_32)
1291 );
1292 assert_eq!(
1293 &x86_64_rel_type_to_string(R_X86_64_GOTPC32_TLSDESC),
1294 stringify!(R_X86_64_GOTPC32_TLSDESC)
1295 );
1296 assert_eq!(
1297 &x86_64_rel_type_to_string(64),
1298 "Unknown x86_64 relocation type 0x40"
1299 );
1300
1301 assert_eq!(
1302 &aarch64_rel_type_to_string(64),
1303 "Unknown aarch64 relocation type 0x40"
1304 );
1305 }
1306
1307 #[test]
1308 fn test_range_from_byte_size() {
1309 assert_eq!(
1310 AllowedRange::from_byte_size(0, Sign::Signed),
1311 AllowedRange::no_check(),
1312 );
1313 assert_eq!(
1314 AllowedRange::from_byte_size(0, Sign::Unsigned),
1315 AllowedRange::no_check(),
1316 );
1317 assert_eq!(
1318 AllowedRange::from_byte_size(1, Sign::Signed),
1319 AllowedRange::new(-128, 127)
1320 );
1321 assert_eq!(
1322 AllowedRange::from_byte_size(1, Sign::Unsigned),
1323 AllowedRange::new(0, 255)
1324 );
1325 assert_eq!(
1326 AllowedRange::from_byte_size(4, Sign::Signed),
1327 AllowedRange::new(i32::MIN.into(), i32::MAX.into())
1328 );
1329 assert_eq!(
1330 AllowedRange::from_byte_size(4, Sign::Unsigned),
1331 AllowedRange::new(u32::MIN.into(), u32::MAX.into())
1332 );
1333 assert_eq!(
1334 AllowedRange::from_byte_size(8, Sign::Signed),
1335 AllowedRange::no_check()
1336 );
1337 assert_eq!(
1339 AllowedRange::from_byte_size(8, Sign::Unsigned),
1340 AllowedRange::no_check()
1341 );
1342 }
1343}