1use anyhow::Result;
2use object::LittleEndian;
3use object::read::elf::ProgramHeader as _;
4use object::read::elf::SectionHeader;
5use std::borrow::Cow;
6
7macro_rules! const_name_by_value {
8 ($needle: expr, $( $const:ident ),*) => {
9 match $needle {
10 $(object::elf::$const => Some(stringify!($const)),)*
11 _ => None
12 }
13 };
14}
15
16#[must_use]
17pub fn x86_64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
18 if let Some(name) = const_name_by_value![
19 r_type,
20 R_X86_64_NONE,
21 R_X86_64_64,
22 R_X86_64_PC32,
23 R_X86_64_GOT32,
24 R_X86_64_PLT32,
25 R_X86_64_COPY,
26 R_X86_64_GLOB_DAT,
27 R_X86_64_JUMP_SLOT,
28 R_X86_64_RELATIVE,
29 R_X86_64_GOTPCREL,
30 R_X86_64_32,
31 R_X86_64_32S,
32 R_X86_64_16,
33 R_X86_64_PC16,
34 R_X86_64_8,
35 R_X86_64_PC8,
36 R_X86_64_DTPMOD64,
37 R_X86_64_DTPOFF64,
38 R_X86_64_TPOFF64,
39 R_X86_64_TLSGD,
40 R_X86_64_TLSLD,
41 R_X86_64_DTPOFF32,
42 R_X86_64_GOTTPOFF,
43 R_X86_64_TPOFF32,
44 R_X86_64_PC64,
45 R_X86_64_GOTOFF64,
46 R_X86_64_GOTPC32,
47 R_X86_64_GOT64,
48 R_X86_64_GOTPCREL64,
49 R_X86_64_GOTPC64,
50 R_X86_64_GOTPLT64,
51 R_X86_64_PLTOFF64,
52 R_X86_64_SIZE32,
53 R_X86_64_SIZE64,
54 R_X86_64_GOTPC32_TLSDESC,
55 R_X86_64_TLSDESC_CALL,
56 R_X86_64_TLSDESC,
57 R_X86_64_IRELATIVE,
58 R_X86_64_RELATIVE64,
59 R_X86_64_GOTPCRELX,
60 R_X86_64_REX_GOTPCRELX
61 ] {
62 Cow::Borrowed(name)
63 } else {
64 Cow::Owned(format!("Unknown x86_64 relocation type 0x{r_type:x}"))
65 }
66}
67
68#[must_use]
69pub fn aarch64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
70 if let Some(name) = const_name_by_value![
71 r_type,
72 R_AARCH64_NONE,
73 R_AARCH64_P32_ABS32,
74 R_AARCH64_P32_COPY,
75 R_AARCH64_P32_GLOB_DAT,
76 R_AARCH64_P32_JUMP_SLOT,
77 R_AARCH64_P32_RELATIVE,
78 R_AARCH64_P32_TLS_DTPMOD,
79 R_AARCH64_P32_TLS_DTPREL,
80 R_AARCH64_P32_TLS_TPREL,
81 R_AARCH64_P32_TLSDESC,
82 R_AARCH64_P32_IRELATIVE,
83 R_AARCH64_ABS64,
84 R_AARCH64_ABS32,
85 R_AARCH64_ABS16,
86 R_AARCH64_PREL64,
87 R_AARCH64_PREL32,
88 R_AARCH64_PREL16,
89 R_AARCH64_MOVW_UABS_G0,
90 R_AARCH64_MOVW_UABS_G0_NC,
91 R_AARCH64_MOVW_UABS_G1,
92 R_AARCH64_MOVW_UABS_G1_NC,
93 R_AARCH64_MOVW_UABS_G2,
94 R_AARCH64_MOVW_UABS_G2_NC,
95 R_AARCH64_MOVW_UABS_G3,
96 R_AARCH64_MOVW_SABS_G0,
97 R_AARCH64_MOVW_SABS_G1,
98 R_AARCH64_MOVW_SABS_G2,
99 R_AARCH64_LD_PREL_LO19,
100 R_AARCH64_ADR_PREL_LO21,
101 R_AARCH64_ADR_PREL_PG_HI21,
102 R_AARCH64_ADR_PREL_PG_HI21_NC,
103 R_AARCH64_ADD_ABS_LO12_NC,
104 R_AARCH64_LDST8_ABS_LO12_NC,
105 R_AARCH64_TSTBR14,
106 R_AARCH64_CONDBR19,
107 R_AARCH64_JUMP26,
108 R_AARCH64_CALL26,
109 R_AARCH64_LDST16_ABS_LO12_NC,
110 R_AARCH64_LDST32_ABS_LO12_NC,
111 R_AARCH64_LDST64_ABS_LO12_NC,
112 R_AARCH64_MOVW_PREL_G0,
113 R_AARCH64_MOVW_PREL_G0_NC,
114 R_AARCH64_MOVW_PREL_G1,
115 R_AARCH64_MOVW_PREL_G1_NC,
116 R_AARCH64_MOVW_PREL_G2,
117 R_AARCH64_MOVW_PREL_G2_NC,
118 R_AARCH64_MOVW_PREL_G3,
119 R_AARCH64_LDST128_ABS_LO12_NC,
120 R_AARCH64_MOVW_GOTOFF_G0,
121 R_AARCH64_MOVW_GOTOFF_G0_NC,
122 R_AARCH64_MOVW_GOTOFF_G1,
123 R_AARCH64_MOVW_GOTOFF_G1_NC,
124 R_AARCH64_MOVW_GOTOFF_G2,
125 R_AARCH64_MOVW_GOTOFF_G2_NC,
126 R_AARCH64_MOVW_GOTOFF_G3,
127 R_AARCH64_GOTREL64,
128 R_AARCH64_GOTREL32,
129 R_AARCH64_GOT_LD_PREL19,
130 R_AARCH64_LD64_GOTOFF_LO15,
131 R_AARCH64_ADR_GOT_PAGE,
132 R_AARCH64_LD64_GOT_LO12_NC,
133 R_AARCH64_LD64_GOTPAGE_LO15,
134 R_AARCH64_TLSGD_ADR_PREL21,
135 R_AARCH64_TLSGD_ADR_PAGE21,
136 R_AARCH64_TLSGD_ADD_LO12_NC,
137 R_AARCH64_TLSGD_MOVW_G1,
138 R_AARCH64_TLSGD_MOVW_G0_NC,
139 R_AARCH64_TLSLD_ADR_PREL21,
140 R_AARCH64_TLSLD_ADR_PAGE21,
141 R_AARCH64_TLSLD_ADD_LO12_NC,
142 R_AARCH64_TLSLD_MOVW_G1,
143 R_AARCH64_TLSLD_MOVW_G0_NC,
144 R_AARCH64_TLSLD_LD_PREL19,
145 R_AARCH64_TLSLD_MOVW_DTPREL_G2,
146 R_AARCH64_TLSLD_MOVW_DTPREL_G1,
147 R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC,
148 R_AARCH64_TLSLD_MOVW_DTPREL_G0,
149 R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC,
150 R_AARCH64_TLSLD_ADD_DTPREL_HI12,
151 R_AARCH64_TLSLD_ADD_DTPREL_LO12,
152 R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC,
153 R_AARCH64_TLSLD_LDST8_DTPREL_LO12,
154 R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC,
155 R_AARCH64_TLSLD_LDST16_DTPREL_LO12,
156 R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC,
157 R_AARCH64_TLSLD_LDST32_DTPREL_LO12,
158 R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC,
159 R_AARCH64_TLSLD_LDST64_DTPREL_LO12,
160 R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC,
161 R_AARCH64_TLSIE_MOVW_GOTTPREL_G1,
162 R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC,
163 R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21,
164 R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC,
165 R_AARCH64_TLSIE_LD_GOTTPREL_PREL19,
166 R_AARCH64_TLSLE_MOVW_TPREL_G2,
167 R_AARCH64_TLSLE_MOVW_TPREL_G1,
168 R_AARCH64_TLSLE_MOVW_TPREL_G1_NC,
169 R_AARCH64_TLSLE_MOVW_TPREL_G0,
170 R_AARCH64_TLSLE_MOVW_TPREL_G0_NC,
171 R_AARCH64_TLSLE_ADD_TPREL_HI12,
172 R_AARCH64_TLSLE_ADD_TPREL_LO12,
173 R_AARCH64_TLSLE_ADD_TPREL_LO12_NC,
174 R_AARCH64_TLSLE_LDST8_TPREL_LO12,
175 R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC,
176 R_AARCH64_TLSLE_LDST16_TPREL_LO12,
177 R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC,
178 R_AARCH64_TLSLE_LDST32_TPREL_LO12,
179 R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC,
180 R_AARCH64_TLSLE_LDST64_TPREL_LO12,
181 R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC,
182 R_AARCH64_TLSDESC_LD_PREL19,
183 R_AARCH64_TLSDESC_ADR_PREL21,
184 R_AARCH64_TLSDESC_ADR_PAGE21,
185 R_AARCH64_TLSDESC_LD64_LO12,
186 R_AARCH64_TLSDESC_ADD_LO12,
187 R_AARCH64_TLSDESC_OFF_G1,
188 R_AARCH64_TLSDESC_OFF_G0_NC,
189 R_AARCH64_TLSDESC_LDR,
190 R_AARCH64_TLSDESC_ADD,
191 R_AARCH64_TLSDESC_CALL,
192 R_AARCH64_TLSLE_LDST128_TPREL_LO12,
193 R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC,
194 R_AARCH64_TLSLD_LDST128_DTPREL_LO12,
195 R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC,
196 R_AARCH64_COPY,
197 R_AARCH64_GLOB_DAT,
198 R_AARCH64_JUMP_SLOT,
199 R_AARCH64_RELATIVE,
200 R_AARCH64_TLS_DTPMOD,
201 R_AARCH64_TLS_DTPREL,
202 R_AARCH64_TLS_TPREL,
203 R_AARCH64_TLSDESC,
204 R_AARCH64_IRELATIVE
205 ] {
206 Cow::Borrowed(name)
207 } else {
208 Cow::Owned(format!("Unknown aarch64 relocation type 0x{r_type:x}"))
209 }
210}
211
212#[must_use]
213pub fn segment_type_to_string(p_type: u32) -> Cow<'static, str> {
214 if let Some(name) = const_name_by_value![
215 p_type,
216 PT_NULL,
217 PT_LOAD,
218 PT_DYNAMIC,
219 PT_INTERP,
220 PT_NOTE,
221 PT_SHLIB,
222 PT_PHDR,
223 PT_TLS,
224 PT_GNU_EH_FRAME,
225 PT_GNU_STACK,
226 PT_GNU_RELRO,
227 PT_GNU_PROPERTY
228 ] {
229 Cow::Borrowed(name)
230 } else {
231 Cow::Owned(format!("UNKNOWN_P_TYPE_{p_type}"))
232 }
233}
234
235pub mod shf {
237 use super::SectionFlags;
238
239 pub const WRITE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_WRITE);
240 pub const ALLOC: SectionFlags = SectionFlags::from_u32(object::elf::SHF_ALLOC);
241 pub const EXECINSTR: SectionFlags = SectionFlags::from_u32(object::elf::SHF_EXECINSTR);
242 pub const MERGE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_MERGE);
243 pub const STRINGS: SectionFlags = SectionFlags::from_u32(object::elf::SHF_STRINGS);
244 pub const INFO_LINK: SectionFlags = SectionFlags::from_u32(object::elf::SHF_INFO_LINK);
245 pub const LINK_ORDER: SectionFlags = SectionFlags::from_u32(object::elf::SHF_LINK_ORDER);
246 pub const OS_NONCONFORMING: SectionFlags =
247 SectionFlags::from_u32(object::elf::SHF_OS_NONCONFORMING);
248 pub const GROUP: SectionFlags = SectionFlags::from_u32(object::elf::SHF_GROUP);
249 pub const TLS: SectionFlags = SectionFlags::from_u32(object::elf::SHF_TLS);
250 pub const COMPRESSED: SectionFlags = SectionFlags::from_u32(object::elf::SHF_COMPRESSED);
251 pub const GNU_RETAIN: SectionFlags = SectionFlags::from_u32(object::elf::SHF_GNU_RETAIN);
252}
253
254pub mod sht {
255 use super::SectionType;
256
257 pub const NULL: SectionType = SectionType(object::elf::SHT_NULL);
258 pub const PROGBITS: SectionType = SectionType(object::elf::SHT_PROGBITS);
259 pub const SYMTAB: SectionType = SectionType(object::elf::SHT_SYMTAB);
260 pub const STRTAB: SectionType = SectionType(object::elf::SHT_STRTAB);
261 pub const RELA: SectionType = SectionType(object::elf::SHT_RELA);
262 pub const HASH: SectionType = SectionType(object::elf::SHT_HASH);
263 pub const DYNAMIC: SectionType = SectionType(object::elf::SHT_DYNAMIC);
264 pub const NOTE: SectionType = SectionType(object::elf::SHT_NOTE);
265 pub const NOBITS: SectionType = SectionType(object::elf::SHT_NOBITS);
266 pub const REL: SectionType = SectionType(object::elf::SHT_REL);
267 pub const SHLIB: SectionType = SectionType(object::elf::SHT_SHLIB);
268 pub const DYNSYM: SectionType = SectionType(object::elf::SHT_DYNSYM);
269 pub const INIT_ARRAY: SectionType = SectionType(object::elf::SHT_INIT_ARRAY);
270 pub const FINI_ARRAY: SectionType = SectionType(object::elf::SHT_FINI_ARRAY);
271 pub const PREINIT_ARRAY: SectionType = SectionType(object::elf::SHT_PREINIT_ARRAY);
272 pub const GROUP: SectionType = SectionType(object::elf::SHT_GROUP);
273 pub const SYMTAB_SHNDX: SectionType = SectionType(object::elf::SHT_SYMTAB_SHNDX);
274 pub const LOOS: SectionType = SectionType(object::elf::SHT_LOOS);
275 pub const GNU_ATTRIBUTES: SectionType = SectionType(object::elf::SHT_GNU_ATTRIBUTES);
276 pub const GNU_HASH: SectionType = SectionType(object::elf::SHT_GNU_HASH);
277 pub const GNU_LIBLIST: SectionType = SectionType(object::elf::SHT_GNU_LIBLIST);
278 pub const CHECKSUM: SectionType = SectionType(object::elf::SHT_CHECKSUM);
279 pub const LOSUNW: SectionType = SectionType(object::elf::SHT_LOSUNW);
280 pub const SUNW_COMDAT: SectionType = SectionType(object::elf::SHT_SUNW_COMDAT);
281 pub const SUNW_SYMINFO: SectionType = SectionType(object::elf::SHT_SUNW_syminfo);
282 pub const GNU_VERDEF: SectionType = SectionType(object::elf::SHT_GNU_VERDEF);
283 pub const GNU_VERNEED: SectionType = SectionType(object::elf::SHT_GNU_VERNEED);
284 pub const GNU_VERSYM: SectionType = SectionType(object::elf::SHT_GNU_VERSYM);
285 pub const HISUNW: SectionType = SectionType(object::elf::SHT_HISUNW);
286 pub const HIOS: SectionType = SectionType(object::elf::SHT_HIOS);
287 pub const LOPROC: SectionType = SectionType(object::elf::SHT_LOPROC);
288 pub const HIPROC: SectionType = SectionType(object::elf::SHT_HIPROC);
289 pub const LOUSER: SectionType = SectionType(object::elf::SHT_LOUSER);
290 pub const HIUSER: SectionType = SectionType(object::elf::SHT_HIUSER);
291}
292
293#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
294pub struct SectionFlags(u32);
295
296impl SectionFlags {
297 #[must_use]
298 pub const fn empty() -> Self {
299 Self(0)
300 }
301
302 #[must_use]
303 pub fn from_header(header: &object::elf::SectionHeader64<LittleEndian>) -> Self {
304 Self(header.sh_flags(LittleEndian) as u32)
305 }
306
307 #[must_use]
308 pub fn contains(self, flag: SectionFlags) -> bool {
309 self.0 & flag.0 != 0
310 }
311
312 #[must_use]
313 pub const fn from_u32(raw: u32) -> SectionFlags {
314 SectionFlags(raw)
315 }
316
317 #[must_use]
319 pub const fn with(self, flags: SectionFlags) -> SectionFlags {
320 SectionFlags(self.0 | flags.0)
321 }
322
323 #[must_use]
325 pub const fn without(self, flags: SectionFlags) -> SectionFlags {
326 SectionFlags(self.0 & !flags.0)
327 }
328
329 #[must_use]
330 pub const fn raw(self) -> u64 {
331 self.0 as u64
332 }
333
334 #[must_use]
335 pub fn should_retain(&self) -> bool {
336 self.contains(shf::GNU_RETAIN)
337 }
338}
339
340impl From<u64> for SectionFlags {
341 fn from(value: u64) -> Self {
342 Self(value as u32)
343 }
344}
345
346impl std::fmt::Display for SectionFlags {
347 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
348 if self.contains(shf::WRITE) {
349 f.write_str("W")?;
350 }
351 if self.contains(shf::ALLOC) {
352 f.write_str("A")?;
353 }
354 if self.contains(shf::EXECINSTR) {
355 f.write_str("X")?;
356 }
357 if self.contains(shf::MERGE) {
358 f.write_str("M")?;
359 }
360 if self.contains(shf::STRINGS) {
361 f.write_str("S")?;
362 }
363 if self.contains(shf::INFO_LINK) {
364 f.write_str("I")?;
365 }
366 if self.contains(shf::LINK_ORDER) {
367 f.write_str("L")?;
368 }
369 if self.contains(shf::OS_NONCONFORMING) {
370 f.write_str("O")?;
371 }
372 if self.contains(shf::GROUP) {
373 f.write_str("G")?;
374 }
375 if self.contains(shf::TLS) {
376 f.write_str("T")?;
377 }
378 if self.contains(shf::COMPRESSED) {
379 f.write_str("C")?;
380 }
381 Ok(())
382 }
383}
384
385impl std::fmt::Debug for SectionFlags {
386 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
387 std::fmt::Display::fmt(&self, f)
388 }
389}
390
391impl std::ops::BitOrAssign for SectionFlags {
392 fn bitor_assign(&mut self, rhs: Self) {
393 self.0 |= rhs.0;
394 }
395}
396
397impl std::ops::BitAnd for SectionFlags {
398 type Output = SectionFlags;
399
400 fn bitand(self, rhs: Self) -> Self::Output {
401 Self(self.0 & rhs.0)
402 }
403}
404
405#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
406pub struct SectionType(u32);
407
408impl SectionType {
409 #[must_use]
410 pub fn raw(self) -> u32 {
411 self.0
412 }
413
414 #[must_use]
415 pub fn from_header(header: &object::elf::SectionHeader64<LittleEndian>) -> Self {
416 Self(header.sh_type(LittleEndian))
417 }
418
419 #[must_use]
420 pub fn from_u32(raw: u32) -> Self {
421 Self(raw)
422 }
423}
424
425pub mod secnames {
426 pub const FILEHEADER_SECTION_NAME_STR: &str = "";
427 pub const FILEHEADER_SECTION_NAME: &[u8] = FILEHEADER_SECTION_NAME_STR.as_bytes();
428 pub const RODATA_SECTION_NAME_STR: &str = ".rodata";
429 pub const RODATA_SECTION_NAME: &[u8] = RODATA_SECTION_NAME_STR.as_bytes();
430 pub const TEXT_SECTION_NAME_STR: &str = ".text";
431 pub const TEXT_SECTION_NAME: &[u8] = TEXT_SECTION_NAME_STR.as_bytes();
432 pub const INIT_ARRAY_SECTION_NAME_STR: &str = ".init_array";
433 pub const INIT_ARRAY_SECTION_NAME: &[u8] = INIT_ARRAY_SECTION_NAME_STR.as_bytes();
434 pub const FINI_ARRAY_SECTION_NAME_STR: &str = ".fini_array";
435 pub const FINI_ARRAY_SECTION_NAME: &[u8] = FINI_ARRAY_SECTION_NAME_STR.as_bytes();
436 pub const PREINIT_ARRAY_SECTION_NAME_STR: &str = ".preinit_array";
437 pub const PREINIT_ARRAY_SECTION_NAME: &[u8] = PREINIT_ARRAY_SECTION_NAME_STR.as_bytes();
438 pub const DATA_SECTION_NAME_STR: &str = ".data";
439 pub const DATA_SECTION_NAME: &[u8] = DATA_SECTION_NAME_STR.as_bytes();
440 pub const EH_FRAME_SECTION_NAME_STR: &str = ".eh_frame";
441 pub const EH_FRAME_SECTION_NAME: &[u8] = EH_FRAME_SECTION_NAME_STR.as_bytes();
442 pub const EH_FRAME_HDR_SECTION_NAME_STR: &str = ".eh_frame_hdr";
443 pub const EH_FRAME_HDR_SECTION_NAME: &[u8] = EH_FRAME_HDR_SECTION_NAME_STR.as_bytes();
444 pub const SHSTRTAB_SECTION_NAME_STR: &str = ".shstrtab";
445 pub const SHSTRTAB_SECTION_NAME: &[u8] = SHSTRTAB_SECTION_NAME_STR.as_bytes();
446 pub const SYMTAB_SECTION_NAME_STR: &str = ".symtab";
447 pub const SYMTAB_SECTION_NAME: &[u8] = SYMTAB_SECTION_NAME_STR.as_bytes();
448 pub const STRTAB_SECTION_NAME_STR: &str = ".strtab";
449 pub const STRTAB_SECTION_NAME: &[u8] = STRTAB_SECTION_NAME_STR.as_bytes();
450 pub const TDATA_SECTION_NAME_STR: &str = ".tdata";
451 pub const TDATA_SECTION_NAME: &[u8] = TDATA_SECTION_NAME_STR.as_bytes();
452 pub const TBSS_SECTION_NAME_STR: &str = ".tbss";
453 pub const TBSS_SECTION_NAME: &[u8] = TBSS_SECTION_NAME_STR.as_bytes();
454 pub const BSS_SECTION_NAME_STR: &str = ".bss";
455 pub const BSS_SECTION_NAME: &[u8] = BSS_SECTION_NAME_STR.as_bytes();
456 pub const GOT_SECTION_NAME_STR: &str = ".got";
457 pub const GOT_SECTION_NAME: &[u8] = GOT_SECTION_NAME_STR.as_bytes();
458 pub const INIT_SECTION_NAME_STR: &str = ".init";
459 pub const INIT_SECTION_NAME: &[u8] = INIT_SECTION_NAME_STR.as_bytes();
460 pub const FINI_SECTION_NAME_STR: &str = ".fini";
461 pub const FINI_SECTION_NAME: &[u8] = FINI_SECTION_NAME_STR.as_bytes();
462 pub const RELA_PLT_SECTION_NAME_STR: &str = ".rela.plt";
463 pub const RELA_PLT_SECTION_NAME: &[u8] = RELA_PLT_SECTION_NAME_STR.as_bytes();
464 pub const COMMENT_SECTION_NAME_STR: &str = ".comment";
465 pub const COMMENT_SECTION_NAME: &[u8] = COMMENT_SECTION_NAME_STR.as_bytes();
466 pub const DYNAMIC_SECTION_NAME_STR: &str = ".dynamic";
467 pub const DYNAMIC_SECTION_NAME: &[u8] = DYNAMIC_SECTION_NAME_STR.as_bytes();
468 pub const DYNSYM_SECTION_NAME_STR: &str = ".dynsym";
469 pub const DYNSYM_SECTION_NAME: &[u8] = DYNSYM_SECTION_NAME_STR.as_bytes();
470 pub const DYNSTR_SECTION_NAME_STR: &str = ".dynstr";
471 pub const DYNSTR_SECTION_NAME: &[u8] = DYNSTR_SECTION_NAME_STR.as_bytes();
472 pub const RELA_DYN_SECTION_NAME_STR: &str = ".rela.dyn";
473 pub const RELA_DYN_SECTION_NAME: &[u8] = RELA_DYN_SECTION_NAME_STR.as_bytes();
474 pub const GCC_EXCEPT_TABLE_SECTION_NAME_STR: &str = ".gcc_except_table";
475 pub const GCC_EXCEPT_TABLE_SECTION_NAME: &[u8] = GCC_EXCEPT_TABLE_SECTION_NAME_STR.as_bytes();
476 pub const INTERP_SECTION_NAME_STR: &str = ".interp";
477 pub const INTERP_SECTION_NAME: &[u8] = INTERP_SECTION_NAME_STR.as_bytes();
478 pub const GNU_VERSION_SECTION_NAME_STR: &str = ".gnu.version";
479 pub const GNU_VERSION_SECTION_NAME: &[u8] = GNU_VERSION_SECTION_NAME_STR.as_bytes();
480 pub const GNU_VERSION_D_SECTION_NAME_STR: &str = ".gnu.version_d";
481 pub const GNU_VERSION_D_SECTION_NAME: &[u8] = GNU_VERSION_D_SECTION_NAME_STR.as_bytes();
482 pub const GNU_VERSION_R_SECTION_NAME_STR: &str = ".gnu.version_r";
483 pub const GNU_VERSION_R_SECTION_NAME: &[u8] = GNU_VERSION_R_SECTION_NAME_STR.as_bytes();
484 pub const PROGRAM_HEADERS_SECTION_NAME_STR: &str = ".phdr";
485 pub const PROGRAM_HEADERS_SECTION_NAME: &[u8] = PROGRAM_HEADERS_SECTION_NAME_STR.as_bytes();
486 pub const SECTION_HEADERS_SECTION_NAME_STR: &str = ".shdr";
487 pub const SECTION_HEADERS_SECTION_NAME: &[u8] = SECTION_HEADERS_SECTION_NAME_STR.as_bytes();
488 pub const GNU_HASH_SECTION_NAME_STR: &str = ".gnu.hash";
489 pub const GNU_HASH_SECTION_NAME: &[u8] = GNU_HASH_SECTION_NAME_STR.as_bytes();
490 pub const PLT_SECTION_NAME_STR: &str = ".plt";
491 pub const PLT_SECTION_NAME: &[u8] = PLT_SECTION_NAME_STR.as_bytes();
492 pub const IPLT_SECTION_NAME_STR: &str = ".iplt";
493 pub const IPLT_SECTION_NAME: &[u8] = IPLT_SECTION_NAME_STR.as_bytes();
494 pub const PLT_GOT_SECTION_NAME_STR: &str = ".plt.got";
495 pub const PLT_GOT_SECTION_NAME: &[u8] = PLT_GOT_SECTION_NAME_STR.as_bytes();
496 pub const GOT_PLT_SECTION_NAME_STR: &str = ".got.plt";
497 pub const GOT_PLT_SECTION_NAME: &[u8] = GOT_PLT_SECTION_NAME_STR.as_bytes();
498 pub const PLT_SEC_SECTION_NAME_STR: &str = ".plt.sec";
499 pub const PLT_SEC_SECTION_NAME: &[u8] = PLT_SEC_SECTION_NAME_STR.as_bytes();
500 pub const NOTE_ABI_TAG_SECTION_NAME_STR: &str = ".note.ABI-tag";
501 pub const NOTE_ABI_TAG_SECTION_NAME: &[u8] = NOTE_ABI_TAG_SECTION_NAME_STR.as_bytes();
502 pub const NOTE_GNU_PROPERTY_SECTION_NAME_STR: &str = ".note.gnu.property";
503 pub const NOTE_GNU_PROPERTY_SECTION_NAME: &[u8] = NOTE_GNU_PROPERTY_SECTION_NAME_STR.as_bytes();
504 pub const NOTE_GNU_BUILD_ID_SECTION_NAME_STR: &str = ".note.gnu.build-id";
505 pub const NOTE_GNU_BUILD_ID_SECTION_NAME: &[u8] = NOTE_GNU_BUILD_ID_SECTION_NAME_STR.as_bytes();
506 pub const DEBUG_LOC_SECTION_NAME_STR: &str = ".debug_loc";
507 pub const DEBUG_LOC_SECTION_NAME: &[u8] = DEBUG_LOC_SECTION_NAME_STR.as_bytes();
508 pub const DEBUG_RANGES_SECTION_NAME_STR: &str = ".debug_ranges";
509 pub const DEBUG_RANGES_SECTION_NAME: &[u8] = DEBUG_RANGES_SECTION_NAME_STR.as_bytes();
510 pub const GROUP_SECTION_NAME_STR: &str = ".group";
511 pub const GROUP_SECTION_NAME: &[u8] = GROUP_SECTION_NAME_STR.as_bytes();
512 pub const DATA_REL_RO_SECTION_NAME_STR: &str = ".data.rel.ro";
513 pub const DATA_REL_RO_SECTION_NAME: &[u8] = DATA_REL_RO_SECTION_NAME_STR.as_bytes();
514}
515
516#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
517pub struct SegmentType(u32);
518
519impl SegmentType {
520 #[must_use]
521 pub fn raw(self) -> u32 {
522 self.0
523 }
524
525 #[must_use]
526 pub fn from_header(header: &object::elf::ProgramHeader64<LittleEndian>) -> Self {
527 Self(header.p_type(LittleEndian))
528 }
529
530 #[must_use]
531 pub const fn from_u32(raw: u32) -> Self {
532 Self(raw)
533 }
534}
535
536impl std::fmt::Display for SegmentType {
537 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
538 match *self {
539 pt::PHDR => write!(f, "PHDR")?,
540 pt::INTERP => write!(f, "INTERP")?,
541 pt::NOTE => write!(f, "NOTE")?,
542 pt::LOAD => write!(f, "LOAD")?,
543 pt::TLS => write!(f, "TLS")?,
544 pt::GNU_EH_FRAME => write!(f, "GNU_EH_FRAME")?,
545 pt::DYNAMIC => write!(f, "DYNAMIC")?,
546 pt::GNU_RELRO => write!(f, "GNU_RELRO")?,
547 pt::GNU_STACK => write!(f, "GNU_STACK")?,
548 other => write!(f, "UNKNOWN_SEG_TYPE({})", other.raw())?,
549 }
550 Ok(())
551 }
552}
553
554pub mod pt {
555 use super::SegmentType;
556
557 pub const PHDR: SegmentType = SegmentType::from_u32(object::elf::PT_PHDR);
558 pub const INTERP: SegmentType = SegmentType::from_u32(object::elf::PT_INTERP);
559 pub const NOTE: SegmentType = SegmentType::from_u32(object::elf::PT_NOTE);
560 pub const LOAD: SegmentType = SegmentType::from_u32(object::elf::PT_LOAD);
561 pub const TLS: SegmentType = SegmentType::from_u32(object::elf::PT_TLS);
562 pub const GNU_EH_FRAME: SegmentType = SegmentType::from_u32(object::elf::PT_GNU_EH_FRAME);
563 pub const DYNAMIC: SegmentType = SegmentType::from_u32(object::elf::PT_DYNAMIC);
564 pub const GNU_RELRO: SegmentType = SegmentType::from_u32(object::elf::PT_GNU_RELRO);
565 pub const GNU_STACK: SegmentType = SegmentType::from_u32(object::elf::PT_GNU_STACK);
566}
567
568#[derive(Clone, Copy, PartialEq, Eq)]
569pub struct SegmentFlags(u32);
570
571impl SegmentFlags {
572 #[must_use]
573 pub const fn empty() -> Self {
574 Self(0)
575 }
576
577 #[must_use]
578 pub fn from_header(header: &object::elf::ProgramHeader64<LittleEndian>) -> Self {
579 Self(header.p_flags(LittleEndian))
580 }
581
582 #[must_use]
583 pub fn contains(self, flag: SegmentFlags) -> bool {
584 self.0 & flag.0 != 0
585 }
586
587 #[must_use]
588 pub const fn from_u32(raw: u32) -> SegmentFlags {
589 SegmentFlags(raw)
590 }
591
592 #[must_use]
594 pub const fn with(self, flags: SegmentFlags) -> SegmentFlags {
595 SegmentFlags(self.0 | flags.0)
596 }
597
598 #[must_use]
600 pub const fn without(self, flags: SegmentFlags) -> SegmentFlags {
601 SegmentFlags(self.0 & !flags.0)
602 }
603
604 #[must_use]
605 pub const fn raw(self) -> u32 {
606 self.0
607 }
608}
609
610pub mod pf {
611 use super::SegmentFlags;
612
613 pub const EXECUTABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_X);
614 pub const WRITABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_W);
615 pub const READABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_R);
616}
617
618impl std::fmt::Display for SegmentFlags {
619 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
620 if self.contains(pf::WRITABLE) {
621 f.write_str("W")?;
622 }
623 if self.contains(pf::READABLE) {
624 f.write_str("R")?;
625 }
626 if self.contains(pf::EXECUTABLE) {
627 f.write_str("X")?;
628 }
629 Ok(())
630 }
631}
632
633impl std::fmt::Debug for SegmentFlags {
634 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
635 std::fmt::Display::fmt(&self, f)
636 }
637}
638
639impl std::ops::BitOrAssign for SegmentFlags {
640 fn bitor_assign(&mut self, rhs: Self) {
641 self.0 |= rhs.0;
642 }
643}
644
645impl std::ops::BitAnd for SegmentFlags {
646 type Output = SegmentFlags;
647
648 fn bitand(self, rhs: Self) -> Self::Output {
649 Self(self.0 & rhs.0)
650 }
651}
652
653#[derive(Clone, Copy, Debug, PartialEq, Eq)]
657pub enum RelocationKind {
658 Absolute,
660
661 AbsoluteAArch64,
664
665 Relative,
667
668 SymRelGotBase,
670
671 GotRelGotBase,
673
674 Got,
676
677 PltRelGotBase,
679
680 PltRelative,
682
683 GotRelative,
685
686 TlsGd,
690
691 TlsGdGot,
693
694 TlsGdGotBase,
696
697 TlsLd,
701
702 TlsLdGot,
704
705 TlsLdGotBase,
708
709 DtpOff,
711
712 GotTpOff,
715
716 GotTpOffGot,
719
720 GotTpOffGotBase,
723
724 TpOff,
726
727 TpOffAArch64,
729
730 TlsDesc,
732
733 TlsDescGot,
735
736 TlsDescGotBase,
738
739 TlsDescCall,
741
742 None,
745}
746
747impl RelocationKind {
748 #[must_use]
749 pub fn is_tls(self) -> bool {
750 matches!(
751 self,
752 Self::DtpOff
753 | Self::GotTpOff
754 | Self::GotTpOffGotBase
755 | Self::TlsDesc
756 | Self::TlsDescCall
757 | Self::TlsDescGot
758 | Self::TlsDescGotBase
759 | Self::TlsGd
760 | Self::TlsGdGot
761 | Self::TlsGdGotBase
762 | Self::TlsLd
763 | Self::TlsLdGot
764 | Self::TlsLdGotBase
765 | Self::TpOffAArch64
766 )
767 }
768}
769
770#[derive(Copy, Clone, Debug, PartialEq, Eq)]
771pub enum DynamicRelocationKind {
772 Copy,
773 Irelative,
774 DtpMod,
775 DtpOff,
776 TlsDesc,
777 TpOff,
778 Relative,
779 Absolute,
780 GotEntry,
781 JumpSlot,
782}
783
784impl DynamicRelocationKind {
785 #[must_use]
786 pub fn from_x86_64_r_type(r_type: u32) -> Option<Self> {
787 let kind = match r_type {
788 object::elf::R_X86_64_COPY => DynamicRelocationKind::Copy,
789 object::elf::R_X86_64_IRELATIVE => DynamicRelocationKind::Irelative,
790 object::elf::R_X86_64_DTPMOD64 => DynamicRelocationKind::DtpMod,
791 object::elf::R_X86_64_DTPOFF64 => DynamicRelocationKind::DtpOff,
792 object::elf::R_X86_64_TPOFF64 => DynamicRelocationKind::TpOff,
793 object::elf::R_X86_64_RELATIVE => DynamicRelocationKind::Relative,
794 object::elf::R_X86_64_GLOB_DAT => DynamicRelocationKind::GotEntry,
795 object::elf::R_X86_64_64 => DynamicRelocationKind::Absolute,
796 object::elf::R_X86_64_TLSDESC => DynamicRelocationKind::TlsDesc,
797 object::elf::R_X86_64_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
798 _ => return None,
799 };
800
801 Some(kind)
802 }
803
804 #[must_use]
805 pub fn x86_64_r_type(self) -> u32 {
806 match self {
807 DynamicRelocationKind::Copy => object::elf::R_X86_64_COPY,
808 DynamicRelocationKind::Irelative => object::elf::R_X86_64_IRELATIVE,
809 DynamicRelocationKind::DtpMod => object::elf::R_X86_64_DTPMOD64,
810 DynamicRelocationKind::DtpOff => object::elf::R_X86_64_DTPOFF64,
811 DynamicRelocationKind::TpOff => object::elf::R_X86_64_TPOFF64,
812 DynamicRelocationKind::Relative => object::elf::R_X86_64_RELATIVE,
813 DynamicRelocationKind::Absolute => object::elf::R_X86_64_64,
814 DynamicRelocationKind::GotEntry => object::elf::R_X86_64_GLOB_DAT,
815 DynamicRelocationKind::TlsDesc => object::elf::R_X86_64_TLSDESC,
816 DynamicRelocationKind::JumpSlot => object::elf::R_X86_64_JUMP_SLOT,
817 }
818 }
819
820 #[must_use]
821 pub fn from_aarch64_r_type(r_type: u32) -> Option<Self> {
822 let kind = match r_type {
823 object::elf::R_AARCH64_COPY => DynamicRelocationKind::Copy,
824 object::elf::R_AARCH64_IRELATIVE => DynamicRelocationKind::Irelative,
825 object::elf::R_AARCH64_TLS_DTPMOD => DynamicRelocationKind::DtpMod,
826 object::elf::R_AARCH64_TLS_DTPREL => DynamicRelocationKind::DtpOff,
827 object::elf::R_AARCH64_TLS_TPREL => DynamicRelocationKind::TpOff,
828 object::elf::R_AARCH64_RELATIVE => DynamicRelocationKind::Relative,
829 object::elf::R_AARCH64_ABS64 => DynamicRelocationKind::Absolute,
830 object::elf::R_AARCH64_GLOB_DAT => DynamicRelocationKind::GotEntry,
831 object::elf::R_AARCH64_TLSDESC => DynamicRelocationKind::TlsDesc,
832 object::elf::R_AARCH64_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
833 _ => return None,
834 };
835
836 Some(kind)
837 }
838
839 #[must_use]
840 pub fn aarch64_r_type(&self) -> u32 {
841 match self {
842 DynamicRelocationKind::Copy => object::elf::R_AARCH64_COPY,
843 DynamicRelocationKind::Irelative => object::elf::R_AARCH64_IRELATIVE,
844 DynamicRelocationKind::DtpMod => object::elf::R_AARCH64_TLS_DTPMOD,
845 DynamicRelocationKind::DtpOff => object::elf::R_AARCH64_TLS_DTPREL,
846 DynamicRelocationKind::TpOff => object::elf::R_AARCH64_TLS_TPREL,
847 DynamicRelocationKind::Relative => object::elf::R_AARCH64_RELATIVE,
848 DynamicRelocationKind::Absolute => object::elf::R_AARCH64_ABS64,
849 DynamicRelocationKind::GotEntry => object::elf::R_AARCH64_GLOB_DAT,
850 DynamicRelocationKind::TlsDesc => object::elf::R_AARCH64_TLSDESC,
851 DynamicRelocationKind::JumpSlot => object::elf::R_AARCH64_JUMP_SLOT,
852 }
853 }
854}
855
856#[derive(Clone, Debug, Copy, PartialEq, Eq)]
858pub struct BitRange {
859 pub start: u32,
860 pub end: u32,
861}
862
863#[derive(Clone, Debug, Copy, PartialEq, Eq)]
864pub enum RelocationInstruction {
865 Adr,
866 Movkz,
867 Movnz,
868 Ldr,
869 LdrRegister,
870 Add,
871 LdSt,
872 TstBr,
873 Bcond,
874 JumpCall,
875}
876
877impl RelocationInstruction {
878 #[must_use]
879 pub fn bit_mask(&self, range: BitRange) -> [u8; 4] {
880 let mut mask = [0; 4];
881
882 let all_ones = (1 << (range.end - range.start)) - 1;
885 self.write_to_value(all_ones, false, &mut mask);
886
887 for b in &mut mask {
889 *b = !*b;
890 }
891
892 mask
893 }
894}
895
896#[derive(Clone, Debug, Copy, PartialEq, Eq)]
897pub enum RelocationSize {
898 ByteSize(usize),
899 BitMasking(BitMask),
900}
901
902impl RelocationSize {
903 pub(crate) const fn bit_mask(
904 bit_start: u32,
905 bit_end: u32,
906 instruction: RelocationInstruction,
907 ) -> RelocationSize {
908 Self::BitMasking(BitMask::new(instruction, bit_start, bit_end))
909 }
910}
911
912#[derive(Clone, Debug, Copy, PartialEq, Eq)]
913pub struct BitMask {
914 pub instruction: RelocationInstruction,
915 pub range: BitRange,
916}
917
918#[derive(Debug, Clone, Copy)]
919pub enum PageMask {
920 SymbolPlusAddendAndPosition,
921 GotEntryAndPosition,
922 GotBase,
923}
924
925#[derive(Clone, Debug, Copy)]
927pub struct AllowedRange {
928 pub min: i64,
929 pub max: i64,
930}
931
932impl AllowedRange {
933 #[must_use]
934 pub const fn new(min: i64, max: i64) -> Self {
935 Self { min, max }
936 }
937
938 #[must_use]
939 pub const fn no_check() -> Self {
940 Self::new(i64::MIN, i64::MAX)
941 }
942}
943
944#[derive(Clone, Debug, Copy)]
945pub struct RelocationKindInfo {
946 pub kind: RelocationKind,
947 pub size: RelocationSize,
948 pub mask: Option<PageMask>,
949 pub range: AllowedRange,
950 pub alignment: usize,
951}
952
953impl RelocationKindInfo {
954 #[inline(always)]
955 pub fn verify(&self, value: i64) -> Result<()> {
956 anyhow::ensure!(
957 (value as usize) & (self.alignment - 1) == 0,
958 "Relocation {value} not aligned to {} bytes",
959 self.alignment
960 );
961 anyhow::ensure!(
962 self.range.min <= value && value < self.range.max,
963 format!(
964 "Relocation {value} outside of bounds [{}, {})",
965 self.range.min, self.range.max
966 )
967 );
968 Ok(())
969 }
970}
971
972impl BitMask {
973 #[must_use]
974 pub const fn new(instruction: RelocationInstruction, bit_start: u32, bit_end: u32) -> Self {
975 Self {
976 instruction,
977 range: BitRange {
978 start: bit_start,
979 end: bit_end,
980 },
981 }
982 }
983}
984
985#[must_use]
987pub fn extract_bits(value: u64, start: u32, end: u32) -> u64 {
988 debug_assert!(start < end);
989 (value >> (start)) & ((1 << (end - start)) - 1)
990}
991
992#[cfg(test)]
993mod tests {
994 use super::*;
995 use object::elf::*;
996
997 #[test]
998 fn test_rel_type_to_string() {
999 assert_eq!(
1000 &x86_64_rel_type_to_string(R_X86_64_32),
1001 stringify!(R_X86_64_32)
1002 );
1003 assert_eq!(
1004 &x86_64_rel_type_to_string(R_X86_64_GOTPC32_TLSDESC),
1005 stringify!(R_X86_64_GOTPC32_TLSDESC)
1006 );
1007 assert_eq!(
1008 &x86_64_rel_type_to_string(64),
1009 "Unknown x86_64 relocation type 0x40"
1010 );
1011
1012 assert_eq!(
1013 &aarch64_rel_type_to_string(64),
1014 "Unknown aarch64 relocation type 0x40"
1015 );
1016 }
1017
1018 #[test]
1019 fn test_bit_operations() {
1020 assert_eq!(0b11000, extract_bits(0b1100_0000, 3, 8));
1021 assert_eq!(0b1010_1010_0000, extract_bits(0b10101010_00001111, 4, 16));
1022 assert_eq!(u32::MAX, extract_bits(u64::MAX, 0, 32) as u32);
1023 }
1024
1025 #[test]
1026 #[cfg(debug_assertions)]
1027 #[should_panic]
1028 fn test_extract_bits_wrong_range() {
1029 let _ = extract_bits(0, 2, 1);
1030 }
1031
1032 #[test]
1033 #[cfg(debug_assertions)]
1034 #[should_panic]
1035 fn test_extract_bits_too_large() {
1036 let _ = extract_bits(0, 0, 100);
1037 }
1038}