linker_utils/
elf.rs

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
29/// Generates newtypes for the non-flag, enum constants exposed by [object].
30/// Each type has automatically generated [Debug] and [Display] implementations.
31/// Constants not (yet) defined by [object] can be given literal values.
32macro_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)] // rustc issues a spurious warning here
53            #[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
442/// Section flag bit values.
443pub 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    /// Returns self with the specified flags set.
487    #[must_use]
488    pub const fn with(self, flags: SectionFlags) -> SectionFlags {
489        SectionFlags(self.0 | flags.0)
490    }
491
492    /// Returns self with the specified flags cleared.
493    #[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            // TODO: ld linker sometimes propagates the flag
536            // (shf::GNU_RETAIN, "R"),
537        ] {
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    /// Returns self with the specified flags set.
686    #[must_use]
687    pub const fn with(self, flags: SegmentFlags) -> SegmentFlags {
688        SegmentFlags(self.0 | flags.0)
689    }
690
691    /// Returns self with the specified flags cleared.
692    #[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
746// RISC-V related constants
747
748/// Dynamic thread vector pointers point 0x800 past the start of each TLS block.
749pub const RISCV_TLS_DTV_OFFSET: u64 = 0x800;
750
751pub const RISCV_ATTRIBUTE_VENDOR_NAME: &str = "riscv";
752
753// RISC-V ELF Tag constants, see: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#risc-v-specific-dynamic-section-tags
754pub mod riscvattr {
755    // Attributes relate to whole file.
756    pub const TAG_RISCV_WHOLE_FILE: u64 = 1;
757    // Indicates the stack alignment requirement in bytes (ULEB128).
758    pub const TAG_RISCV_STACK_ALIGN: u64 = 4;
759    // Indicates the target architecture of this object (NTBS).
760    pub const TAG_RISCV_ARCH: u64 = 5;
761    // Indicates whether to impose unaligned memory accesses in code generation (ULEB128).
762    pub const TAG_RISCV_UNALIGNED_ACCESS: u64 = 6;
763    // Indicates the major version of the privileged specification (ULEB128, deprecated).
764    pub const TAG_RISCV_PRIV_SPEC: u64 = 8;
765    // Indicates the minor version of the privileged specification (ULEB128, deprecated).
766    pub const TAG_RISCV_PRIV_SPEC_MINOR: u64 = 10;
767    // Indicates the revision version of the privileged specification (ULEB128, deprecated).
768    pub const TAG_RISCV_PRIV_SPEC_REVISION: u64 = 12;
769    // Indicates which version of the atomics ABI is being used (ULEB128).
770    pub const TAG_RISCV_ATOMIC_ABI: u64 = 14;
771    // Indicates the usage definition of the X3 register (ULEB128).
772    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/// For additional information on ELF relocation types, see "ELF-64 Object File Format" -
782/// <https://uclibc.org/docs/elf-64-gen.pdf>. For information on the TLS related relocations, see "ELF
783/// Handling For Thread-Local Storage" - <https://www.uclibc.org/docs/tls.pdf>.
784#[derive(Clone, Copy, Debug, PartialEq, Eq)]
785pub enum RelocationKind {
786    /// The absolute address of a symbol or section.
787    Absolute,
788
789    /// The absolute address of a symbol or section related to EH section.
790    AbsoluteSet,
791
792    /// The 6 low bits of an absolute address of a symbol or section.
793    AbsoluteSetWord6,
794
795    /// Add the absolute address of a symbol or section at the place of the relocation
796    /// to the value at the place.
797    AbsoluteAddition,
798
799    /// Subtract the absolute address of a symbol or section at the place of the relocation
800    /// from the value at the place.
801    AbsoluteSubtraction,
802
803    /// Subtract the absolute address of a symbol or section at the place of the relocation
804    /// from the value at the place (use WORD6 type for the operation)
805    AbsoluteSubtractionWord6,
806
807    /// The absolute address of a symbol or section. We are going to extract only the offset
808    /// within a page, so dynamic relocation creation must be skipped.
809    AbsoluteAArch64,
810
811    /// Subtract addresses of two symbols and encode the value using ULEB128.
812    PairSubtraction,
813
814    /// The address of the symbol, relative to the place of the relocation.
815    Relative,
816
817    /// The address of the symbol, relative to the place of the relocation. The address of the relocation
818    /// points to an instruction for which the R_RISCV_PCREL_HI20 relocation is used and that is the place
819    /// we make this relocation relative to.
820    RelativeRiscVLow12,
821
822    /// The address of the symbol, relative to the base address of the GOT.
823    SymRelGotBase,
824
825    /// The offset of the symbol's GOT entry, relative to the start of the GOT.
826    GotRelGotBase,
827
828    /// The address of the symbol's GOT entry.
829    Got,
830
831    /// The address of the symbol's PLT entry, relative to the base address of the GOT.
832    PltRelGotBase,
833
834    /// The address of the symbol's PLT entry, relative to the place of relocation.
835    PltRelative,
836
837    /// The address of the symbol's GOT entry, relative to the place of the relocation.
838    GotRelative,
839
840    /// The address of a TLSGD structure, relative to the place of the relocation. A TLSGD
841    /// (thread-local storage general dynamic) structure is a pair of values containing a module ID
842    /// and the offset within that module's TLS storage.
843    TlsGd,
844
845    /// The address of the symbol's TLSGD GOT entry.
846    TlsGdGot,
847
848    /// The address of the symbol's TLSGD GOT entry, relative to the start of the GOT.
849    TlsGdGotBase,
850
851    /// The address of the TLS module ID for the shared object that we're writing, relative to the
852    /// place of the relocation. This is used when a TLS variable is defined and used within the
853    /// same shared object.
854    TlsLd,
855
856    /// The address of the TLS module ID for the shared object that we're writing.
857    TlsLdGot,
858
859    /// The address of the TLS module ID for the shared object that we're writing,
860    /// relative to the start of the GOT.
861    TlsLdGotBase,
862
863    /// The offset of a thread-local within the TLS storage of DSO that defines that thread-local.
864    DtpOff,
865
866    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
867    /// TLS storage, relative to the place of the relocation.
868    GotTpOff,
869
870    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
871    /// TLS storage.
872    GotTpOffGot,
873
874    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
875    /// TLS storage, relative to the start of the GOT.
876    GotTpOffGotBase,
877
878    /// The offset of a TLS variable within the executable's TLS storage.
879    TpOff,
880
881    /// The address of a TLS descriptor structure, relative to the place of the relocation.
882    TlsDesc,
883
884    /// The address of a TLS descriptor structure.
885    TlsDescGot,
886
887    /// The address of a TLS descriptor structure, relative to the start of the GOT.
888    TlsDescGotBase,
889
890    /// Call to the TLS descriptor trampoline. Used only as a placeholder for a linker relaxation opportunity.
891    TlsDescCall,
892
893    /// No relocation needs to be applied. Produced when we eliminate a relocation due to an
894    /// optimisation.
895    None,
896
897    /// The address must fulfill the alignment requirement.
898    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    // The relocation encoding actually modifies the consecutive pair of instructions:
1060    //   10:	00000097          	auipc	ra,0x0	10: R_RISCV_CALL_PLT	symbol_name
1061    //   14:	000080e7          	jalr	ra # 10 <main+0x10>
1062    //
1063    // That makes the relocation pretty unusual as one would expect 2 relocations:
1064    // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#procedure-calls
1065    UiType,
1066
1067    // Encodes high 20 bits of 32-bit value and encodes the bits to upper part.
1068    UType,
1069
1070    // Encodes low 12 bits of 32-bit value and encodes the bits to upper part.
1071    IType,
1072
1073    // Encodes 12 bits of 32-bit value.
1074    SType,
1075
1076    // The X-type instruction immediate encoding is defined here:
1077    // https://riscv.github.io/riscv-isa-manual/snapshot/unprivileged/#_immediate_encoding_variants
1078
1079    // Specifies a field as the immediate field in a B-type (branch) instruction
1080    BType,
1081
1082    // Specifies a field as the immediate field in a J-type (jump) instruction
1083    JType,
1084
1085    // Specifies a field as the immediate field in a CB-type (compressed branch) instruction
1086    // https://riscv.github.io/riscv-isa-manual/snapshot/unprivileged/#_control_transfer_instructions_2
1087    CbType,
1088
1089    // Specifies a field as the immediate field in a CJ-type (compressed jump) instruction
1090    CjType,
1091
1092    // Encode the value using ULEB128 encoding (the size of the output is variable based on the value)
1093    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        // To figure out which bits are part of the relocation, we write a value with
1108        // all ones into a buffer that initially contains zeros.
1109        let all_ones = (1 << (range.end - range.start)) - 1;
1110        self.write_to_value(all_ones, false, &mut mask);
1111
1112        // Wherever we get a 1 is part of the relocation, so invert all bits.
1113        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    /// The inverse of `write_to_value`. Returns `(extracted_value, negative)`. Supplied `bytes`
1128    /// must be at least 4 bytes, otherwise we panic.
1129    #[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    /// The number of bytes the relocation actually can modify in the output data.
1138    #[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// Allow range (half-open) of a computed value of a relocation
1204#[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    /// Note: for the 8-byte size, we actually do signed checks regardless of the `sign` argument
1223    /// because the `min` and `max` are `i64` type
1224    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        // 8-byte unsigned is also no check because the range cannot be represented in i64
1338        assert_eq!(
1339            AllowedRange::from_byte_size(8, Sign::Unsigned),
1340            AllowedRange::no_check()
1341        );
1342    }
1343}