linker_utils/
elf.rs

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
235/// Section flag bit values.
236pub 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    /// Returns self with the specified flags set.
318    #[must_use]
319    pub const fn with(self, flags: SectionFlags) -> SectionFlags {
320        SectionFlags(self.0 | flags.0)
321    }
322
323    /// Returns self with the specified flags cleared.
324    #[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    /// Returns self with the specified flags set.
593    #[must_use]
594    pub const fn with(self, flags: SegmentFlags) -> SegmentFlags {
595        SegmentFlags(self.0 | flags.0)
596    }
597
598    /// Returns self with the specified flags cleared.
599    #[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/// For additional information on ELF relocation types, see "ELF-64 Object File Format" -
654/// https://uclibc.org/docs/elf-64-gen.pdf. For information on the TLS related relocations, see "ELF
655/// Handling For Thread-Local Storage" - https://www.uclibc.org/docs/tls.pdf.
656#[derive(Clone, Copy, Debug, PartialEq, Eq)]
657pub enum RelocationKind {
658    /// The absolute address of a symbol or section.
659    Absolute,
660
661    /// The absolute address of a symbol or section. We are going to extract only the offset
662    /// within a page, so dynamic relocation creation must be skipped.
663    AbsoluteAArch64,
664
665    /// The address of the symbol, relative to the place of the relocation.
666    Relative,
667
668    /// The address of the symbol, relative to the base address of the GOT.
669    SymRelGotBase,
670
671    /// The offset of the symbol's GOT entry, relative to the start of the GOT.
672    GotRelGotBase,
673
674    /// The address of the symbol's GOT entry.
675    Got,
676
677    /// The address of the symbol's PLT entry, relative to the base address of the GOT.
678    PltRelGotBase,
679
680    /// The address of the symbol's PLT entry, relative to the place of relocation.
681    PltRelative,
682
683    /// The address of the symbol's GOT entry, relative to the place of the relocation.
684    GotRelative,
685
686    /// The address of a TLSGD structure, relative to the place of the relocation. A TLSGD
687    /// (thread-local storage general dynamic) structure is a pair of values containing a module ID
688    /// and the offset within that module's TLS storage.
689    TlsGd,
690
691    /// The address of the symbol's TLSGD GOT entry.
692    TlsGdGot,
693
694    /// The address of the symbol's TLSGD GOT entry, relative to the start of the GOT.
695    TlsGdGotBase,
696
697    /// The address of the TLS module ID for the shared object that we're writing, relative to the
698    /// place of the relocation. This is used when a TLS variable is defined and used within the
699    /// same shared object.
700    TlsLd,
701
702    /// The address of the TLS module ID for the shared object that we're writing.
703    TlsLdGot,
704
705    /// The address of the TLS module ID for the shared object that we're writing,
706    /// relative to the start of the GOT.
707    TlsLdGotBase,
708
709    /// The offset of a thread-local within the TLS storage of DSO that defines that thread-local.
710    DtpOff,
711
712    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
713    /// TLS storage, relative to the place of the relocation.
714    GotTpOff,
715
716    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
717    /// TLS storage.
718    GotTpOffGot,
719
720    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
721    /// TLS storage, relative to the start of the GOT.
722    GotTpOffGotBase,
723
724    /// The offset of a TLS variable within the executable's TLS storage.
725    TpOff,
726
727    /// The offset of a TLS variable within the executable's TLS storage, AArch64 TLS block layout.
728    TpOffAArch64,
729
730    /// The address of a TLS descriptor structure, relative to the place of the relocation.
731    TlsDesc,
732
733    /// The address of a TLS descriptor structure.
734    TlsDescGot,
735
736    /// The address of a TLS descriptor structure, relative to the start of the GOT.
737    TlsDescGotBase,
738
739    /// Call to the TLS descriptor trampoline. Used only as a placeholder for a linker relaxation opportunity.
740    TlsDescCall,
741
742    /// No relocation needs to be applied. Produced when we eliminate a relocation due to an
743    /// optimisation.
744    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// Half-opened range bounded inclusively below and exclusively above: [`start`, `end`)
857#[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        // To figure out which bits are part of the relocation, we write a value with
883        // all ones into a buffer that initially contains zeros.
884        let all_ones = (1 << (range.end - range.start)) - 1;
885        self.write_to_value(all_ones, false, &mut mask);
886
887        // Wherever we get a 1 is part of the relocation, so invert all bits.
888        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// Allow range (half-open) of a computed value of a relocation
926#[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/// Extract range-specified ([`start`..`end`]) bits from the provided `value`.
986#[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}