Skip to main content

linker_utils/
elf.rs

1use crate::bit_misc::BitExtraction;
2use crate::bit_misc::BitRange;
3use anyhow::Result;
4use object::LittleEndian;
5use object::read::elf::ProgramHeader as _;
6use object::read::elf::SectionHeader;
7use std::borrow::Cow;
8use std::fmt;
9use std::io::Cursor;
10
11macro_rules! const_name_by_value {
12    ($needle: expr, $( $const:ident ),* $(,)?) => {
13        match $needle {
14            $(object::elf::$const => Some(stringify!($const)),)*
15            _ => None
16        }
17    };
18}
19
20macro_rules! const_or_literal {
21    ($prefix:ident $const:ident = $value:expr) => {
22        $value
23    };
24    ($prefix:ident $const:ident) => {
25        ::paste::paste! {
26            ::object::elf::[<$prefix _ $const>]
27        }
28    };
29}
30
31/// Generates newtypes for the non-flag, enum constants exposed by [object].
32/// Each type has automatically generated [Debug] and [Display] implementations.
33/// Constants not (yet) defined by [object] can be given literal values.
34macro_rules! elf_constant_newtype {
35    (
36        $name:ident,
37        $inner_type:ident,
38        $constants_module:ident,
39        $prefix:ident,
40        $(
41            $const:ident $(= $value:expr)?
42        ),* $(,)?
43    ) => {
44        #[derive(Clone, Copy, derive_more::Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
45        #[debug("{}", self.as_str())]
46        pub struct $name($inner_type);
47
48        impl $name {
49            #[must_use]
50            pub fn raw(&self) -> $inner_type {
51                self.0
52            }
53
54            #[allow(unreachable_patterns)] // rustc issues a spurious warning here
55            #[must_use]
56            pub fn as_str(&self) -> Cow<'static, str> {
57                    match self.0 {
58                        $(
59                            const_or_literal!($prefix $const $(= $value )?)
60                                => ::std::borrow::Cow::Borrowed(stringify!($const)),
61                        )*
62                        r => Cow::Owned(format!("Unknown({r})")),
63                    }
64            }
65
66            ::paste::paste! {
67                #[must_use]
68                pub const fn [<from_ $inner_type>](value: $inner_type) -> Self {
69                    Self(value)
70                }
71            }
72        }
73
74        impl From < $inner_type > for $name {
75            fn from(value: $inner_type) -> Self {
76                Self(value)
77            }
78        }
79
80        impl std::fmt::Display for $name {
81            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82                write!(f, "{}", self.as_str())
83            }
84        }
85
86        pub mod $constants_module {
87            #![allow(non_upper_case_globals)]
88            use super::$name;
89
90            $(pub const $const: $name = $name(const_or_literal!($prefix $const $(= $value)?));)*
91        }
92    };
93}
94
95elf_constant_newtype!(
96    SegmentType,
97    u32,
98    pt,
99    PT,
100    NULL,
101    LOAD,
102    DYNAMIC,
103    INTERP,
104    NOTE,
105    SHLIB,
106    PHDR,
107    TLS,
108    GNU_EH_FRAME,
109    GNU_STACK,
110    GNU_RELRO,
111    GNU_PROPERTY,
112    GNU_SFRAME,
113    RISCV_ATTRIBUTES,
114);
115
116impl SegmentType {
117    #[must_use]
118    pub fn from_header(header: &object::elf::ProgramHeader64<LittleEndian>) -> Self {
119        Self(header.p_type(LittleEndian))
120    }
121}
122
123elf_constant_newtype!(
124    SectionType,
125    u32,
126    sht,
127    SHT,
128    NULL,
129    PROGBITS,
130    SYMTAB,
131    STRTAB,
132    RELA,
133    RELR,
134    HASH,
135    DYNAMIC,
136    NOTE,
137    NOBITS,
138    REL,
139    SHLIB,
140    DYNSYM,
141    INIT_ARRAY,
142    FINI_ARRAY,
143    PREINIT_ARRAY,
144    GROUP,
145    SYMTAB_SHNDX,
146    LOOS,
147    GNU_SFRAME,
148    GNU_ATTRIBUTES,
149    GNU_HASH,
150    GNU_LIBLIST,
151    CHECKSUM,
152    LOSUNW,
153    SUNW_COMDAT,
154    SUNW_syminfo,
155    GNU_VERDEF,
156    GNU_VERNEED,
157    GNU_VERSYM,
158    HISUNW,
159    HIOS,
160    LOPROC,
161    HIPROC,
162    LOUSER,
163    HIUSER,
164    RISCV_ATTRIBUTES,
165);
166
167impl SectionType {
168    #[must_use]
169    pub fn from_header(header: &object::elf::SectionHeader64<LittleEndian>) -> Self {
170        Self(header.sh_type(LittleEndian))
171    }
172}
173
174elf_constant_newtype!(SymbolType, u8, stt, STT, NOTYPE, TLS);
175
176#[must_use]
177pub fn x86_64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
178    if let Some(name) = const_name_by_value![
179        r_type,
180        R_X86_64_NONE,
181        R_X86_64_64,
182        R_X86_64_PC32,
183        R_X86_64_GOT32,
184        R_X86_64_PLT32,
185        R_X86_64_COPY,
186        R_X86_64_GLOB_DAT,
187        R_X86_64_JUMP_SLOT,
188        R_X86_64_RELATIVE,
189        R_X86_64_GOTPCREL,
190        R_X86_64_32,
191        R_X86_64_32S,
192        R_X86_64_16,
193        R_X86_64_PC16,
194        R_X86_64_8,
195        R_X86_64_PC8,
196        R_X86_64_DTPMOD64,
197        R_X86_64_DTPOFF64,
198        R_X86_64_TPOFF64,
199        R_X86_64_TLSGD,
200        R_X86_64_TLSLD,
201        R_X86_64_DTPOFF32,
202        R_X86_64_GOTTPOFF,
203        R_X86_64_TPOFF32,
204        R_X86_64_PC64,
205        R_X86_64_GOTOFF64,
206        R_X86_64_GOTPC32,
207        R_X86_64_GOT64,
208        R_X86_64_GOTPCREL64,
209        R_X86_64_GOTPC64,
210        R_X86_64_GOTPLT64,
211        R_X86_64_PLTOFF64,
212        R_X86_64_SIZE32,
213        R_X86_64_SIZE64,
214        R_X86_64_GOTPC32_TLSDESC,
215        R_X86_64_TLSDESC_CALL,
216        R_X86_64_TLSDESC,
217        R_X86_64_IRELATIVE,
218        R_X86_64_RELATIVE64,
219        R_X86_64_GOTPCRELX,
220        R_X86_64_REX_GOTPCRELX,
221        R_X86_64_CODE_4_GOTPCRELX,
222        R_X86_64_CODE_4_GOTTPOFF,
223        R_X86_64_CODE_4_GOTPC32_TLSDESC,
224        R_X86_64_CODE_5_GOTPCRELX,
225        R_X86_64_CODE_5_GOTTPOFF,
226        R_X86_64_CODE_5_GOTPC32_TLSDESC,
227        R_X86_64_CODE_6_GOTPCRELX,
228        R_X86_64_CODE_6_GOTTPOFF,
229        R_X86_64_CODE_6_GOTPC32_TLSDESC,
230    ] {
231        Cow::Borrowed(name)
232    } else {
233        Cow::Owned(format!("Unknown x86_64 relocation type 0x{r_type:x}"))
234    }
235}
236
237#[must_use]
238pub fn aarch64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
239    if let Some(name) = const_name_by_value![
240        r_type,
241        R_AARCH64_NONE,
242        R_AARCH64_P32_ABS32,
243        R_AARCH64_P32_COPY,
244        R_AARCH64_P32_GLOB_DAT,
245        R_AARCH64_P32_JUMP_SLOT,
246        R_AARCH64_P32_RELATIVE,
247        R_AARCH64_P32_TLS_DTPMOD,
248        R_AARCH64_P32_TLS_DTPREL,
249        R_AARCH64_P32_TLS_TPREL,
250        R_AARCH64_P32_TLSDESC,
251        R_AARCH64_P32_IRELATIVE,
252        R_AARCH64_ABS64,
253        R_AARCH64_ABS32,
254        R_AARCH64_ABS16,
255        R_AARCH64_PREL64,
256        R_AARCH64_PREL32,
257        R_AARCH64_PREL16,
258        R_AARCH64_MOVW_UABS_G0,
259        R_AARCH64_MOVW_UABS_G0_NC,
260        R_AARCH64_MOVW_UABS_G1,
261        R_AARCH64_MOVW_UABS_G1_NC,
262        R_AARCH64_MOVW_UABS_G2,
263        R_AARCH64_MOVW_UABS_G2_NC,
264        R_AARCH64_MOVW_UABS_G3,
265        R_AARCH64_MOVW_SABS_G0,
266        R_AARCH64_MOVW_SABS_G1,
267        R_AARCH64_MOVW_SABS_G2,
268        R_AARCH64_LD_PREL_LO19,
269        R_AARCH64_ADR_PREL_LO21,
270        R_AARCH64_ADR_PREL_PG_HI21,
271        R_AARCH64_ADR_PREL_PG_HI21_NC,
272        R_AARCH64_ADD_ABS_LO12_NC,
273        R_AARCH64_LDST8_ABS_LO12_NC,
274        R_AARCH64_TSTBR14,
275        R_AARCH64_CONDBR19,
276        R_AARCH64_JUMP26,
277        R_AARCH64_CALL26,
278        R_AARCH64_LDST16_ABS_LO12_NC,
279        R_AARCH64_LDST32_ABS_LO12_NC,
280        R_AARCH64_LDST64_ABS_LO12_NC,
281        R_AARCH64_MOVW_PREL_G0,
282        R_AARCH64_MOVW_PREL_G0_NC,
283        R_AARCH64_MOVW_PREL_G1,
284        R_AARCH64_MOVW_PREL_G1_NC,
285        R_AARCH64_MOVW_PREL_G2,
286        R_AARCH64_MOVW_PREL_G2_NC,
287        R_AARCH64_MOVW_PREL_G3,
288        R_AARCH64_LDST128_ABS_LO12_NC,
289        R_AARCH64_MOVW_GOTOFF_G0,
290        R_AARCH64_MOVW_GOTOFF_G0_NC,
291        R_AARCH64_MOVW_GOTOFF_G1,
292        R_AARCH64_MOVW_GOTOFF_G1_NC,
293        R_AARCH64_MOVW_GOTOFF_G2,
294        R_AARCH64_MOVW_GOTOFF_G2_NC,
295        R_AARCH64_MOVW_GOTOFF_G3,
296        R_AARCH64_GOTREL64,
297        R_AARCH64_GOTREL32,
298        R_AARCH64_GOT_LD_PREL19,
299        R_AARCH64_LD64_GOTOFF_LO15,
300        R_AARCH64_ADR_GOT_PAGE,
301        R_AARCH64_LD64_GOT_LO12_NC,
302        R_AARCH64_LD64_GOTPAGE_LO15,
303        R_AARCH64_PLT32,
304        R_AARCH64_GOTPCREL32,
305        R_AARCH64_TLSGD_ADR_PREL21,
306        R_AARCH64_TLSGD_ADR_PAGE21,
307        R_AARCH64_TLSGD_ADD_LO12_NC,
308        R_AARCH64_TLSGD_MOVW_G1,
309        R_AARCH64_TLSGD_MOVW_G0_NC,
310        R_AARCH64_TLSLD_ADR_PREL21,
311        R_AARCH64_TLSLD_ADR_PAGE21,
312        R_AARCH64_TLSLD_ADD_LO12_NC,
313        R_AARCH64_TLSLD_MOVW_G1,
314        R_AARCH64_TLSLD_MOVW_G0_NC,
315        R_AARCH64_TLSLD_LD_PREL19,
316        R_AARCH64_TLSLD_MOVW_DTPREL_G2,
317        R_AARCH64_TLSLD_MOVW_DTPREL_G1,
318        R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC,
319        R_AARCH64_TLSLD_MOVW_DTPREL_G0,
320        R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC,
321        R_AARCH64_TLSLD_ADD_DTPREL_HI12,
322        R_AARCH64_TLSLD_ADD_DTPREL_LO12,
323        R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC,
324        R_AARCH64_TLSLD_LDST8_DTPREL_LO12,
325        R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC,
326        R_AARCH64_TLSLD_LDST16_DTPREL_LO12,
327        R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC,
328        R_AARCH64_TLSLD_LDST32_DTPREL_LO12,
329        R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC,
330        R_AARCH64_TLSLD_LDST64_DTPREL_LO12,
331        R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC,
332        R_AARCH64_TLSIE_MOVW_GOTTPREL_G1,
333        R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC,
334        R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21,
335        R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC,
336        R_AARCH64_TLSIE_LD_GOTTPREL_PREL19,
337        R_AARCH64_TLSLE_MOVW_TPREL_G2,
338        R_AARCH64_TLSLE_MOVW_TPREL_G1,
339        R_AARCH64_TLSLE_MOVW_TPREL_G1_NC,
340        R_AARCH64_TLSLE_MOVW_TPREL_G0,
341        R_AARCH64_TLSLE_MOVW_TPREL_G0_NC,
342        R_AARCH64_TLSLE_ADD_TPREL_HI12,
343        R_AARCH64_TLSLE_ADD_TPREL_LO12,
344        R_AARCH64_TLSLE_ADD_TPREL_LO12_NC,
345        R_AARCH64_TLSLE_LDST8_TPREL_LO12,
346        R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC,
347        R_AARCH64_TLSLE_LDST16_TPREL_LO12,
348        R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC,
349        R_AARCH64_TLSLE_LDST32_TPREL_LO12,
350        R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC,
351        R_AARCH64_TLSLE_LDST64_TPREL_LO12,
352        R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC,
353        R_AARCH64_TLSDESC_LD_PREL19,
354        R_AARCH64_TLSDESC_ADR_PREL21,
355        R_AARCH64_TLSDESC_ADR_PAGE21,
356        R_AARCH64_TLSDESC_LD64_LO12,
357        R_AARCH64_TLSDESC_ADD_LO12,
358        R_AARCH64_TLSDESC_OFF_G1,
359        R_AARCH64_TLSDESC_OFF_G0_NC,
360        R_AARCH64_TLSDESC_LDR,
361        R_AARCH64_TLSDESC_ADD,
362        R_AARCH64_TLSDESC_CALL,
363        R_AARCH64_TLSLE_LDST128_TPREL_LO12,
364        R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC,
365        R_AARCH64_TLSLD_LDST128_DTPREL_LO12,
366        R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC,
367        R_AARCH64_COPY,
368        R_AARCH64_GLOB_DAT,
369        R_AARCH64_JUMP_SLOT,
370        R_AARCH64_RELATIVE,
371        R_AARCH64_TLS_DTPMOD,
372        R_AARCH64_TLS_DTPREL,
373        R_AARCH64_TLS_TPREL,
374        R_AARCH64_TLSDESC,
375        R_AARCH64_IRELATIVE,
376    ] {
377        Cow::Borrowed(name)
378    } else {
379        Cow::Owned(format!("Unknown aarch64 relocation type 0x{r_type:x}"))
380    }
381}
382
383#[must_use]
384pub fn riscv64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
385    if let Some(name) = const_name_by_value![
386        r_type,
387        R_RISCV_NONE,
388        R_RISCV_32,
389        R_RISCV_64,
390        R_RISCV_RELATIVE,
391        R_RISCV_COPY,
392        R_RISCV_JUMP_SLOT,
393        R_RISCV_TLS_DTPMOD32,
394        R_RISCV_TLS_DTPMOD64,
395        R_RISCV_TLS_DTPREL32,
396        R_RISCV_TLS_DTPREL64,
397        R_RISCV_TLS_TPREL32,
398        R_RISCV_TLS_TPREL64,
399        R_RISCV_TLSDESC,
400        R_RISCV_BRANCH,
401        R_RISCV_JAL,
402        R_RISCV_CALL,
403        R_RISCV_CALL_PLT,
404        R_RISCV_GOT_HI20,
405        R_RISCV_TLS_GOT_HI20,
406        R_RISCV_TLS_GD_HI20,
407        R_RISCV_PCREL_HI20,
408        R_RISCV_PCREL_LO12_I,
409        R_RISCV_PCREL_LO12_S,
410        R_RISCV_HI20,
411        R_RISCV_LO12_I,
412        R_RISCV_LO12_S,
413        R_RISCV_TPREL_HI20,
414        R_RISCV_TPREL_LO12_I,
415        R_RISCV_TPREL_LO12_S,
416        R_RISCV_TPREL_ADD,
417        R_RISCV_ADD8,
418        R_RISCV_ADD16,
419        R_RISCV_ADD32,
420        R_RISCV_ADD64,
421        R_RISCV_SUB8,
422        R_RISCV_SUB16,
423        R_RISCV_SUB32,
424        R_RISCV_SUB64,
425        R_RISCV_GOT32_PCREL,
426        R_RISCV_ALIGN,
427        R_RISCV_RVC_BRANCH,
428        R_RISCV_RVC_JUMP,
429        R_RISCV_RVC_LUI,
430        R_RISCV_GPREL_I,
431        R_RISCV_GPREL_S,
432        R_RISCV_TPREL_I,
433        R_RISCV_TPREL_S,
434        R_RISCV_RELAX,
435        R_RISCV_SUB6,
436        R_RISCV_SET6,
437        R_RISCV_SET8,
438        R_RISCV_SET16,
439        R_RISCV_SET32,
440        R_RISCV_32_PCREL,
441        R_RISCV_IRELATIVE,
442        R_RISCV_PLT32,
443        R_RISCV_SET_ULEB128,
444        R_RISCV_SUB_ULEB128,
445        R_RISCV_TLSDESC_HI20,
446        R_RISCV_TLSDESC_LOAD_LO12,
447        R_RISCV_TLSDESC_ADD_LO12,
448        R_RISCV_TLSDESC_CALL,
449    ] {
450        Cow::Borrowed(name)
451    } else {
452        Cow::Owned(format!("Unknown riscv64 relocation type 0x{r_type:x}"))
453    }
454}
455
456#[must_use]
457pub fn loongarch64_rel_type_to_string(r_type: u32) -> Cow<'static, str> {
458    if let Some(name) = const_name_by_value![
459        r_type,
460        R_LARCH_32,
461        R_LARCH_64,
462        R_LARCH_B16,
463        R_LARCH_CFA,
464        R_LARCH_B21,
465        R_LARCH_B26,
466        R_LARCH_NONE,
467        R_LARCH_ADD6,
468        R_LARCH_SUB8,
469        R_LARCH_COPY,
470        R_LARCH_ADD8,
471        R_LARCH_SUB6,
472        R_LARCH_ADD16,
473        R_LARCH_ADD64,
474        R_LARCH_SUB32,
475        R_LARCH_ADD24,
476        R_LARCH_ADD32,
477        R_LARCH_SUB16,
478        R_LARCH_SUB24,
479        R_LARCH_SOP_SL,
480        R_LARCH_SOP_SR,
481        R_LARCH_SUB64,
482        R_LARCH_RELAX,
483        R_LARCH_ALIGN,
484        R_LARCH_SOP_SUB,
485        R_LARCH_SOP_ADD,
486        R_LARCH_SOP_AND,
487        R_LARCH_MARK_LA,
488        R_LARCH_CALL36,
489        R_LARCH_SOP_NOT,
490        R_LARCH_DELETE,
491        R_LARCH_GOT_HI20,
492        R_LARCH_GOT_LO12,
493        R_LARCH_32_PCREL,
494        R_LARCH_64_PCREL,
495        R_LARCH_ABS_HI20,
496        R_LARCH_ABS_LO12,
497        R_LARCH_JUMP_SLOT,
498        R_LARCH_RELATIVE,
499        R_LARCH_PCREL20_S2,
500        R_LARCH_ABS64_HI12,
501        R_LARCH_ABS64_LO20,
502        R_LARCH_TLS_LD_HI20,
503        R_LARCH_GOT64_HI12,
504        R_LARCH_GOT64_LO20,
505        R_LARCH_TLS_LE_LO12,
506        R_LARCH_GOT_PC_LO12,
507        R_LARCH_TLS_LE_ADD_R,
508        R_LARCH_SOP_POP_32_U,
509        R_LARCH_SOP_IF_ELSE,
510        R_LARCH_TLS_DESC_LD,
511        R_LARCH_SOP_ASSERT,
512        R_LARCH_MARK_PCREL,
513        R_LARCH_PCALA_HI20,
514        R_LARCH_PCALA_LO12,
515        R_LARCH_GOT_PC_HI20,
516        R_LARCH_TLS_LE_HI20,
517        R_LARCH_IRELATIVE,
518        R_LARCH_TLS_GD_HI20,
519        R_LARCH_TLS_IE_HI20,
520        R_LARCH_TLS_IE_LO12,
521        R_LARCH_SOP_PUSH_DUP,
522        R_LARCH_TLS_TPREL32,
523        R_LARCH_TLS_LE_LO12_R,
524        R_LARCH_TLS_TPREL64,
525        R_LARCH_TLS_LE_HI20_R,
526        R_LARCH_GNU_VTENTRY,
527        R_LARCH_SUB_ULEB128,
528        R_LARCH_ADD_ULEB128,
529        R_LARCH_TLS_DTPREL32,
530        R_LARCH_GOT64_PC_HI12,
531        R_LARCH_TLS_GD_PC_HI20,
532        R_LARCH_TLS_IE64_LO20,
533        R_LARCH_TLS_DESC_CALL,
534        R_LARCH_TLS_LE64_LO20,
535        R_LARCH_TLS_DTPMOD32,
536        R_LARCH_PCALA64_LO20,
537        R_LARCH_TLS_DTPMOD64,
538        R_LARCH_TLS_IE64_HI12,
539        R_LARCH_TLS_DTPREL64,
540        R_LARCH_TLS_DESC_HI20,
541        R_LARCH_GOT64_PC_LO20,
542        R_LARCH_TLS_IE_PC_HI20,
543        R_LARCH_TLS_IE_PC_LO12,
544        R_LARCH_TLS_DESC_LO12,
545        R_LARCH_TLS_LE64_HI12,
546        R_LARCH_TLS_LD_PC_HI20,
547        R_LARCH_PCALA64_HI12,
548        R_LARCH_SOP_POP_32_S_10_5,
549        R_LARCH_SOP_PUSH_PCREL,
550        R_LARCH_SOP_POP_32_S_5_20,
551        R_LARCH_SOP_PUSH_GPREL,
552        R_LARCH_SOP_PUSH_TLS_GD,
553        R_LARCH_GNU_VTINHERIT,
554        R_LARCH_TLS_IE64_PC_LO20,
555        R_LARCH_SOP_POP_32_S_10_12,
556        R_LARCH_TLS_DESC_PC_HI20,
557        R_LARCH_TLS_DESC_PC_LO12,
558        R_LARCH_SOP_POP_32_S_10_16,
559        R_LARCH_SOP_POP_32_U_10_12,
560        R_LARCH_TLS_DESC64_HI12,
561        R_LARCH_SOP_PUSH_TLS_GOT,
562        R_LARCH_TLS_IE64_PC_HI12,
563        R_LARCH_TLS_DESC64_LO20,
564        R_LARCH_TLS_LD_PCREL20_S2,
565        R_LARCH_TLS_GD_PCREL20_S2,
566        R_LARCH_TLS_DESC64_PC_HI12,
567        R_LARCH_SOP_PUSH_ABSOLUTE,
568        R_LARCH_TLS_DESC64_PC_LO20,
569        R_LARCH_SOP_PUSH_PLT_PCREL,
570        R_LARCH_SOP_PUSH_TLS_TPREL,
571        R_LARCH_SOP_POP_32_S_10_16_S2,
572        R_LARCH_TLS_DESC_PCREL20_S2,
573        R_LARCH_SOP_POP_32_S_0_5_10_16_S2,
574        R_LARCH_SOP_POP_32_S_0_10_10_16_S2,
575    ] {
576        Cow::Borrowed(name)
577    } else {
578        Cow::Owned(format!("Unknown loongarch relocation type 0x{r_type:x}"))
579    }
580}
581
582/// Section flag bit values.
583pub mod shf {
584    use super::SectionFlags;
585
586    pub const WRITE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_WRITE);
587    pub const ALLOC: SectionFlags = SectionFlags::from_u32(object::elf::SHF_ALLOC);
588    pub const EXECINSTR: SectionFlags = SectionFlags::from_u32(object::elf::SHF_EXECINSTR);
589    pub const MERGE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_MERGE);
590    pub const STRINGS: SectionFlags = SectionFlags::from_u32(object::elf::SHF_STRINGS);
591    pub const INFO_LINK: SectionFlags = SectionFlags::from_u32(object::elf::SHF_INFO_LINK);
592    pub const LINK_ORDER: SectionFlags = SectionFlags::from_u32(object::elf::SHF_LINK_ORDER);
593    pub const OS_NONCONFORMING: SectionFlags =
594        SectionFlags::from_u32(object::elf::SHF_OS_NONCONFORMING);
595    pub const GROUP: SectionFlags = SectionFlags::from_u32(object::elf::SHF_GROUP);
596    pub const TLS: SectionFlags = SectionFlags::from_u32(object::elf::SHF_TLS);
597    pub const COMPRESSED: SectionFlags = SectionFlags::from_u32(object::elf::SHF_COMPRESSED);
598    pub const GNU_RETAIN: SectionFlags = SectionFlags::from_u32(object::elf::SHF_GNU_RETAIN);
599    pub const EXCLUDE: SectionFlags = SectionFlags::from_u32(object::elf::SHF_EXCLUDE);
600}
601
602#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
603pub struct SectionFlags(u32);
604
605impl SectionFlags {
606    #[must_use]
607    pub const fn empty() -> Self {
608        Self(0)
609    }
610
611    #[must_use]
612    pub fn from_header(header: &object::elf::SectionHeader64<LittleEndian>) -> Self {
613        Self(header.sh_flags(LittleEndian) as u32)
614    }
615
616    #[must_use]
617    pub fn contains(self, flag: SectionFlags) -> bool {
618        self.0 & flag.0 != 0
619    }
620
621    #[must_use]
622    pub const fn from_u32(raw: u32) -> SectionFlags {
623        SectionFlags(raw)
624    }
625
626    /// Returns self with the specified flags set.
627    #[must_use]
628    pub const fn with(self, flags: SectionFlags) -> SectionFlags {
629        SectionFlags(self.0 | flags.0)
630    }
631
632    /// Returns self with the specified flags cleared.
633    #[must_use]
634    pub const fn without(self, flags: SectionFlags) -> SectionFlags {
635        SectionFlags(self.0 & !flags.0)
636    }
637
638    #[must_use]
639    pub const fn raw(self) -> u64 {
640        self.0 as u64
641    }
642
643    #[must_use]
644    pub fn should_exclude(&self) -> bool {
645        self.contains(shf::EXCLUDE)
646    }
647}
648
649impl From<u64> for SectionFlags {
650    fn from(value: u64) -> Self {
651        Self(value as u32)
652    }
653}
654
655impl std::fmt::Display for SectionFlags {
656    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
657        for (flag, ch) in [
658            (shf::WRITE, "W"),
659            (shf::ALLOC, "A"),
660            (shf::EXECINSTR, "X"),
661            (shf::MERGE, "M"),
662            (shf::STRINGS, "S"),
663            (shf::INFO_LINK, "I"),
664            (shf::LINK_ORDER, "L"),
665            (shf::OS_NONCONFORMING, "O"),
666            (shf::GROUP, "G"),
667            (shf::TLS, "T"),
668            (shf::COMPRESSED, "C"),
669            (shf::EXCLUDE, "E"),
670            // TODO: ld linker sometimes propagates the flag
671            // (shf::GNU_RETAIN, "R"),
672        ] {
673            if self.contains(flag) {
674                f.write_str(ch)?;
675            }
676        }
677        Ok(())
678    }
679}
680
681impl std::fmt::Debug for SectionFlags {
682    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
683        std::fmt::Display::fmt(&self, f)
684    }
685}
686
687impl std::ops::BitOrAssign for SectionFlags {
688    fn bitor_assign(&mut self, rhs: Self) {
689        self.0 |= rhs.0;
690    }
691}
692
693impl std::ops::BitAnd for SectionFlags {
694    type Output = SectionFlags;
695
696    fn bitand(self, rhs: Self) -> Self::Output {
697        Self(self.0 & rhs.0)
698    }
699}
700
701pub mod secnames {
702    pub const FILEHEADER_SECTION_NAME_STR: &str = "";
703    pub const FILEHEADER_SECTION_NAME: &[u8] = FILEHEADER_SECTION_NAME_STR.as_bytes();
704    pub const RODATA_SECTION_NAME_STR: &str = ".rodata";
705    pub const RODATA_SECTION_NAME: &[u8] = RODATA_SECTION_NAME_STR.as_bytes();
706    pub const TEXT_SECTION_NAME_STR: &str = ".text";
707    pub const TEXT_SECTION_NAME: &[u8] = TEXT_SECTION_NAME_STR.as_bytes();
708    pub const CTORS_SECTION_NAME_STR: &str = ".ctors";
709    pub const CTORS_SECTION_NAME: &[u8] = CTORS_SECTION_NAME_STR.as_bytes();
710    pub const DTORS_SECTION_NAME_STR: &str = ".dtors";
711    pub const DTORS_SECTION_NAME: &[u8] = DTORS_SECTION_NAME_STR.as_bytes();
712    pub const INIT_ARRAY_SECTION_NAME_STR: &str = ".init_array";
713    pub const INIT_ARRAY_SECTION_NAME: &[u8] = INIT_ARRAY_SECTION_NAME_STR.as_bytes();
714    pub const FINI_ARRAY_SECTION_NAME_STR: &str = ".fini_array";
715    pub const FINI_ARRAY_SECTION_NAME: &[u8] = FINI_ARRAY_SECTION_NAME_STR.as_bytes();
716    pub const PREINIT_ARRAY_SECTION_NAME_STR: &str = ".preinit_array";
717    pub const PREINIT_ARRAY_SECTION_NAME: &[u8] = PREINIT_ARRAY_SECTION_NAME_STR.as_bytes();
718    pub const DATA_SECTION_NAME_STR: &str = ".data";
719    pub const DATA_SECTION_NAME: &[u8] = DATA_SECTION_NAME_STR.as_bytes();
720    pub const EH_FRAME_SECTION_NAME_STR: &str = ".eh_frame";
721    pub const EH_FRAME_SECTION_NAME: &[u8] = EH_FRAME_SECTION_NAME_STR.as_bytes();
722    pub const EH_FRAME_HDR_SECTION_NAME_STR: &str = ".eh_frame_hdr";
723    pub const EH_FRAME_HDR_SECTION_NAME: &[u8] = EH_FRAME_HDR_SECTION_NAME_STR.as_bytes();
724    pub const SFRAME_SECTION_NAME_STR: &str = ".sframe";
725    pub const SFRAME_SECTION_NAME: &[u8] = SFRAME_SECTION_NAME_STR.as_bytes();
726    pub const SHSTRTAB_SECTION_NAME_STR: &str = ".shstrtab";
727    pub const SHSTRTAB_SECTION_NAME: &[u8] = SHSTRTAB_SECTION_NAME_STR.as_bytes();
728    pub const SYMTAB_SECTION_NAME_STR: &str = ".symtab";
729    pub const SYMTAB_SECTION_NAME: &[u8] = SYMTAB_SECTION_NAME_STR.as_bytes();
730    pub const STRTAB_SECTION_NAME_STR: &str = ".strtab";
731    pub const STRTAB_SECTION_NAME: &[u8] = STRTAB_SECTION_NAME_STR.as_bytes();
732    pub const TDATA_SECTION_NAME_STR: &str = ".tdata";
733    pub const TDATA_SECTION_NAME: &[u8] = TDATA_SECTION_NAME_STR.as_bytes();
734    pub const TBSS_SECTION_NAME_STR: &str = ".tbss";
735    pub const TBSS_SECTION_NAME: &[u8] = TBSS_SECTION_NAME_STR.as_bytes();
736    pub const BSS_SECTION_NAME_STR: &str = ".bss";
737    pub const BSS_SECTION_NAME: &[u8] = BSS_SECTION_NAME_STR.as_bytes();
738    pub const GOT_SECTION_NAME_STR: &str = ".got";
739    pub const GOT_SECTION_NAME: &[u8] = GOT_SECTION_NAME_STR.as_bytes();
740    pub const INIT_SECTION_NAME_STR: &str = ".init";
741    pub const INIT_SECTION_NAME: &[u8] = INIT_SECTION_NAME_STR.as_bytes();
742    pub const FINI_SECTION_NAME_STR: &str = ".fini";
743    pub const FINI_SECTION_NAME: &[u8] = FINI_SECTION_NAME_STR.as_bytes();
744    pub const RELA_SECTION_NAME_STR: &str = ".rela";
745    pub const RELA_SECTION_NAME: &[u8] = RELA_SECTION_NAME_STR.as_bytes();
746    pub const CREL_SECTION_NAME_STR: &str = ".crel";
747    pub const CREL_SECTION_NAME: &[u8] = CREL_SECTION_NAME_STR.as_bytes();
748    pub const RELA_PLT_SECTION_NAME_STR: &str = ".rela.plt";
749    pub const RELA_PLT_SECTION_NAME: &[u8] = RELA_PLT_SECTION_NAME_STR.as_bytes();
750    pub const COMMENT_SECTION_NAME_STR: &str = ".comment";
751    pub const COMMENT_SECTION_NAME: &[u8] = COMMENT_SECTION_NAME_STR.as_bytes();
752    pub const DYNAMIC_SECTION_NAME_STR: &str = ".dynamic";
753    pub const DYNAMIC_SECTION_NAME: &[u8] = DYNAMIC_SECTION_NAME_STR.as_bytes();
754    pub const DYNSYM_SECTION_NAME_STR: &str = ".dynsym";
755    pub const DYNSYM_SECTION_NAME: &[u8] = DYNSYM_SECTION_NAME_STR.as_bytes();
756    pub const DYNSTR_SECTION_NAME_STR: &str = ".dynstr";
757    pub const DYNSTR_SECTION_NAME: &[u8] = DYNSTR_SECTION_NAME_STR.as_bytes();
758    pub const RELA_DYN_SECTION_NAME_STR: &str = ".rela.dyn";
759    pub const RELA_DYN_SECTION_NAME: &[u8] = RELA_DYN_SECTION_NAME_STR.as_bytes();
760    pub const RELR_DYN_SECTION_NAME_STR: &str = ".relr.dyn";
761    pub const RELR_DYN_SECTION_NAME: &[u8] = RELR_DYN_SECTION_NAME_STR.as_bytes();
762    pub const GCC_EXCEPT_TABLE_SECTION_NAME_STR: &str = ".gcc_except_table";
763    pub const GCC_EXCEPT_TABLE_SECTION_NAME: &[u8] = GCC_EXCEPT_TABLE_SECTION_NAME_STR.as_bytes();
764    pub const INTERP_SECTION_NAME_STR: &str = ".interp";
765    pub const INTERP_SECTION_NAME: &[u8] = INTERP_SECTION_NAME_STR.as_bytes();
766    pub const GNU_VERSION_SECTION_NAME_STR: &str = ".gnu.version";
767    pub const GNU_VERSION_SECTION_NAME: &[u8] = GNU_VERSION_SECTION_NAME_STR.as_bytes();
768    pub const GNU_VERSION_D_SECTION_NAME_STR: &str = ".gnu.version_d";
769    pub const GNU_VERSION_D_SECTION_NAME: &[u8] = GNU_VERSION_D_SECTION_NAME_STR.as_bytes();
770    pub const GNU_VERSION_R_SECTION_NAME_STR: &str = ".gnu.version_r";
771    pub const GNU_VERSION_R_SECTION_NAME: &[u8] = GNU_VERSION_R_SECTION_NAME_STR.as_bytes();
772    pub const HASH_SECTION_NAME_STR: &str = ".hash";
773    pub const HASH_SECTION_NAME: &[u8] = HASH_SECTION_NAME_STR.as_bytes();
774    pub const PROGRAM_HEADERS_SECTION_NAME_STR: &str = ".phdr";
775    pub const PROGRAM_HEADERS_SECTION_NAME: &[u8] = PROGRAM_HEADERS_SECTION_NAME_STR.as_bytes();
776    pub const SECTION_HEADERS_SECTION_NAME_STR: &str = ".shdr";
777    pub const SECTION_HEADERS_SECTION_NAME: &[u8] = SECTION_HEADERS_SECTION_NAME_STR.as_bytes();
778    pub const GNU_HASH_SECTION_NAME_STR: &str = ".gnu.hash";
779    pub const GNU_HASH_SECTION_NAME: &[u8] = GNU_HASH_SECTION_NAME_STR.as_bytes();
780    pub const PLT_SECTION_NAME_STR: &str = ".plt";
781    pub const PLT_SECTION_NAME: &[u8] = PLT_SECTION_NAME_STR.as_bytes();
782    pub const IPLT_SECTION_NAME_STR: &str = ".iplt";
783    pub const IPLT_SECTION_NAME: &[u8] = IPLT_SECTION_NAME_STR.as_bytes();
784    pub const PLT_GOT_SECTION_NAME_STR: &str = ".plt.got";
785    pub const PLT_GOT_SECTION_NAME: &[u8] = PLT_GOT_SECTION_NAME_STR.as_bytes();
786    pub const GOT_PLT_SECTION_NAME_STR: &str = ".got.plt";
787    pub const GOT_PLT_SECTION_NAME: &[u8] = GOT_PLT_SECTION_NAME_STR.as_bytes();
788    pub const PLT_SEC_SECTION_NAME_STR: &str = ".plt.sec";
789    pub const PLT_SEC_SECTION_NAME: &[u8] = PLT_SEC_SECTION_NAME_STR.as_bytes();
790    pub const NOTE_ABI_TAG_SECTION_NAME_STR: &str = ".note.ABI-tag";
791    pub const NOTE_ABI_TAG_SECTION_NAME: &[u8] = NOTE_ABI_TAG_SECTION_NAME_STR.as_bytes();
792    pub const NOTE_GNU_PROPERTY_SECTION_NAME_STR: &str = ".note.gnu.property";
793    pub const NOTE_GNU_PROPERTY_SECTION_NAME: &[u8] = NOTE_GNU_PROPERTY_SECTION_NAME_STR.as_bytes();
794    pub const NOTE_GNU_BUILD_ID_SECTION_NAME_STR: &str = ".note.gnu.build-id";
795    pub const NOTE_GNU_BUILD_ID_SECTION_NAME: &[u8] = NOTE_GNU_BUILD_ID_SECTION_NAME_STR.as_bytes();
796    pub const NOTE_GNU_STACK_SECTION_NAME_STR: &str = ".note.GNU-stack";
797    pub const NOTE_GNU_STACK_SECTION_NAME: &[u8] = NOTE_GNU_STACK_SECTION_NAME_STR.as_bytes();
798    pub const DEBUG_LOC_SECTION_NAME_STR: &str = ".debug_loc";
799    pub const DEBUG_LOC_SECTION_NAME: &[u8] = DEBUG_LOC_SECTION_NAME_STR.as_bytes();
800    pub const DEBUG_RANGES_SECTION_NAME_STR: &str = ".debug_ranges";
801    pub const DEBUG_RANGES_SECTION_NAME: &[u8] = DEBUG_RANGES_SECTION_NAME_STR.as_bytes();
802    pub const GROUP_SECTION_NAME_STR: &str = ".group";
803    pub const GROUP_SECTION_NAME: &[u8] = GROUP_SECTION_NAME_STR.as_bytes();
804    pub const DATA_REL_RO_SECTION_NAME_STR: &str = ".data.rel.ro";
805    pub const DATA_REL_RO_SECTION_NAME: &[u8] = DATA_REL_RO_SECTION_NAME_STR.as_bytes();
806    pub const RISCV_ATTRIBUTES_SECTION_NAME_STR: &str = ".riscv.attributes";
807    pub const RISCV_ATTRIBUTES_SECTION_NAME: &[u8] = RISCV_ATTRIBUTES_SECTION_NAME_STR.as_bytes();
808    pub const RELRO_PADDING_SECTION_NAME_STR: &str = ".relro_padding";
809    pub const RELRO_PADDING_SECTION_NAME: &[u8] = RELRO_PADDING_SECTION_NAME_STR.as_bytes();
810    pub const SYMTAB_SHNDX_SECTION_NAME_STR: &str = ".symtab_shndx";
811    pub const SYMTAB_SHNDX_SECTION_NAME: &[u8] = SYMTAB_SHNDX_SECTION_NAME_STR.as_bytes();
812
813    pub const GNU_LTO_SYMTAB_PREFIX: &str = ".gnu.lto_.symtab";
814}
815
816#[derive(Clone, Copy, PartialEq, Eq)]
817pub struct SegmentFlags(u32);
818
819impl SegmentFlags {
820    #[must_use]
821    pub const fn empty() -> Self {
822        Self(0)
823    }
824
825    #[must_use]
826    pub fn from_header(header: &object::elf::ProgramHeader64<LittleEndian>) -> Self {
827        Self(header.p_flags(LittleEndian))
828    }
829
830    #[must_use]
831    pub fn contains(self, flag: SegmentFlags) -> bool {
832        self.0 & flag.0 != 0
833    }
834
835    #[must_use]
836    pub const fn from_u32(raw: u32) -> SegmentFlags {
837        SegmentFlags(raw)
838    }
839
840    /// Returns self with the specified flags set.
841    #[must_use]
842    pub const fn with(self, flags: SegmentFlags) -> SegmentFlags {
843        SegmentFlags(self.0 | flags.0)
844    }
845
846    /// Returns self with the specified flags cleared.
847    #[must_use]
848    pub const fn without(self, flags: SegmentFlags) -> SegmentFlags {
849        SegmentFlags(self.0 & !flags.0)
850    }
851
852    #[must_use]
853    pub const fn raw(self) -> u32 {
854        self.0
855    }
856}
857
858pub mod pf {
859    use super::SegmentFlags;
860
861    pub const EXECUTABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_X);
862    pub const WRITABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_W);
863    pub const READABLE: SegmentFlags = SegmentFlags::from_u32(object::elf::PF_R);
864}
865
866impl std::fmt::Display for SegmentFlags {
867    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
868        if self.contains(pf::WRITABLE) {
869            f.write_str("W")?;
870        }
871        if self.contains(pf::READABLE) {
872            f.write_str("R")?;
873        }
874        if self.contains(pf::EXECUTABLE) {
875            f.write_str("X")?;
876        }
877        Ok(())
878    }
879}
880
881impl std::fmt::Debug for SegmentFlags {
882    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
883        std::fmt::Display::fmt(&self, f)
884    }
885}
886
887impl std::ops::BitOrAssign for SegmentFlags {
888    fn bitor_assign(&mut self, rhs: Self) {
889        self.0 |= rhs.0;
890    }
891}
892
893impl std::ops::BitAnd for SegmentFlags {
894    type Output = SegmentFlags;
895
896    fn bitand(self, rhs: Self) -> Self::Output {
897        Self(self.0 & rhs.0)
898    }
899}
900
901// RISC-V related constants
902
903/// Dynamic thread vector pointers point 0x800 past the start of each TLS block.
904pub const RISCV_TLS_DTV_OFFSET: u64 = 0x800;
905
906pub const RISCV_ATTRIBUTE_VENDOR_NAME: &str = "riscv";
907
908// 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
909pub mod riscvattr {
910    // Attributes relate to whole file.
911    pub const TAG_RISCV_WHOLE_FILE: u64 = 1;
912    // Indicates the stack alignment requirement in bytes (ULEB128).
913    pub const TAG_RISCV_STACK_ALIGN: u64 = 4;
914    // Indicates the target architecture of this object (NTBS).
915    pub const TAG_RISCV_ARCH: u64 = 5;
916    // Indicates whether to impose unaligned memory accesses in code generation (ULEB128).
917    pub const TAG_RISCV_UNALIGNED_ACCESS: u64 = 6;
918    // Indicates the major version of the privileged specification (ULEB128, deprecated).
919    pub const TAG_RISCV_PRIV_SPEC: u64 = 8;
920    // Indicates the minor version of the privileged specification (ULEB128, deprecated).
921    pub const TAG_RISCV_PRIV_SPEC_MINOR: u64 = 10;
922    // Indicates the revision version of the privileged specification (ULEB128, deprecated).
923    pub const TAG_RISCV_PRIV_SPEC_REVISION: u64 = 12;
924    // Indicates which version of the atomics ABI is being used (ULEB128).
925    pub const TAG_RISCV_ATOMIC_ABI: u64 = 14;
926    // Indicates the usage definition of the X3 register (ULEB128).
927    pub const TAG_RISCV_X3_REG_USAGE: u64 = 16;
928}
929
930#[derive(Clone, Copy, Debug, PartialEq, Eq)]
931pub enum Sign {
932    Signed,
933    Unsigned,
934}
935
936/// For additional information on ELF relocation types, see "ELF-64 Object File Format" -
937/// <https://uclibc.org/docs/elf-64-gen.pdf>. For information on the TLS related relocations, see "ELF
938/// Handling For Thread-Local Storage" - <https://www.uclibc.org/docs/tls.pdf>.
939#[derive(Clone, Copy, Debug, PartialEq, Eq)]
940pub enum RelocationKind {
941    /// The absolute address of a symbol or section.
942    Absolute,
943
944    /// The absolute address of a symbol or section related to EH section.
945    AbsoluteSet,
946
947    /// The 6 low bits of an absolute address of a symbol or section.
948    AbsoluteSetWord6,
949
950    /// Add the absolute address of a symbol or section at the place of the relocation
951    /// to the value at the place.
952    AbsoluteAddition,
953
954    /// Add the absolute address of a symbol or section at the place of the relocation
955    /// to the value at the place (use WORD6 type for the operation)
956    AbsoluteAdditionWord6,
957
958    /// Subtract the absolute address of a symbol or section at the place of the relocation
959    /// from the value at the place.
960    AbsoluteSubtraction,
961
962    /// Subtract the absolute address of a symbol or section at the place of the relocation
963    /// from the value at the place (use WORD6 type for the operation)
964    AbsoluteSubtractionWord6,
965
966    /// The absolute address of a symbol or section. We are going to extract only the offset
967    /// within a page, so dynamic relocation creation must be skipped. Used by both AArch64
968    /// and LoongArch64 targets.
969    AbsoluteLowPart,
970
971    /// Subtract addresses of two symbols and encode the value using ULEB128.
972    ///
973    /// Note: The assembler must allocate sufficient space to accommodate the final value for the
974    /// R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128 relocation pair and fill the space with a
975    /// single ULEB128-encoded value. This is achieved by prepending the redundant 0x80 byte as
976    /// necessary. The linker must not alter the length of the ULEB128-encoded value.
977    PairSubtractionULEB128(u32),
978
979    /// The address of the symbol, relative to the place of the relocation.
980    Relative,
981
982    /// The address of the symbol, relative to the place of the relocation
983    /// (using LoongArch64 high part encoding).
984    RelativeLoongArchHigh,
985
986    /// The address of the symbol, relative to the place of the relocation. The address of the
987    /// relocation points to an instruction for which the R_RISCV_PCREL_HI20 relocation is used
988    /// and that is the place we make this relocation relative to.
989    RelativeRiscVLow12,
990
991    /// The address of the symbol, relative to the base address of the GOT.
992    SymRelGotBase,
993
994    /// The offset of the symbol's GOT entry, relative to the start of the GOT.
995    GotRelGotBase,
996
997    /// The address of the symbol's GOT entry.
998    Got,
999
1000    /// The address of the symbol's PLT entry, relative to the base address of the GOT.
1001    PltRelGotBase,
1002
1003    /// The address of the symbol's PLT entry, relative to the place of relocation.
1004    PltRelative,
1005
1006    /// The address of the symbol's GOT entry, relative to the place of the relocation.
1007    GotRelative,
1008
1009    /// The address of the symbol's GOT entry, relative to the place of the relocation
1010    /// (using LoongArch64 high part encoding).
1011    GotRelativeLoongArch64,
1012
1013    /// The address of a TLSGD structure, relative to the place of the relocation. A TLSGD
1014    /// (thread-local storage general dynamic) structure is a pair of values containing a module ID
1015    /// and the offset within that module's TLS storage.
1016    TlsGd,
1017
1018    /// The address of the symbol's TLSGD GOT entry.
1019    TlsGdGot,
1020
1021    /// The address of the symbol's TLSGD GOT entry, relative to the start of the GOT.
1022    TlsGdGotBase,
1023
1024    /// The address of the TLS module ID for the shared object that we're writing, relative to the
1025    /// place of the relocation. This is used when a TLS variable is defined and used within the
1026    /// same shared object.
1027    TlsLd,
1028
1029    /// The address of the TLS module ID for the shared object that we're writing.
1030    TlsLdGot,
1031
1032    /// The address of the TLS module ID for the shared object that we're writing,
1033    /// relative to the start of the GOT.
1034    TlsLdGotBase,
1035
1036    /// The offset of a thread-local within the TLS storage of DSO that defines that thread-local.
1037    DtpOff,
1038
1039    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
1040    /// TLS storage, relative to the place of the relocation.
1041    GotTpOff,
1042
1043    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
1044    /// TLS storage, relative to the place of the relocation.
1045    /// (using LoongArch64 high part encoding).
1046    GotTpOffLoongArch64,
1047
1048    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
1049    /// TLS storage.
1050    GotTpOffGot,
1051
1052    /// The address of a GOT entry containing the offset of a TLS variable within the executable's
1053    /// TLS storage, relative to the start of the GOT.
1054    GotTpOffGotBase,
1055
1056    /// The offset of a TLS variable within the executable's TLS storage.
1057    TpOff,
1058
1059    /// The address of a TLS descriptor structure, relative to the place of the relocation.
1060    TlsDesc,
1061
1062    /// The address of a TLS descriptor structure, relative to the place of the relocation.
1063    /// (using LoongArch64 high part encoding).
1064    TlsDescLoongArch64,
1065
1066    /// The address of a TLS descriptor structure.
1067    TlsDescGot,
1068
1069    /// The address of a TLS descriptor structure, relative to the start of the GOT.
1070    TlsDescGotBase,
1071
1072    /// Call to the TLS descriptor trampoline. Used only as a placeholder for a linker relaxation
1073    /// opportunity.
1074    TlsDescCall,
1075
1076    /// No relocation needs to be applied. Produced when we eliminate a relocation due to an
1077    /// optimisation.
1078    None,
1079
1080    /// The address must fulfill the alignment requirement.
1081    Alignment,
1082}
1083
1084impl RelocationKind {
1085    #[must_use]
1086    pub fn is_tls(self) -> bool {
1087        matches!(
1088            self,
1089            Self::DtpOff
1090                | Self::GotTpOff
1091                | Self::GotTpOffGotBase
1092                | Self::TlsDesc
1093                | Self::TlsDescCall
1094                | Self::TlsDescGot
1095                | Self::TlsDescGotBase
1096                | Self::TlsGd
1097                | Self::TlsGdGot
1098                | Self::TlsGdGotBase
1099                | Self::TlsLd
1100                | Self::TlsLdGot
1101                | Self::TlsLdGotBase
1102                | Self::TpOff
1103        )
1104    }
1105}
1106
1107#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1108pub enum DynamicRelocationKind {
1109    Copy,
1110    Irelative,
1111    DtpMod,
1112    DtpOff,
1113    TlsDesc,
1114    TpOff,
1115    Relative,
1116    Absolute,
1117    GotEntry,
1118    JumpSlot,
1119}
1120
1121impl DynamicRelocationKind {
1122    #[must_use]
1123    pub fn from_x86_64_r_type(r_type: u32) -> Option<Self> {
1124        let kind = match r_type {
1125            object::elf::R_X86_64_COPY => DynamicRelocationKind::Copy,
1126            object::elf::R_X86_64_IRELATIVE => DynamicRelocationKind::Irelative,
1127            object::elf::R_X86_64_DTPMOD64 => DynamicRelocationKind::DtpMod,
1128            object::elf::R_X86_64_DTPOFF64 => DynamicRelocationKind::DtpOff,
1129            object::elf::R_X86_64_TPOFF64 => DynamicRelocationKind::TpOff,
1130            object::elf::R_X86_64_RELATIVE => DynamicRelocationKind::Relative,
1131            object::elf::R_X86_64_GLOB_DAT => DynamicRelocationKind::GotEntry,
1132            object::elf::R_X86_64_64 => DynamicRelocationKind::Absolute,
1133            object::elf::R_X86_64_TLSDESC => DynamicRelocationKind::TlsDesc,
1134            object::elf::R_X86_64_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1135            _ => return None,
1136        };
1137
1138        Some(kind)
1139    }
1140
1141    #[must_use]
1142    pub fn x86_64_r_type(self) -> u32 {
1143        match self {
1144            DynamicRelocationKind::Copy => object::elf::R_X86_64_COPY,
1145            DynamicRelocationKind::Irelative => object::elf::R_X86_64_IRELATIVE,
1146            DynamicRelocationKind::DtpMod => object::elf::R_X86_64_DTPMOD64,
1147            DynamicRelocationKind::DtpOff => object::elf::R_X86_64_DTPOFF64,
1148            DynamicRelocationKind::TpOff => object::elf::R_X86_64_TPOFF64,
1149            DynamicRelocationKind::Relative => object::elf::R_X86_64_RELATIVE,
1150            DynamicRelocationKind::Absolute => object::elf::R_X86_64_64,
1151            DynamicRelocationKind::GotEntry => object::elf::R_X86_64_GLOB_DAT,
1152            DynamicRelocationKind::TlsDesc => object::elf::R_X86_64_TLSDESC,
1153            DynamicRelocationKind::JumpSlot => object::elf::R_X86_64_JUMP_SLOT,
1154        }
1155    }
1156
1157    #[must_use]
1158    pub fn from_aarch64_r_type(r_type: u32) -> Option<Self> {
1159        let kind = match r_type {
1160            object::elf::R_AARCH64_COPY => DynamicRelocationKind::Copy,
1161            object::elf::R_AARCH64_IRELATIVE => DynamicRelocationKind::Irelative,
1162            object::elf::R_AARCH64_TLS_DTPMOD => DynamicRelocationKind::DtpMod,
1163            object::elf::R_AARCH64_TLS_DTPREL => DynamicRelocationKind::DtpOff,
1164            object::elf::R_AARCH64_TLS_TPREL => DynamicRelocationKind::TpOff,
1165            object::elf::R_AARCH64_RELATIVE => DynamicRelocationKind::Relative,
1166            object::elf::R_AARCH64_ABS64 => DynamicRelocationKind::Absolute,
1167            object::elf::R_AARCH64_GLOB_DAT => DynamicRelocationKind::GotEntry,
1168            object::elf::R_AARCH64_TLSDESC => DynamicRelocationKind::TlsDesc,
1169            object::elf::R_AARCH64_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1170            _ => return None,
1171        };
1172
1173        Some(kind)
1174    }
1175
1176    #[must_use]
1177    pub fn aarch64_r_type(&self) -> u32 {
1178        match self {
1179            DynamicRelocationKind::Copy => object::elf::R_AARCH64_COPY,
1180            DynamicRelocationKind::Irelative => object::elf::R_AARCH64_IRELATIVE,
1181            DynamicRelocationKind::DtpMod => object::elf::R_AARCH64_TLS_DTPMOD,
1182            DynamicRelocationKind::DtpOff => object::elf::R_AARCH64_TLS_DTPREL,
1183            DynamicRelocationKind::TpOff => object::elf::R_AARCH64_TLS_TPREL,
1184            DynamicRelocationKind::Relative => object::elf::R_AARCH64_RELATIVE,
1185            DynamicRelocationKind::Absolute => object::elf::R_AARCH64_ABS64,
1186            DynamicRelocationKind::GotEntry => object::elf::R_AARCH64_GLOB_DAT,
1187            DynamicRelocationKind::TlsDesc => object::elf::R_AARCH64_TLSDESC,
1188            DynamicRelocationKind::JumpSlot => object::elf::R_AARCH64_JUMP_SLOT,
1189        }
1190    }
1191
1192    #[must_use]
1193    pub fn from_riscv64_r_type(r_type: u32) -> Option<Self> {
1194        let kind = match r_type {
1195            object::elf::R_RISCV_COPY => DynamicRelocationKind::Copy,
1196            object::elf::R_RISCV_IRELATIVE => DynamicRelocationKind::Irelative,
1197            object::elf::R_RISCV_TLS_DTPMOD64 => DynamicRelocationKind::DtpMod,
1198            object::elf::R_RISCV_TLS_DTPREL64 => DynamicRelocationKind::DtpOff,
1199            object::elf::R_RISCV_TLS_TPREL64 => DynamicRelocationKind::TpOff,
1200            object::elf::R_RISCV_RELATIVE => DynamicRelocationKind::Relative,
1201            object::elf::R_RISCV_64 => DynamicRelocationKind::Absolute,
1202            object::elf::R_RISCV_TLSDESC => DynamicRelocationKind::TlsDesc,
1203            object::elf::R_RISCV_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1204            _ => return None,
1205        };
1206        Some(kind)
1207    }
1208
1209    #[must_use]
1210    pub fn riscv64_r_type(&self) -> u32 {
1211        match self {
1212            DynamicRelocationKind::Copy => object::elf::R_RISCV_COPY,
1213            DynamicRelocationKind::Irelative => object::elf::R_RISCV_IRELATIVE,
1214            DynamicRelocationKind::DtpMod => object::elf::R_RISCV_TLS_DTPMOD64,
1215            DynamicRelocationKind::DtpOff => object::elf::R_RISCV_TLS_DTPREL64,
1216            DynamicRelocationKind::TpOff => object::elf::R_RISCV_TLS_TPREL64,
1217            DynamicRelocationKind::Relative => object::elf::R_RISCV_RELATIVE,
1218            DynamicRelocationKind::Absolute => object::elf::R_RISCV_64,
1219            DynamicRelocationKind::GotEntry => object::elf::R_RISCV_64,
1220            DynamicRelocationKind::TlsDesc => object::elf::R_RISCV_TLSDESC,
1221            DynamicRelocationKind::JumpSlot => object::elf::R_RISCV_JUMP_SLOT,
1222        }
1223    }
1224
1225    #[must_use]
1226    pub fn from_loongarch64_r_type(r_type: u32) -> Option<Self> {
1227        let kind = match r_type {
1228            object::elf::R_LARCH_COPY => DynamicRelocationKind::Copy,
1229            object::elf::R_LARCH_IRELATIVE => DynamicRelocationKind::Irelative,
1230            object::elf::R_LARCH_TLS_DTPMOD64 => DynamicRelocationKind::DtpMod,
1231            object::elf::R_LARCH_TLS_DTPREL64 => DynamicRelocationKind::DtpOff,
1232            object::elf::R_LARCH_TLS_TPREL64 => DynamicRelocationKind::TpOff,
1233            object::elf::R_LARCH_RELATIVE => DynamicRelocationKind::Relative,
1234            object::elf::R_LARCH_64 => DynamicRelocationKind::Absolute,
1235            object::elf::R_LARCH_TLS_DESC64 => DynamicRelocationKind::TlsDesc,
1236            object::elf::R_LARCH_JUMP_SLOT => DynamicRelocationKind::JumpSlot,
1237            _ => return None,
1238        };
1239        Some(kind)
1240    }
1241
1242    #[must_use]
1243    pub fn loongarch64_r_type(&self) -> u32 {
1244        match self {
1245            DynamicRelocationKind::Copy => object::elf::R_LARCH_COPY,
1246            DynamicRelocationKind::Irelative => object::elf::R_LARCH_IRELATIVE,
1247            DynamicRelocationKind::DtpMod => object::elf::R_LARCH_TLS_DTPMOD64,
1248            DynamicRelocationKind::DtpOff => object::elf::R_LARCH_TLS_DTPREL64,
1249            DynamicRelocationKind::TpOff => object::elf::R_LARCH_TLS_TPREL64,
1250            DynamicRelocationKind::Relative => object::elf::R_LARCH_RELATIVE,
1251            DynamicRelocationKind::Absolute => object::elf::R_LARCH_64,
1252            DynamicRelocationKind::GotEntry => object::elf::R_LARCH_64,
1253            DynamicRelocationKind::TlsDesc => object::elf::R_LARCH_TLS_DESC64,
1254            DynamicRelocationKind::JumpSlot => object::elf::R_LARCH_JUMP_SLOT,
1255        }
1256    }
1257}
1258
1259#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1260pub enum AArch64Instruction {
1261    Adr,
1262    Movkz,
1263    Movnz,
1264    Ldr,
1265    LdrRegister,
1266    Add,
1267    LdSt,
1268    TstBr,
1269    Bcond,
1270    JumpCall,
1271    // Mach-O specific
1272    MachOLow12,
1273}
1274
1275#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1276pub enum RiscVInstruction {
1277    // The relocation encoding actually modifies the consecutive pair of instructions:
1278    //   10:	00000097          	auipc	ra,0x0	10: R_RISCV_CALL_PLT	symbol_name
1279    //   14:	000080e7          	jalr	ra # 10 <main+0x10>
1280    //
1281    // That makes the relocation pretty unusual as one would expect 2 relocations:
1282    // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#procedure-calls
1283    UiType,
1284
1285    // Encodes high 20 bits of 32-bit value and encodes the bits to upper part.
1286    UType,
1287
1288    // Encodes low 12 bits of 32-bit value and encodes the bits to upper part.
1289    IType,
1290
1291    // Encodes 12 bits of 32-bit value.
1292    SType,
1293
1294    // The X-type instruction immediate encoding is defined here:
1295    // https://riscv.github.io/riscv-isa-manual/snapshot/unprivileged/#_immediate_encoding_variants
1296
1297    // Specifies a field as the immediate field in a B-type (branch) instruction
1298    BType,
1299
1300    // Specifies a field as the immediate field in a J-type (jump) instruction
1301    JType,
1302
1303    // Specifies a field as the immediate field in a CB-type (compressed branch) instruction
1304    // https://riscv.github.io/riscv-isa-manual/snapshot/unprivileged/#_control_transfer_instructions_2
1305    CbType,
1306
1307    // Specifies a field as the immediate field in a CJ-type (compressed jump) instruction
1308    CjType,
1309
1310    // Encodes the immediate field of a C.LUI instruction (CI-type, 2 bytes).
1311    CluiType,
1312}
1313
1314#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1315pub enum LoongArch64Instruction {
1316    Shift5,
1317    Shift10,
1318    Branch21,
1319    Branch26,
1320    Call30,
1321    Call36,
1322}
1323
1324#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1325pub enum RelocationInstruction {
1326    AArch64(AArch64Instruction),
1327    RiscV(RiscVInstruction),
1328    LoongArch64(LoongArch64Instruction),
1329}
1330
1331impl RelocationInstruction {
1332    #[must_use]
1333    pub fn bit_mask(&self, range: BitRange) -> [u8; 4] {
1334        let mut mask = [0; 4];
1335
1336        // To figure out which bits are part of the relocation, we write a value with
1337        // all ones into a buffer that initially contains zeros.
1338        let all_ones = (1 << (range.end - range.start)) - 1;
1339        self.write_to_value(all_ones, false, &mut mask);
1340
1341        // Wherever we get a 1 is part of the relocation, so invert all bits.
1342        for b in &mut mask {
1343            *b = !*b;
1344        }
1345
1346        mask
1347    }
1348
1349    pub fn write_to_value(self, extracted_value: u64, negative: bool, dest: &mut [u8]) {
1350        match self {
1351            Self::AArch64(insn) => insn.write_to_value(extracted_value, negative, dest),
1352            Self::RiscV(insn) => insn.write_to_value(extracted_value, negative, dest),
1353            Self::LoongArch64(insn) => insn.write_to_value(extracted_value, negative, dest),
1354        }
1355    }
1356
1357    /// The inverse of `write_to_value`. Returns `(extracted_value, negative)`. Supplied `bytes`
1358    /// must be at least 4 bytes, otherwise we panic.
1359    #[must_use]
1360    pub fn read_value(self, bytes: &[u8]) -> (u64, bool) {
1361        match self {
1362            Self::AArch64(insn) => insn.read_value(bytes),
1363            Self::RiscV(insn) => insn.read_value(bytes),
1364            Self::LoongArch64(insn) => insn.read_value(bytes),
1365        }
1366    }
1367
1368    /// The number of bytes the relocation actually can modify in the output data.
1369    #[must_use]
1370    pub fn write_windows_size(self) -> usize {
1371        match self {
1372            Self::AArch64(..) => 4,
1373            Self::RiscV(..) => 4,
1374            Self::LoongArch64(..) => 4,
1375        }
1376    }
1377}
1378
1379#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1380pub enum RelocationSize {
1381    ByteSize(usize),
1382    BitMasking(BitMask),
1383}
1384
1385impl fmt::Display for RelocationSize {
1386    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1387        match self {
1388            Self::ByteSize(bytes) => f.write_fmt(format_args!("{bytes}B")),
1389            Self::BitMasking(mask) => {
1390                f.write_fmt(format_args!("{}..{}", mask.range.start, mask.range.end))
1391            }
1392        }
1393    }
1394}
1395
1396impl RelocationSize {
1397    #[must_use]
1398    pub const fn bit_mask_aarch64(
1399        bit_start: u32,
1400        bit_end: u32,
1401        instruction: AArch64Instruction,
1402    ) -> RelocationSize {
1403        Self::BitMasking(BitMask::new(
1404            RelocationInstruction::AArch64(instruction),
1405            bit_start,
1406            bit_end,
1407        ))
1408    }
1409
1410    #[must_use]
1411    pub const fn bit_mask_riscv(
1412        bit_start: u32,
1413        bit_end: u32,
1414        instruction: RiscVInstruction,
1415    ) -> RelocationSize {
1416        Self::BitMasking(BitMask::new(
1417            RelocationInstruction::RiscV(instruction),
1418            bit_start,
1419            bit_end,
1420        ))
1421    }
1422
1423    #[must_use]
1424    pub const fn bit_mask_loongarch64(
1425        bit_start: u32,
1426        bit_end: u32,
1427        instruction: LoongArch64Instruction,
1428    ) -> RelocationSize {
1429        Self::BitMasking(BitMask::new(
1430            RelocationInstruction::LoongArch64(instruction),
1431            bit_start,
1432            bit_end,
1433        ))
1434    }
1435}
1436
1437#[derive(Clone, Debug, Copy, PartialEq, Eq)]
1438pub struct BitMask {
1439    pub instruction: RelocationInstruction,
1440    pub range: BitRange,
1441}
1442
1443pub const SIZE_2KB: u64 = 1 << 11;
1444pub const SIZE_4KB: u64 = 1 << 12;
1445pub const SIZE_2GB: u64 = 1 << 31;
1446pub const SIZE_4GB: u64 = 1 << 32;
1447
1448pub const PAGE_MASK_4KB: u64 = SIZE_4KB - 1;
1449pub const PAGE_MASK_4GB: u64 = SIZE_4GB - 1;
1450
1451#[derive(Debug, Clone, Copy)]
1452pub enum PageMask {
1453    SymbolPlusAddendAndPosition(u64),
1454    GotEntryAndPosition(u64),
1455    GotBase(u64),
1456    Position(u64),
1457}
1458
1459// Allow range (half-open) of a computed value of a relocation
1460#[derive(Clone, Debug, Copy, PartialEq)]
1461pub struct AllowedRange {
1462    pub min: i64,
1463    pub max: i64,
1464}
1465
1466impl AllowedRange {
1467    #[must_use]
1468    pub const fn new(min: i64, max: i64) -> Self {
1469        Self { min, max }
1470    }
1471
1472    #[must_use]
1473    pub const fn no_check() -> Self {
1474        Self::new(i64::MIN, i64::MAX)
1475    }
1476
1477    #[must_use]
1478    /// Note: for the 64-bit size, we actually do signed checks regardless of the `sign` argument
1479    /// because the `min` and `max` are `i64` type
1480    pub const fn from_bit_size(n_bits: usize, sign: Sign) -> Self {
1481        match n_bits {
1482            0 | 64 => Self::no_check(),
1483            63 if matches!(sign, Sign::Unsigned) => panic!("2^63 cannot be represented as i64"),
1484            1..64 => {
1485                let n_bits = n_bits as u32;
1486                match sign {
1487                    Sign::Unsigned => Self::new(0, 2i64.pow(n_bits)),
1488                    Sign::Signed => Self::new(-2i64.pow(n_bits - 1), 2i64.pow(n_bits - 1)),
1489                }
1490            }
1491            _ => panic!("Only sizes up to 8 bytes are supported"),
1492        }
1493    }
1494
1495    #[must_use]
1496    /// Note: for the 8-byte size, we actually do signed checks regardless of the `sign` argument
1497    /// because the `min` and `max` are `i64` type
1498    pub const fn from_byte_size(n_bytes: usize, sign: Sign) -> Self {
1499        Self::from_bit_size(8 * n_bytes, sign)
1500    }
1501
1502    #[must_use]
1503    /// Return true if the value is present in the allowed range.
1504    pub fn contains(&self, value: i64) -> bool {
1505        self.min <= value && value < self.max
1506    }
1507
1508    /// Returns how far we're outside the allowed range.
1509    #[must_use]
1510    pub fn overrun(&self, value: i64) -> i64 {
1511        if value < self.min {
1512            value - self.min
1513        } else if value > self.max {
1514            value - self.max
1515        } else {
1516            0
1517        }
1518    }
1519}
1520
1521#[derive(Clone, Debug, Copy)]
1522pub struct RelocationKindInfo {
1523    pub kind: RelocationKind,
1524    pub size: RelocationSize,
1525    pub mask: Option<PageMask>,
1526    pub range: AllowedRange,
1527    pub alignment: usize,
1528    pub bias: u64,
1529    /// Whether this relocation type supports range-extension thunks.
1530    pub thunkable: bool,
1531}
1532
1533impl RelocationKindInfo {
1534    #[inline(always)]
1535    fn verify(&self, value: i64) -> Result<()> {
1536        anyhow::ensure!(
1537            (value as usize).is_multiple_of(self.alignment),
1538            "Relocation {value} not aligned to {} bytes",
1539            self.alignment
1540        );
1541        anyhow::ensure!(
1542            self.range.contains(value),
1543            format!(
1544                "Relocation {value} outside of bounds [{}, {})",
1545                self.range.min, self.range.max
1546            )
1547        );
1548        Ok(())
1549    }
1550
1551    #[inline(always)]
1552    pub fn write_to_buffer(self, value: u64, output: &mut [u8]) -> Result<()> {
1553        self.verify(value as i64)?;
1554
1555        if matches!(self.kind, RelocationKind::PairSubtractionULEB128(..)) {
1556            let mut writer = Cursor::new([0u8; u64::BITS.div_ceil(7) as usize]);
1557            let n = leb128::write::unsigned(&mut writer, value).expect("Must fit into the buffer");
1558            anyhow::ensure!(
1559                output.len() >= n,
1560                "cannot write encoded ULEB128 value of {n} bytes"
1561            );
1562            output[..n].copy_from_slice(&writer.into_inner()[..n]);
1563        } else {
1564            match self.size {
1565                RelocationSize::ByteSize(byte_size) => {
1566                    anyhow::ensure!(
1567                        byte_size <= output.len(),
1568                        "Relocation outside of bounds of section"
1569                    );
1570                    let value_bytes = value.to_le_bytes();
1571                    output[..byte_size].copy_from_slice(&value_bytes[..byte_size]);
1572                }
1573                RelocationSize::BitMasking(BitMask {
1574                    range,
1575                    instruction: insn,
1576                }) => {
1577                    let extracted_value = value.extract_bit_range(range.start..range.end);
1578                    let negative = (value as i64).is_negative();
1579                    let output_len = output.len();
1580                    insn.write_to_value(extracted_value, negative, &mut output[..output_len]);
1581                }
1582            }
1583        }
1584
1585        Ok(())
1586    }
1587}
1588
1589impl BitMask {
1590    #[must_use]
1591    pub const fn new(instruction: RelocationInstruction, bit_start: u32, bit_end: u32) -> Self {
1592        Self {
1593            instruction,
1594            range: BitRange {
1595                start: bit_start,
1596                end: bit_end,
1597            },
1598        }
1599    }
1600}
1601
1602#[cfg(test)]
1603mod tests {
1604    use super::*;
1605    use object::elf::*;
1606
1607    #[test]
1608    fn test_rel_type_to_string() {
1609        assert_eq!(
1610            &x86_64_rel_type_to_string(R_X86_64_32),
1611            stringify!(R_X86_64_32)
1612        );
1613        assert_eq!(
1614            &x86_64_rel_type_to_string(R_X86_64_GOTPC32_TLSDESC),
1615            stringify!(R_X86_64_GOTPC32_TLSDESC)
1616        );
1617        assert_eq!(
1618            &x86_64_rel_type_to_string(64),
1619            "Unknown x86_64 relocation type 0x40"
1620        );
1621
1622        assert_eq!(
1623            &aarch64_rel_type_to_string(64),
1624            "Unknown aarch64 relocation type 0x40"
1625        );
1626    }
1627
1628    #[test]
1629    fn test_range_from_byte_size() {
1630        assert_eq!(
1631            AllowedRange::from_byte_size(0, Sign::Signed),
1632            AllowedRange::no_check(),
1633        );
1634        assert_eq!(
1635            AllowedRange::from_byte_size(0, Sign::Unsigned),
1636            AllowedRange::no_check(),
1637        );
1638        assert_eq!(
1639            AllowedRange::from_byte_size(1, Sign::Signed),
1640            AllowedRange::new(-128, 128)
1641        );
1642        assert_eq!(
1643            AllowedRange::from_byte_size(1, Sign::Signed),
1644            AllowedRange::new(-128, 128)
1645        );
1646        assert_eq!(
1647            AllowedRange::from_byte_size(1, Sign::Unsigned),
1648            AllowedRange::new(0, 256)
1649        );
1650        assert_eq!(
1651            AllowedRange::from_byte_size(4, Sign::Signed),
1652            AllowedRange::new(i64::from(i32::MIN), i64::from(i32::MAX) + 1)
1653        );
1654        assert_eq!(
1655            AllowedRange::from_byte_size(4, Sign::Unsigned),
1656            AllowedRange::new(i64::from(u32::MIN), i64::from(u32::MAX) + 1)
1657        );
1658        assert_eq!(
1659            AllowedRange::from_byte_size(8, Sign::Signed),
1660            AllowedRange::no_check()
1661        );
1662        // 8-byte unsigned is also no check because the range cannot be represented in i64
1663        assert_eq!(
1664            AllowedRange::from_byte_size(8, Sign::Unsigned),
1665            AllowedRange::no_check()
1666        );
1667
1668        assert_eq!(
1669            AllowedRange::from_bit_size(1, Sign::Signed),
1670            AllowedRange::new(-1, 1),
1671        );
1672        assert_eq!(
1673            AllowedRange::from_bit_size(10, Sign::Signed),
1674            AllowedRange::new(-512, 512),
1675        );
1676        assert_eq!(
1677            AllowedRange::from_bit_size(10, Sign::Unsigned),
1678            AllowedRange::new(0, 1024),
1679        );
1680
1681        let r_riscv_branch_range = AllowedRange::new(-(2i64.pow(12)), 2i64.pow(12) - 1);
1682        assert!(r_riscv_branch_range.contains(-4096));
1683        assert!(r_riscv_branch_range.contains(4094));
1684        assert!(!r_riscv_branch_range.contains(4095));
1685
1686        let r_riscv_rvc_branch_range = AllowedRange::new(-(2i64.pow(8)), 2i64.pow(8) - 1);
1687        assert!(r_riscv_rvc_branch_range.contains(-256));
1688        assert!(r_riscv_rvc_branch_range.contains(254));
1689        assert!(!r_riscv_rvc_branch_range.contains(255));
1690    }
1691}