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,
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#[must_use]
443pub fn loongarch64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
444    if let Some(name) = const_name_by_value![
445        r_type,
446        R_LARCH_32,
447        R_LARCH_64,
448        R_LARCH_B16,
449        R_LARCH_CFA,
450        R_LARCH_B21,
451        R_LARCH_B26,
452        R_LARCH_NONE,
453        R_LARCH_ADD6,
454        R_LARCH_SUB8,
455        R_LARCH_COPY,
456        R_LARCH_ADD8,
457        R_LARCH_SUB6,
458        R_LARCH_ADD16,
459        R_LARCH_ADD64,
460        R_LARCH_SUB32,
461        R_LARCH_ADD24,
462        R_LARCH_ADD32,
463        R_LARCH_SUB16,
464        R_LARCH_SUB24,
465        R_LARCH_SOP_SL,
466        R_LARCH_SOP_SR,
467        R_LARCH_SUB64,
468        R_LARCH_RELAX,
469        R_LARCH_ALIGN,
470        R_LARCH_SOP_SUB,
471        R_LARCH_SOP_ADD,
472        R_LARCH_SOP_AND,
473        R_LARCH_MARK_LA,
474        R_LARCH_CALL36,
475        R_LARCH_SOP_NOT,
476        R_LARCH_DELETE,
477        R_LARCH_GOT_HI20,
478        R_LARCH_GOT_LO12,
479        R_LARCH_32_PCREL,
480        R_LARCH_64_PCREL,
481        R_LARCH_ABS_HI20,
482        R_LARCH_ABS_LO12,
483        R_LARCH_JUMP_SLOT,
484        R_LARCH_RELATIVE,
485        R_LARCH_PCREL20_S2,
486        R_LARCH_ABS64_HI12,
487        R_LARCH_ABS64_LO20,
488        R_LARCH_TLS_LD_HI20,
489        R_LARCH_GOT64_HI12,
490        R_LARCH_GOT64_LO20,
491        R_LARCH_TLS_LE_LO12,
492        R_LARCH_GOT_PC_LO12,
493        R_LARCH_TLS_LE_ADD_R,
494        R_LARCH_SOP_POP_32_U,
495        R_LARCH_SOP_IF_ELSE,
496        R_LARCH_TLS_DESC_LD,
497        R_LARCH_SOP_ASSERT,
498        R_LARCH_MARK_PCREL,
499        R_LARCH_PCALA_HI20,
500        R_LARCH_PCALA_LO12,
501        R_LARCH_GOT_PC_HI20,
502        R_LARCH_TLS_LE_HI20,
503        R_LARCH_IRELATIVE,
504        R_LARCH_TLS_GD_HI20,
505        R_LARCH_TLS_IE_HI20,
506        R_LARCH_TLS_IE_LO12,
507        R_LARCH_SOP_PUSH_DUP,
508        R_LARCH_TLS_TPREL32,
509        R_LARCH_TLS_LE_LO12_R,
510        R_LARCH_TLS_TPREL64,
511        R_LARCH_TLS_LE_HI20_R,
512        R_LARCH_GNU_VTENTRY,
513        R_LARCH_SUB_ULEB128,
514        R_LARCH_ADD_ULEB128,
515        R_LARCH_TLS_DTPREL32,
516        R_LARCH_GOT64_PC_HI12,
517        R_LARCH_TLS_GD_PC_HI20,
518        R_LARCH_TLS_IE64_LO20,
519        R_LARCH_TLS_DESC_CALL,
520        R_LARCH_TLS_LE64_LO20,
521        R_LARCH_TLS_DTPMOD32,
522        R_LARCH_PCALA64_LO20,
523        R_LARCH_TLS_DTPMOD64,
524        R_LARCH_TLS_IE64_HI12,
525        R_LARCH_TLS_DTPREL64,
526        R_LARCH_TLS_DESC_HI20,
527        R_LARCH_GOT64_PC_LO20,
528        R_LARCH_TLS_IE_PC_HI20,
529        R_LARCH_TLS_IE_PC_LO12,
530        R_LARCH_TLS_DESC_LO12,
531        R_LARCH_TLS_LE64_HI12,
532        R_LARCH_TLS_LD_PC_HI20,
533        R_LARCH_PCALA64_HI12,
534        R_LARCH_SOP_POP_32_S_10_5,
535        R_LARCH_SOP_PUSH_PCREL,
536        R_LARCH_SOP_POP_32_S_5_20,
537        R_LARCH_SOP_PUSH_GPREL,
538        R_LARCH_SOP_PUSH_TLS_GD,
539        R_LARCH_GNU_VTINHERIT,
540        R_LARCH_TLS_IE64_PC_LO20,
541        R_LARCH_SOP_POP_32_S_10_12,
542        R_LARCH_TLS_DESC_PC_HI20,
543        R_LARCH_TLS_DESC_PC_LO12,
544        R_LARCH_SOP_POP_32_S_10_16,
545        R_LARCH_SOP_POP_32_U_10_12,
546        R_LARCH_TLS_DESC64_HI12,
547        R_LARCH_SOP_PUSH_TLS_GOT,
548        R_LARCH_TLS_IE64_PC_HI12,
549        R_LARCH_TLS_DESC64_LO20,
550        R_LARCH_TLS_LD_PCREL20_S2,
551        R_LARCH_TLS_GD_PCREL20_S2,
552        R_LARCH_TLS_DESC64_PC_HI12,
553        R_LARCH_SOP_PUSH_ABSOLUTE,
554        R_LARCH_TLS_DESC64_PC_LO20,
555        R_LARCH_SOP_PUSH_PLT_PCREL,
556        R_LARCH_SOP_PUSH_TLS_TPREL,
557        R_LARCH_SOP_POP_32_S_10_16_S2,
558        R_LARCH_TLS_DESC_PCREL20_S2,
559        R_LARCH_SOP_POP_32_S_0_5_10_16_S2,
560        R_LARCH_SOP_POP_32_S_0_10_10_16_S2,
561    ] {
562        Cow::Borrowed(name)
563    } else {
564        Cow::Owned(format!("Unknown loongarch relocation type 0x{r_type:x}"))
565    }
566}
567
568/// Section flag bit values.
569pub mod shf {
570    use super::SectionFlags;
571
572    pub const WRITE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_WRITE);
573    pub const ALLOC: SectionFlags = SectionFlags::from_u32(object::elf::SHF_ALLOC);
574    pub const EXECINSTR: SectionFlags = SectionFlags::from_u32(object::elf::SHF_EXECINSTR);
575    pub const MERGE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_MERGE);
576    pub const STRINGS: SectionFlags = SectionFlags::from_u32(object::elf::SHF_STRINGS);
577    pub const INFO_LINK: SectionFlags = SectionFlags::from_u32(object::elf::SHF_INFO_LINK);
578    pub const LINK_ORDER: SectionFlags = SectionFlags::from_u32(object::elf::SHF_LINK_ORDER);
579    pub const OS_NONCONFORMING: SectionFlags =
580        SectionFlags::from_u32(object::elf::SHF_OS_NONCONFORMING);
581    pub const GROUP: SectionFlags = SectionFlags::from_u32(object::elf::SHF_GROUP);
582    pub const TLS: SectionFlags = SectionFlags::from_u32(object::elf::SHF_TLS);
583    pub const COMPRESSED: SectionFlags = SectionFlags::from_u32(object::elf::SHF_COMPRESSED);
584    pub const GNU_RETAIN: SectionFlags = SectionFlags::from_u32(object::elf::SHF_GNU_RETAIN);
585    pub const EXCLUDE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_EXCLUDE);
586}
587
588#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
589pub struct SectionFlags(u32);
590
591impl SectionFlags {
592    #[must_use]
593    pub const fn empty() -> Self {
594        Self(0)
595    }
596
597    #[must_use]
598    pub fn from_header(header: &object::elf::SectionHeader64<LittleEndian>) -> Self {
599        Self(header.sh_flags(LittleEndian) as u32)
600    }
601
602    #[must_use]
603    pub fn contains(self, flag: SectionFlags) -> bool {
604        self.0 & flag.0 != 0
605    }
606
607    #[must_use]
608    pub const fn from_u32(raw: u32) -> SectionFlags {
609        SectionFlags(raw)
610    }
611
612    /// Returns self with the specified flags set.
613    #[must_use]
614    pub const fn with(self, flags: SectionFlags) -> SectionFlags {
615        SectionFlags(self.0 | flags.0)
616    }
617
618    /// Returns self with the specified flags cleared.
619    #[must_use]
620    pub const fn without(self, flags: SectionFlags) -> SectionFlags {
621        SectionFlags(self.0 & !flags.0)
622    }
623
624    #[must_use]
625    pub const fn raw(self) -> u64 {
626        self.0 as u64
627    }
628
629    #[must_use]
630    pub fn should_retain(&self) -> bool {
631        self.contains(shf::GNU_RETAIN)
632    }
633
634    #[must_use]
635    pub fn should_exclude(&self) -> bool {
636        self.contains(shf::EXCLUDE)
637    }
638}
639
640impl From<u64> for SectionFlags {
641    fn from(value: u64) -> Self {
642        Self(value as u32)
643    }
644}
645
646impl std::fmt::Display for SectionFlags {
647    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
648        for (flag, ch) in [
649            (shf::WRITE, "W"),
650            (shf::ALLOC, "A"),
651            (shf::EXECINSTR, "X"),
652            (shf::MERGE, "M"),
653            (shf::STRINGS, "S"),
654            (shf::INFO_LINK, "I"),
655            (shf::LINK_ORDER, "L"),
656            (shf::OS_NONCONFORMING, "O"),
657            (shf::GROUP, "G"),
658            (shf::TLS, "T"),
659            (shf::COMPRESSED, "C"),
660            (shf::EXCLUDE, "E"),
661            // TODO: ld linker sometimes propagates the flag
662            // (shf::GNU_RETAIN, "R"),
663        ] {
664            if self.contains(flag) {
665                f.write_str(ch)?;
666            }
667        }
668        Ok(())
669    }
670}
671
672impl std::fmt::Debug for SectionFlags {
673    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
674        std::fmt::Display::fmt(&self, f)
675    }
676}
677
678impl std::ops::BitOrAssign for SectionFlags {
679    fn bitor_assign(&mut self, rhs: Self) {
680        self.0 |= rhs.0;
681    }
682}
683
684impl std::ops::BitAnd for SectionFlags {
685    type Output = SectionFlags;
686
687    fn bitand(self, rhs: Self) -> Self::Output {
688        Self(self.0 & rhs.0)
689    }
690}
691
692pub mod secnames {
693    pub const FILEHEADER_SECTION_NAME_STR: &str = "";
694    pub const FILEHEADER_SECTION_NAME: &[u8] = FILEHEADER_SECTION_NAME_STR.as_bytes();
695    pub const RODATA_SECTION_NAME_STR: &str = ".rodata";
696    pub const RODATA_SECTION_NAME: &[u8] = RODATA_SECTION_NAME_STR.as_bytes();
697    pub const TEXT_SECTION_NAME_STR: &str = ".text";
698    pub const TEXT_SECTION_NAME: &[u8] = TEXT_SECTION_NAME_STR.as_bytes();
699    pub const INIT_ARRAY_SECTION_NAME_STR: &str = ".init_array";
700    pub const INIT_ARRAY_SECTION_NAME: &[u8] = INIT_ARRAY_SECTION_NAME_STR.as_bytes();
701    pub const FINI_ARRAY_SECTION_NAME_STR: &str = ".fini_array";
702    pub const FINI_ARRAY_SECTION_NAME: &[u8] = FINI_ARRAY_SECTION_NAME_STR.as_bytes();
703    pub const PREINIT_ARRAY_SECTION_NAME_STR: &str = ".preinit_array";
704    pub const PREINIT_ARRAY_SECTION_NAME: &[u8] = PREINIT_ARRAY_SECTION_NAME_STR.as_bytes();
705    pub const DATA_SECTION_NAME_STR: &str = ".data";
706    pub const DATA_SECTION_NAME: &[u8] = DATA_SECTION_NAME_STR.as_bytes();
707    pub const EH_FRAME_SECTION_NAME_STR: &str = ".eh_frame";
708    pub const EH_FRAME_SECTION_NAME: &[u8] = EH_FRAME_SECTION_NAME_STR.as_bytes();
709    pub const EH_FRAME_HDR_SECTION_NAME_STR: &str = ".eh_frame_hdr";
710    pub const EH_FRAME_HDR_SECTION_NAME: &[u8] = EH_FRAME_HDR_SECTION_NAME_STR.as_bytes();
711    pub const SFRAME_SECTION_NAME_STR: &str = ".sframe";
712    pub const SFRAME_SECTION_NAME: &[u8] = SFRAME_SECTION_NAME_STR.as_bytes();
713    pub const SHSTRTAB_SECTION_NAME_STR: &str = ".shstrtab";
714    pub const SHSTRTAB_SECTION_NAME: &[u8] = SHSTRTAB_SECTION_NAME_STR.as_bytes();
715    pub const SYMTAB_SECTION_NAME_STR: &str = ".symtab";
716    pub const SYMTAB_SECTION_NAME: &[u8] = SYMTAB_SECTION_NAME_STR.as_bytes();
717    pub const STRTAB_SECTION_NAME_STR: &str = ".strtab";
718    pub const STRTAB_SECTION_NAME: &[u8] = STRTAB_SECTION_NAME_STR.as_bytes();
719    pub const TDATA_SECTION_NAME_STR: &str = ".tdata";
720    pub const TDATA_SECTION_NAME: &[u8] = TDATA_SECTION_NAME_STR.as_bytes();
721    pub const TBSS_SECTION_NAME_STR: &str = ".tbss";
722    pub const TBSS_SECTION_NAME: &[u8] = TBSS_SECTION_NAME_STR.as_bytes();
723    pub const BSS_SECTION_NAME_STR: &str = ".bss";
724    pub const BSS_SECTION_NAME: &[u8] = BSS_SECTION_NAME_STR.as_bytes();
725    pub const GOT_SECTION_NAME_STR: &str = ".got";
726    pub const GOT_SECTION_NAME: &[u8] = GOT_SECTION_NAME_STR.as_bytes();
727    pub const INIT_SECTION_NAME_STR: &str = ".init";
728    pub const INIT_SECTION_NAME: &[u8] = INIT_SECTION_NAME_STR.as_bytes();
729    pub const FINI_SECTION_NAME_STR: &str = ".fini";
730    pub const FINI_SECTION_NAME: &[u8] = FINI_SECTION_NAME_STR.as_bytes();
731    pub const RELA_PLT_SECTION_NAME_STR: &str = ".rela.plt";
732    pub const RELA_PLT_SECTION_NAME: &[u8] = RELA_PLT_SECTION_NAME_STR.as_bytes();
733    pub const COMMENT_SECTION_NAME_STR: &str = ".comment";
734    pub const COMMENT_SECTION_NAME: &[u8] = COMMENT_SECTION_NAME_STR.as_bytes();
735    pub const DYNAMIC_SECTION_NAME_STR: &str = ".dynamic";
736    pub const DYNAMIC_SECTION_NAME: &[u8] = DYNAMIC_SECTION_NAME_STR.as_bytes();
737    pub const DYNSYM_SECTION_NAME_STR: &str = ".dynsym";
738    pub const DYNSYM_SECTION_NAME: &[u8] = DYNSYM_SECTION_NAME_STR.as_bytes();
739    pub const DYNSTR_SECTION_NAME_STR: &str = ".dynstr";
740    pub const DYNSTR_SECTION_NAME: &[u8] = DYNSTR_SECTION_NAME_STR.as_bytes();
741    pub const RELA_DYN_SECTION_NAME_STR: &str = ".rela.dyn";
742    pub const RELA_DYN_SECTION_NAME: &[u8] = RELA_DYN_SECTION_NAME_STR.as_bytes();
743    pub const GCC_EXCEPT_TABLE_SECTION_NAME_STR: &str = ".gcc_except_table";
744    pub const GCC_EXCEPT_TABLE_SECTION_NAME: &[u8] = GCC_EXCEPT_TABLE_SECTION_NAME_STR.as_bytes();
745    pub const INTERP_SECTION_NAME_STR: &str = ".interp";
746    pub const INTERP_SECTION_NAME: &[u8] = INTERP_SECTION_NAME_STR.as_bytes();
747    pub const GNU_VERSION_SECTION_NAME_STR: &str = ".gnu.version";
748    pub const GNU_VERSION_SECTION_NAME: &[u8] = GNU_VERSION_SECTION_NAME_STR.as_bytes();
749    pub const GNU_VERSION_D_SECTION_NAME_STR: &str = ".gnu.version_d";
750    pub const GNU_VERSION_D_SECTION_NAME: &[u8] = GNU_VERSION_D_SECTION_NAME_STR.as_bytes();
751    pub const GNU_VERSION_R_SECTION_NAME_STR: &str = ".gnu.version_r";
752    pub const GNU_VERSION_R_SECTION_NAME: &[u8] = GNU_VERSION_R_SECTION_NAME_STR.as_bytes();
753    pub const HASH_SECTION_NAME_STR: &str = ".hash";
754    pub const HASH_SECTION_NAME: &[u8] = HASH_SECTION_NAME_STR.as_bytes();
755    pub const PROGRAM_HEADERS_SECTION_NAME_STR: &str = ".phdr";
756    pub const PROGRAM_HEADERS_SECTION_NAME: &[u8] = PROGRAM_HEADERS_SECTION_NAME_STR.as_bytes();
757    pub const SECTION_HEADERS_SECTION_NAME_STR: &str = ".shdr";
758    pub const SECTION_HEADERS_SECTION_NAME: &[u8] = SECTION_HEADERS_SECTION_NAME_STR.as_bytes();
759    pub const GNU_HASH_SECTION_NAME_STR: &str = ".gnu.hash";
760    pub const GNU_HASH_SECTION_NAME: &[u8] = GNU_HASH_SECTION_NAME_STR.as_bytes();
761    pub const PLT_SECTION_NAME_STR: &str = ".plt";
762    pub const PLT_SECTION_NAME: &[u8] = PLT_SECTION_NAME_STR.as_bytes();
763    pub const IPLT_SECTION_NAME_STR: &str = ".iplt";
764    pub const IPLT_SECTION_NAME: &[u8] = IPLT_SECTION_NAME_STR.as_bytes();
765    pub const PLT_GOT_SECTION_NAME_STR: &str = ".plt.got";
766    pub const PLT_GOT_SECTION_NAME: &[u8] = PLT_GOT_SECTION_NAME_STR.as_bytes();
767    pub const GOT_PLT_SECTION_NAME_STR: &str = ".got.plt";
768    pub const GOT_PLT_SECTION_NAME: &[u8] = GOT_PLT_SECTION_NAME_STR.as_bytes();
769    pub const PLT_SEC_SECTION_NAME_STR: &str = ".plt.sec";
770    pub const PLT_SEC_SECTION_NAME: &[u8] = PLT_SEC_SECTION_NAME_STR.as_bytes();
771    pub const NOTE_ABI_TAG_SECTION_NAME_STR: &str = ".note.ABI-tag";
772    pub const NOTE_ABI_TAG_SECTION_NAME: &[u8] = NOTE_ABI_TAG_SECTION_NAME_STR.as_bytes();
773    pub const NOTE_GNU_PROPERTY_SECTION_NAME_STR: &str = ".note.gnu.property";
774    pub const NOTE_GNU_PROPERTY_SECTION_NAME: &[u8] = NOTE_GNU_PROPERTY_SECTION_NAME_STR.as_bytes();
775    pub const NOTE_GNU_BUILD_ID_SECTION_NAME_STR: &str = ".note.gnu.build-id";
776    pub const NOTE_GNU_BUILD_ID_SECTION_NAME: &[u8] = NOTE_GNU_BUILD_ID_SECTION_NAME_STR.as_bytes();
777    pub const DEBUG_LOC_SECTION_NAME_STR: &str = ".debug_loc";
778    pub const DEBUG_LOC_SECTION_NAME: &[u8] = DEBUG_LOC_SECTION_NAME_STR.as_bytes();
779    pub const DEBUG_RANGES_SECTION_NAME_STR: &str = ".debug_ranges";
780    pub const DEBUG_RANGES_SECTION_NAME: &[u8] = DEBUG_RANGES_SECTION_NAME_STR.as_bytes();
781    pub const GROUP_SECTION_NAME_STR: &str = ".group";
782    pub const GROUP_SECTION_NAME: &[u8] = GROUP_SECTION_NAME_STR.as_bytes();
783    pub const DATA_REL_RO_SECTION_NAME_STR: &str = ".data.rel.ro";
784    pub const DATA_REL_RO_SECTION_NAME: &[u8] = DATA_REL_RO_SECTION_NAME_STR.as_bytes();
785    pub const RISCV_ATTRIBUTES_SECTION_NAME_STR: &str = ".riscv.attributes";
786    pub const RISCV_ATTRIBUTES_SECTION_NAME: &[u8] = RISCV_ATTRIBUTES_SECTION_NAME_STR.as_bytes();
787
788    pub const GNU_LTO_SYMTAB_PREFIX: &str = ".gnu.lto_.symtab";
789}
790
791#[derive(Clone, Copy, PartialEq, Eq)]
792pub struct SegmentFlags(u32);
793
794impl SegmentFlags {
795    #[must_use]
796    pub const fn empty() -> Self {
797        Self(0)
798    }
799
800    #[must_use]
801    pub fn from_header(header: &object::elf::ProgramHeader64<LittleEndian>) -> Self {
802        Self(header.p_flags(LittleEndian))
803    }
804
805    #[must_use]
806    pub fn contains(self, flag: SegmentFlags) -> bool {
807        self.0 & flag.0 != 0
808    }
809
810    #[must_use]
811    pub const fn from_u32(raw: u32) -> SegmentFlags {
812        SegmentFlags(raw)
813    }
814
815    /// Returns self with the specified flags set.
816    #[must_use]
817    pub const fn with(self, flags: SegmentFlags) -> SegmentFlags {
818        SegmentFlags(self.0 | flags.0)
819    }
820
821    /// Returns self with the specified flags cleared.
822    #[must_use]
823    pub const fn without(self, flags: SegmentFlags) -> SegmentFlags {
824        SegmentFlags(self.0 & !flags.0)
825    }
826
827    #[must_use]
828    pub const fn raw(self) -> u32 {
829        self.0
830    }
831}
832
833pub mod pf {
834    use super::SegmentFlags;
835
836    pub const EXECUTABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_X);
837    pub const WRITABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_W);
838    pub const READABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_R);
839}
840
841impl std::fmt::Display for SegmentFlags {
842    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
843        if self.contains(pf::WRITABLE) {
844            f.write_str("W")?;
845        }
846        if self.contains(pf::READABLE) {
847            f.write_str("R")?;
848        }
849        if self.contains(pf::EXECUTABLE) {
850            f.write_str("X")?;
851        }
852        Ok(())
853    }
854}
855
856impl std::fmt::Debug for SegmentFlags {
857    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
858        std::fmt::Display::fmt(&self, f)
859    }
860}
861
862impl std::ops::BitOrAssign for SegmentFlags {
863    fn bitor_assign(&mut self, rhs: Self) {
864        self.0 |= rhs.0;
865    }
866}
867
868impl std::ops::BitAnd for SegmentFlags {
869    type Output = SegmentFlags;
870
871    fn bitand(self, rhs: Self) -> Self::Output {
872        Self(self.0 & rhs.0)
873    }
874}
875
876// RISC-V related constants
877
878/// Dynamic thread vector pointers point 0x800 past the start of each TLS block.
879pub const RISCV_TLS_DTV_OFFSET: u64 = 0x800;
880
881pub const RISCV_ATTRIBUTE_VENDOR_NAME: &str = "riscv";
882
883// 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
884pub mod riscvattr {
885    // Attributes relate to whole file.
886    pub const TAG_RISCV_WHOLE_FILE: u64 = 1;
887    // Indicates the stack alignment requirement in bytes (ULEB128).
888    pub const TAG_RISCV_STACK_ALIGN: u64 = 4;
889    // Indicates the target architecture of this object (NTBS).
890    pub const TAG_RISCV_ARCH: u64 = 5;
891    // Indicates whether to impose unaligned memory accesses in code generation (ULEB128).
892    pub const TAG_RISCV_UNALIGNED_ACCESS: u64 = 6;
893    // Indicates the major version of the privileged specification (ULEB128, deprecated).
894    pub const TAG_RISCV_PRIV_SPEC: u64 = 8;
895    // Indicates the minor version of the privileged specification (ULEB128, deprecated).
896    pub const TAG_RISCV_PRIV_SPEC_MINOR: u64 = 10;
897    // Indicates the revision version of the privileged specification (ULEB128, deprecated).
898    pub const TAG_RISCV_PRIV_SPEC_REVISION: u64 = 12;
899    // Indicates which version of the atomics ABI is being used (ULEB128).
900    pub const TAG_RISCV_ATOMIC_ABI: u64 = 14;
901    // Indicates the usage definition of the X3 register (ULEB128).
902    pub const TAG_RISCV_X3_REG_USAGE: u64 = 16;
903}
904
905#[derive(Clone, Copy, Debug, PartialEq, Eq)]
906pub enum Sign {
907    Signed,
908    Unsigned,
909}
910
911/// For additional information on ELF relocation types, see "ELF-64 Object File Format" -
912/// <https://uclibc.org/docs/elf-64-gen.pdf>. For information on the TLS related relocations, see "ELF
913/// Handling For Thread-Local Storage" - <https://www.uclibc.org/docs/tls.pdf>.
914#[derive(Clone, Copy, Debug, PartialEq, Eq)]
915pub enum RelocationKind {
916    /// The absolute address of a symbol or section.
917    Absolute,
918
919    /// The absolute address of a symbol or section related to EH section.
920    AbsoluteSet,
921
922    /// The 6 low bits of an absolute address of a symbol or section.
923    AbsoluteSetWord6,
924
925    /// Add the absolute address of a symbol or section at the place of the relocation
926    /// to the value at the place.
927    AbsoluteAddition,
928
929    /// Add the absolute address of a symbol or section at the place of the relocation
930    /// to the value at the place (use WORD6 type for the operation)
931    AbsoluteAdditionWord6,
932
933    /// Subtract the absolute address of a symbol or section at the place of the relocation
934    /// from the value at the place.
935    AbsoluteSubtraction,
936
937    /// Subtract the absolute address of a symbol or section at the place of the relocation
938    /// from the value at the place (use WORD6 type for the operation)
939    AbsoluteSubtractionWord6,
940
941    /// The absolute address of a symbol or section. We are going to extract only the offset
942    /// within a page, so dynamic relocation creation must be skipped. Used by both AArch64
943    /// and LoongArch64 targets.
944    AbsoluteLowPart,
945
946    /// Subtract addresses of two symbols and encode the value using ULEB128.
947    ///
948    /// Note: The assembler must allocate sufficient space to accommodate the final value for the
949    /// R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 relocation pair and fill the space with a
950    /// single ULEB128-encoded value. This is achieved by prepending the redundant 0x80 byte as
951    /// necessary. The linker must not alter the length of the ULEB128-encoded value.
952    PairSubtractionULEB128(u32),
953
954    /// The address of the symbol, relative to the place of the relocation.
955    Relative,
956
957    /// The address of the symbol, relative to the place of the relocation
958    /// (using LoongArch64 high part encoding).
959    RelativeLoongArchHigh,
960
961    /// The address of the symbol, relative to the place of the relocation. The address of the
962    /// relocation points to an instruction for which the R_RISCV_PCREL_HI20 relocation is used
963    /// and that is the place we make this relocation relative to.
964    RelativeRiscVLow12,
965
966    /// The address of the symbol, relative to the base address of the GOT.
967    SymRelGotBase,
968
969    /// The offset of the symbol's GOT entry, relative to the start of the GOT.
970    GotRelGotBase,
971
972    /// The address of the symbol's GOT entry.
973    Got,
974
975    /// The address of the symbol's PLT entry, relative to the base address of the GOT.
976    PltRelGotBase,
977
978    /// The address of the symbol's PLT entry, relative to the place of relocation.
979    PltRelative,
980
981    /// The address of the symbol's GOT entry, relative to the place of the relocation.
982    GotRelative,
983
984    /// The address of the symbol's GOT entry, relative to the place of the relocation
985    /// (using LoongArch64 high part encoding).
986    GotRelativeLoongArch64,
987
988    /// The address of a TLSGD structure, relative to the place of the relocation. A TLSGD
989    /// (thread-local storage general dynamic) structure is a pair of values containing a module ID
990    /// and the offset within that module's TLS storage.
991    TlsGd,
992
993    /// The address of the symbol's TLSGD GOT entry.
994    TlsGdGot,
995
996    /// The address of the symbol's TLSGD GOT entry, relative to the start of the GOT.
997    TlsGdGotBase,
998
999    /// The address of the TLS module ID for the shared object that we're writing, relative to the
1000    /// place of the relocation. This is used when a TLS variable is defined and used within the
1001    /// same shared object.
1002    TlsLd,
1003
1004    /// The address of the TLS module ID for the shared object that we're writing.
1005    TlsLdGot,
1006
1007    /// The address of the TLS module ID for the shared object that we're writing,
1008    /// relative to the start of the GOT.
1009    TlsLdGotBase,
1010
1011    /// The offset of a thread-local within the TLS storage of DSO that defines that thread-local.
1012    DtpOff,
1013
1014    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
1015    /// TLS storage, relative to the place of the relocation.
1016    GotTpOff,
1017
1018    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
1019    /// TLS storage, relative to the place of the relocation.
1020    /// (using LoongArch64 high part encoding).
1021    GotTpOffLoongArch64,
1022
1023    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
1024    /// TLS storage.
1025    GotTpOffGot,
1026
1027    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
1028    /// TLS storage, relative to the start of the GOT.
1029    GotTpOffGotBase,
1030
1031    /// The offset of a TLS variable within the executable's TLS storage.
1032    TpOff,
1033
1034    /// The address of a TLS descriptor structure, relative to the place of the relocation.
1035    TlsDesc,
1036
1037    /// The address of a TLS descriptor structure, relative to the place of the relocation.
1038    /// (using LoongArch64 high part encoding).
1039    TlsDescLoongArch64,
1040
1041    /// The address of a TLS descriptor structure.
1042    TlsDescGot,
1043
1044    /// The address of a TLS descriptor structure, relative to the start of the GOT.
1045    TlsDescGotBase,
1046
1047    /// Call to the TLS descriptor trampoline. Used only as a placeholder for a linker relaxation
1048    /// opportunity.
1049    TlsDescCall,
1050
1051    /// No relocation needs to be applied. Produced when we eliminate a relocation due to an
1052    /// optimisation.
1053    None,
1054
1055    /// The address must fulfill the alignment requirement.
1056    Alignment,
1057}
1058
1059impl RelocationKind {
1060    #[must_use]
1061    pub fn is_tls(self) -> bool {
1062        matches!(
1063            self,
1064            Self::DtpOff
1065                | Self::GotTpOff
1066                | Self::GotTpOffGotBase
1067                | Self::TlsDesc
1068                | Self::TlsDescCall
1069                | Self::TlsDescGot
1070                | Self::TlsDescGotBase
1071                | Self::TlsGd
1072                | Self::TlsGdGot
1073                | Self::TlsGdGotBase
1074                | Self::TlsLd
1075                | Self::TlsLdGot
1076                | Self::TlsLdGotBase
1077                | Self::TpOff
1078        )
1079    }
1080}
1081
1082#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1083pub enum DynamicRelocationKind {
1084    Copy,
1085    Irelative,
1086    DtpMod,
1087    DtpOff,
1088    TlsDesc,
1089    TpOff,
1090    Relative,
1091    Absolute,
1092    GotEntry,
1093    JumpSlot,
1094}
1095
1096impl DynamicRelocationKind {
1097    #[must_use]
1098    pub fn from_x86_64_r_type(r_type: u32) -> Option<Self> {
1099        let kind = match r_type {
1100            object::elf::R_X86_64_COPY => DynamicRelocationKind::Copy,
1101            object::elf::R_X86_64_IRELATIVE => DynamicRelocationKind::Irelative,
1102            object::elf::R_X86_64_DTPMOD64 => DynamicRelocationKind::DtpMod,
1103            object::elf::R_X86_64_DTPOFF64 => DynamicRelocationKind::DtpOff,
1104            object::elf::R_X86_64_TPOFF64 => DynamicRelocationKind::TpOff,
1105            object::elf::R_X86_64_RELATIVE => DynamicRelocationKind::Relative,
1106            object::elf::R_X86_64_GLOB_DAT => DynamicRelocationKind::GotEntry,
1107            object::elf::R_X86_64_64 => DynamicRelocationKind::Absolute,
1108            object::elf::R_X86_64_TLSDESC => DynamicRelocationKind::TlsDesc,
1109            object::elf::R_X86_64_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1110            _ => return None,
1111        };
1112
1113        Some(kind)
1114    }
1115
1116    #[must_use]
1117    pub fn x86_64_r_type(self) -> u32 {
1118        match self {
1119            DynamicRelocationKind::Copy => object::elf::R_X86_64_COPY,
1120            DynamicRelocationKind::Irelative => object::elf::R_X86_64_IRELATIVE,
1121            DynamicRelocationKind::DtpMod => object::elf::R_X86_64_DTPMOD64,
1122            DynamicRelocationKind::DtpOff => object::elf::R_X86_64_DTPOFF64,
1123            DynamicRelocationKind::TpOff => object::elf::R_X86_64_TPOFF64,
1124            DynamicRelocationKind::Relative => object::elf::R_X86_64_RELATIVE,
1125            DynamicRelocationKind::Absolute => object::elf::R_X86_64_64,
1126            DynamicRelocationKind::GotEntry => object::elf::R_X86_64_GLOB_DAT,
1127            DynamicRelocationKind::TlsDesc => object::elf::R_X86_64_TLSDESC,
1128            DynamicRelocationKind::JumpSlot => object::elf::R_X86_64_JUMP_SLOT,
1129        }
1130    }
1131
1132    #[must_use]
1133    pub fn from_aarch64_r_type(r_type: u32) -> Option<Self> {
1134        let kind = match r_type {
1135            object::elf::R_AARCH64_COPY => DynamicRelocationKind::Copy,
1136            object::elf::R_AARCH64_IRELATIVE => DynamicRelocationKind::Irelative,
1137            object::elf::R_AARCH64_TLS_DTPMOD => DynamicRelocationKind::DtpMod,
1138            object::elf::R_AARCH64_TLS_DTPREL => DynamicRelocationKind::DtpOff,
1139            object::elf::R_AARCH64_TLS_TPREL => DynamicRelocationKind::TpOff,
1140            object::elf::R_AARCH64_RELATIVE => DynamicRelocationKind::Relative,
1141            object::elf::R_AARCH64_ABS64 => DynamicRelocationKind::Absolute,
1142            object::elf::R_AARCH64_GLOB_DAT => DynamicRelocationKind::GotEntry,
1143            object::elf::R_AARCH64_TLSDESC => DynamicRelocationKind::TlsDesc,
1144            object::elf::R_AARCH64_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1145            _ => return None,
1146        };
1147
1148        Some(kind)
1149    }
1150
1151    #[must_use]
1152    pub fn aarch64_r_type(&self) -> u32 {
1153        match self {
1154            DynamicRelocationKind::Copy => object::elf::R_AARCH64_COPY,
1155            DynamicRelocationKind::Irelative => object::elf::R_AARCH64_IRELATIVE,
1156            DynamicRelocationKind::DtpMod => object::elf::R_AARCH64_TLS_DTPMOD,
1157            DynamicRelocationKind::DtpOff => object::elf::R_AARCH64_TLS_DTPREL,
1158            DynamicRelocationKind::TpOff => object::elf::R_AARCH64_TLS_TPREL,
1159            DynamicRelocationKind::Relative => object::elf::R_AARCH64_RELATIVE,
1160            DynamicRelocationKind::Absolute => object::elf::R_AARCH64_ABS64,
1161            DynamicRelocationKind::GotEntry => object::elf::R_AARCH64_GLOB_DAT,
1162            DynamicRelocationKind::TlsDesc => object::elf::R_AARCH64_TLSDESC,
1163            DynamicRelocationKind::JumpSlot => object::elf::R_AARCH64_JUMP_SLOT,
1164        }
1165    }
1166
1167    #[must_use]
1168    pub fn from_riscv64_r_type(r_type: u32) -> Option<Self> {
1169        let kind = match r_type {
1170            object::elf::R_RISCV_COPY => DynamicRelocationKind::Copy,
1171            object::elf::R_RISCV_IRELATIVE => DynamicRelocationKind::Irelative,
1172            object::elf::R_RISCV_TLS_DTPMOD64 => DynamicRelocationKind::DtpMod,
1173            object::elf::R_RISCV_TLS_DTPREL64 => DynamicRelocationKind::DtpOff,
1174            object::elf::R_RISCV_TLS_TPREL64 => DynamicRelocationKind::TpOff,
1175            object::elf::R_RISCV_RELATIVE => DynamicRelocationKind::Relative,
1176            object::elf::R_RISCV_64 => DynamicRelocationKind::Absolute,
1177            object::elf::R_RISCV_TLSDESC => DynamicRelocationKind::TlsDesc,
1178            object::elf::R_RISCV_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1179            _ => return None,
1180        };
1181        Some(kind)
1182    }
1183
1184    #[must_use]
1185    pub fn riscv64_r_type(&self) -> u32 {
1186        match self {
1187            DynamicRelocationKind::Copy => object::elf::R_RISCV_COPY,
1188            DynamicRelocationKind::Irelative => object::elf::R_RISCV_IRELATIVE,
1189            DynamicRelocationKind::DtpMod => object::elf::R_RISCV_TLS_DTPMOD64,
1190            DynamicRelocationKind::DtpOff => object::elf::R_RISCV_TLS_DTPREL64,
1191            DynamicRelocationKind::TpOff => object::elf::R_RISCV_TLS_TPREL64,
1192            DynamicRelocationKind::Relative => object::elf::R_RISCV_RELATIVE,
1193            DynamicRelocationKind::Absolute => object::elf::R_RISCV_64,
1194            DynamicRelocationKind::GotEntry => object::elf::R_RISCV_64,
1195            DynamicRelocationKind::TlsDesc => object::elf::R_RISCV_TLSDESC,
1196            DynamicRelocationKind::JumpSlot => object::elf::R_RISCV_JUMP_SLOT,
1197        }
1198    }
1199
1200    #[must_use]
1201    pub fn from_loongarch64_r_type(r_type: u32) -> Option<Self> {
1202        let kind = match r_type {
1203            object::elf::R_LARCH_COPY => DynamicRelocationKind::Copy,
1204            object::elf::R_LARCH_IRELATIVE => DynamicRelocationKind::Irelative,
1205            object::elf::R_LARCH_TLS_DTPMOD64 => DynamicRelocationKind::DtpMod,
1206            object::elf::R_LARCH_TLS_DTPREL64 => DynamicRelocationKind::DtpOff,
1207            object::elf::R_LARCH_TLS_TPREL64 => DynamicRelocationKind::TpOff,
1208            object::elf::R_LARCH_RELATIVE => DynamicRelocationKind::Relative,
1209            object::elf::R_LARCH_64 => DynamicRelocationKind::Absolute,
1210            object::elf::R_LARCH_TLS_DESC64 => DynamicRelocationKind::TlsDesc,
1211            object::elf::R_LARCH_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1212            _ => return None,
1213        };
1214        Some(kind)
1215    }
1216
1217    #[must_use]
1218    pub fn loongarch64_r_type(&self) -> u32 {
1219        match self {
1220            DynamicRelocationKind::Copy => object::elf::R_LARCH_COPY,
1221            DynamicRelocationKind::Irelative => object::elf::R_LARCH_IRELATIVE,
1222            DynamicRelocationKind::DtpMod => object::elf::R_LARCH_TLS_DTPMOD64,
1223            DynamicRelocationKind::DtpOff => object::elf::R_LARCH_TLS_DTPREL64,
1224            DynamicRelocationKind::TpOff => object::elf::R_LARCH_TLS_TPREL64,
1225            DynamicRelocationKind::Relative => object::elf::R_LARCH_RELATIVE,
1226            DynamicRelocationKind::Absolute => object::elf::R_LARCH_64,
1227            DynamicRelocationKind::GotEntry => object::elf::R_LARCH_64,
1228            DynamicRelocationKind::TlsDesc => object::elf::R_LARCH_TLS_DESC64,
1229            DynamicRelocationKind::JumpSlot => object::elf::R_LARCH_JUMP_SLOT,
1230        }
1231    }
1232}
1233
1234#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1235pub enum AArch64Instruction {
1236    Adr,
1237    Movkz,
1238    Movnz,
1239    Ldr,
1240    LdrRegister,
1241    Add,
1242    LdSt,
1243    TstBr,
1244    Bcond,
1245    JumpCall,
1246}
1247
1248#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1249pub enum RiscVInstruction {
1250    // The relocation encoding actually modifies the consecutive pair of instructions:
1251    //   10:	00000097          	auipc	ra,0x0	10: R_RISCV_CALL_PLT	symbol_name
1252    //   14:	000080e7          	jalr	ra # 10 <main+0x10>
1253    //
1254    // That makes the relocation pretty unusual as one would expect 2 relocations:
1255    // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#procedure-calls
1256    UiType,
1257
1258    // Encodes high 20 bits of 32-bit value and encodes the bits to upper part.
1259    UType,
1260
1261    // Encodes low 12 bits of 32-bit value and encodes the bits to upper part.
1262    IType,
1263
1264    // Encodes 12 bits of 32-bit value.
1265    SType,
1266
1267    // The X-type instruction immediate encoding is defined here:
1268    // https://riscv.github.io/riscv-isa-manual/snapshot/unprivileged/#_immediate_encoding_variants
1269
1270    // Specifies a field as the immediate field in a B-type (branch) instruction
1271    BType,
1272
1273    // Specifies a field as the immediate field in a J-type (jump) instruction
1274    JType,
1275
1276    // Specifies a field as the immediate field in a CB-type (compressed branch) instruction
1277    // https://riscv.github.io/riscv-isa-manual/snapshot/unprivileged/#_control_transfer_instructions_2
1278    CbType,
1279
1280    // Specifies a field as the immediate field in a CJ-type (compressed jump) instruction
1281    CjType,
1282}
1283
1284#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1285pub enum LoongArch64Instruction {
1286    Shift5,
1287    Shift10,
1288    Branch21or26,
1289    Call30,
1290    Call36,
1291}
1292
1293#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1294pub enum RelocationInstruction {
1295    AArch64(AArch64Instruction),
1296    RiscV(RiscVInstruction),
1297    LoongArch64(LoongArch64Instruction),
1298}
1299
1300impl RelocationInstruction {
1301    #[must_use]
1302    pub fn bit_mask(&self, range: BitRange) -> [u8; 4] {
1303        let mut mask = [0; 4];
1304
1305        // To figure out which bits are part of the relocation, we write a value with
1306        // all ones into a buffer that initially contains zeros.
1307        let all_ones = (1 << (range.end - range.start)) - 1;
1308        self.write_to_value(all_ones, false, &mut mask);
1309
1310        // Wherever we get a 1 is part of the relocation, so invert all bits.
1311        for b in &mut mask {
1312            *b = !*b;
1313        }
1314
1315        mask
1316    }
1317
1318    pub fn write_to_value(self, extracted_value: u64, negative: bool, dest: &mut [u8]) {
1319        match self {
1320            Self::AArch64(insn) => insn.write_to_value(extracted_value, negative, dest),
1321            Self::RiscV(insn) => insn.write_to_value(extracted_value, negative, dest),
1322            Self::LoongArch64(insn) => insn.write_to_value(extracted_value, negative, dest),
1323        }
1324    }
1325
1326    /// The inverse of `write_to_value`. Returns `(extracted_value, negative)`. Supplied `bytes`
1327    /// must be at least 4 bytes, otherwise we panic.
1328    #[must_use]
1329    pub fn read_value(self, bytes: &[u8]) -> (u64, bool) {
1330        match self {
1331            Self::AArch64(insn) => insn.read_value(bytes),
1332            Self::RiscV(insn) => insn.read_value(bytes),
1333            Self::LoongArch64(insn) => insn.read_value(bytes),
1334        }
1335    }
1336
1337    /// The number of bytes the relocation actually can modify in the output data.
1338    #[must_use]
1339    pub fn write_windows_size(self) -> usize {
1340        match self {
1341            Self::AArch64(..) => 4,
1342            Self::RiscV(..) => 4,
1343            Self::LoongArch64(..) => 4,
1344        }
1345    }
1346}
1347
1348#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1349pub enum RelocationSize {
1350    ByteSize(usize),
1351    BitMasking(BitMask),
1352}
1353
1354impl fmt::Display for RelocationSize {
1355    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1356        match self {
1357            Self::ByteSize(bytes) => f.write_fmt(format_args!("{bytes}B")),
1358            Self::BitMasking(mask) => {
1359                f.write_fmt(format_args!("{}..{}", mask.range.start, mask.range.end))
1360            }
1361        }
1362    }
1363}
1364
1365impl RelocationSize {
1366    pub(crate) const fn bit_mask_aarch64(
1367        bit_start: u32,
1368        bit_end: u32,
1369        instruction: AArch64Instruction,
1370    ) -> RelocationSize {
1371        Self::BitMasking(BitMask::new(
1372            RelocationInstruction::AArch64(instruction),
1373            bit_start,
1374            bit_end,
1375        ))
1376    }
1377
1378    pub(crate) const fn bit_mask_riscv(
1379        bit_start: u32,
1380        bit_end: u32,
1381        instruction: RiscVInstruction,
1382    ) -> RelocationSize {
1383        Self::BitMasking(BitMask::new(
1384            RelocationInstruction::RiscV(instruction),
1385            bit_start,
1386            bit_end,
1387        ))
1388    }
1389
1390    pub(crate) const fn bit_mask_loongarch64(
1391        bit_start: u32,
1392        bit_end: u32,
1393        instruction: LoongArch64Instruction,
1394    ) -> RelocationSize {
1395        Self::BitMasking(BitMask::new(
1396            RelocationInstruction::LoongArch64(instruction),
1397            bit_start,
1398            bit_end,
1399        ))
1400    }
1401}
1402
1403#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1404pub struct BitMask {
1405    pub instruction: RelocationInstruction,
1406    pub range: BitRange,
1407}
1408
1409pub const SIZE_2KB: u64 = 1 << 11;
1410pub const SIZE_4KB: u64 = 1 << 12;
1411pub const SIZE_2GB: u64 = 1 << 31;
1412pub const SIZE_4GB: u64 = 1 << 32;
1413
1414pub const PAGE_MASK_4KB: u64 = SIZE_4KB - 1;
1415pub const PAGE_MASK_4GB: u64 = SIZE_4GB - 1;
1416
1417#[derive(Debug, Clone, Copy)]
1418pub enum PageMask {
1419    SymbolPlusAddendAndPosition(u64),
1420    GotEntryAndPosition(u64),
1421    GotBase(u64),
1422    Position(u64),
1423}
1424
1425// Allow range (half-open) of a computed value of a relocation
1426#[derive(Clone, Debug, Copy, PartialEq)]
1427pub struct AllowedRange {
1428    pub min: i64,
1429    pub max: i64,
1430}
1431
1432impl AllowedRange {
1433    #[must_use]
1434    pub const fn new(min: i64, max: i64) -> Self {
1435        Self { min, max }
1436    }
1437
1438    #[must_use]
1439    pub const fn no_check() -> Self {
1440        Self::new(i64::MIN, i64::MAX)
1441    }
1442
1443    #[must_use]
1444    /// Note: for the 8-byte size, we actually do signed checks regardless of the `sign` argument
1445    /// because the `min` and `max` are `i64` type
1446    pub const fn from_byte_size(n_bytes: usize, sign: Sign) -> Self {
1447        match n_bytes {
1448            0 | 8 => Self::no_check(),
1449            1..=7 => {
1450                let bits = n_bytes * 8;
1451                let half_range = 1i64 << (bits - 1);
1452                match sign {
1453                    Sign::Unsigned => Self::new(0, half_range * 2 - 1),
1454                    Sign::Signed => Self::new(-half_range, half_range - 1),
1455                }
1456            }
1457            _ => panic!("Only sizes up to 8 bytes are supported"),
1458        }
1459    }
1460}
1461
1462#[derive(Clone, Debug, Copy)]
1463pub struct RelocationKindInfo {
1464    pub kind: RelocationKind,
1465    pub size: RelocationSize,
1466    pub mask: Option<PageMask>,
1467    pub range: AllowedRange,
1468    pub alignment: usize,
1469    pub bias: u64,
1470}
1471
1472impl RelocationKindInfo {
1473    #[inline(always)]
1474    pub fn verify(&self, value: i64) -> Result<()> {
1475        anyhow::ensure!(
1476            (value as usize) & (self.alignment - 1) == 0,
1477            "Relocation {value} not aligned to {} bytes",
1478            self.alignment
1479        );
1480        anyhow::ensure!(
1481            self.range.min <= value && value < self.range.max,
1482            format!(
1483                "Relocation {value} outside of bounds [{}, {})",
1484                self.range.min, self.range.max
1485            )
1486        );
1487        Ok(())
1488    }
1489}
1490
1491impl BitMask {
1492    #[must_use]
1493    pub const fn new(instruction: RelocationInstruction, bit_start: u32, bit_end: u32) -> Self {
1494        Self {
1495            instruction,
1496            range: BitRange {
1497                start: bit_start,
1498                end: bit_end,
1499            },
1500        }
1501    }
1502}
1503
1504#[cfg(test)]
1505mod tests {
1506    use super::*;
1507    use object::elf::*;
1508
1509    #[test]
1510    fn test_rel_type_to_string() {
1511        assert_eq!(
1512            &x86_64_rel_type_to_string(R_X86_64_32),
1513            stringify!(R_X86_64_32)
1514        );
1515        assert_eq!(
1516            &x86_64_rel_type_to_string(R_X86_64_GOTPC32_TLSDESC),
1517            stringify!(R_X86_64_GOTPC32_TLSDESC)
1518        );
1519        assert_eq!(
1520            &x86_64_rel_type_to_string(64),
1521            "Unknown x86_64 relocation type 0x40"
1522        );
1523
1524        assert_eq!(
1525            &aarch64_rel_type_to_string(64),
1526            "Unknown aarch64 relocation type 0x40"
1527        );
1528    }
1529
1530    #[test]
1531    fn test_range_from_byte_size() {
1532        assert_eq!(
1533            AllowedRange::from_byte_size(0, Sign::Signed),
1534            AllowedRange::no_check(),
1535        );
1536        assert_eq!(
1537            AllowedRange::from_byte_size(0, Sign::Unsigned),
1538            AllowedRange::no_check(),
1539        );
1540        assert_eq!(
1541            AllowedRange::from_byte_size(1, Sign::Signed),
1542            AllowedRange::new(-128, 127)
1543        );
1544        assert_eq!(
1545            AllowedRange::from_byte_size(1, Sign::Unsigned),
1546            AllowedRange::new(0, 255)
1547        );
1548        assert_eq!(
1549            AllowedRange::from_byte_size(4, Sign::Signed),
1550            AllowedRange::new(i32::MIN.into(), i32::MAX.into())
1551        );
1552        assert_eq!(
1553            AllowedRange::from_byte_size(4, Sign::Unsigned),
1554            AllowedRange::new(u32::MIN.into(), u32::MAX.into())
1555        );
1556        assert_eq!(
1557            AllowedRange::from_byte_size(8, Sign::Signed),
1558            AllowedRange::no_check()
1559        );
1560        // 8-byte unsigned is also no check because the range cannot be represented in i64
1561        assert_eq!(
1562            AllowedRange::from_byte_size(8, Sign::Unsigned),
1563            AllowedRange::no_check()
1564        );
1565    }
1566}