Skip to main content

object/
common.rs

1use core::{
2    fmt,
3    ops::{Deref, DerefMut},
4};
5
6/// A CPU architecture.
7#[allow(missing_docs)]
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9#[non_exhaustive]
10pub enum Architecture {
11    Unknown,
12    Aarch64,
13    #[allow(non_camel_case_types)]
14    Aarch64_Ilp32,
15    Alpha,
16    Arm,
17    Avr,
18    Bpf,
19    Csky,
20    E2K32,
21    E2K64,
22    I386,
23    X86_64,
24    #[allow(non_camel_case_types)]
25    X86_64_X32,
26    Hexagon,
27    Hppa,
28    LoongArch32,
29    LoongArch64,
30    M68k,
31    Mips,
32    Mips64,
33    #[allow(non_camel_case_types)]
34    Mips64_N32,
35    Msp430,
36    PowerPc,
37    PowerPc64,
38    Riscv32,
39    Riscv64,
40    S390x,
41    Sbf,
42    Sharc,
43    Sparc,
44    Sparc32Plus,
45    Sparc64,
46    SuperH,
47    Wasm32,
48    Wasm64,
49    Xtensa,
50}
51
52/// A CPU sub-architecture.
53#[allow(missing_docs)]
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
55#[non_exhaustive]
56pub enum SubArchitecture {
57    Arm64E,
58    Arm64EC,
59}
60
61impl Architecture {
62    /// The size of an address value for this architecture.
63    ///
64    /// Returns `None` for unknown architectures.
65    pub fn address_size(self) -> Option<AddressSize> {
66        match self {
67            Architecture::Unknown => None,
68            Architecture::Aarch64 => Some(AddressSize::U64),
69            Architecture::Aarch64_Ilp32 => Some(AddressSize::U32),
70            Architecture::Alpha => Some(AddressSize::U64),
71            Architecture::Arm => Some(AddressSize::U32),
72            Architecture::Avr => Some(AddressSize::U8),
73            Architecture::Bpf => Some(AddressSize::U64),
74            Architecture::Csky => Some(AddressSize::U32),
75            Architecture::E2K32 => Some(AddressSize::U32),
76            Architecture::E2K64 => Some(AddressSize::U64),
77            Architecture::I386 => Some(AddressSize::U32),
78            Architecture::X86_64 => Some(AddressSize::U64),
79            Architecture::X86_64_X32 => Some(AddressSize::U32),
80            Architecture::Hexagon => Some(AddressSize::U32),
81            Architecture::Hppa => Some(AddressSize::U32),
82            Architecture::LoongArch32 => Some(AddressSize::U32),
83            Architecture::LoongArch64 => Some(AddressSize::U64),
84            Architecture::M68k => Some(AddressSize::U32),
85            Architecture::Mips => Some(AddressSize::U32),
86            Architecture::Mips64 => Some(AddressSize::U64),
87            Architecture::Mips64_N32 => Some(AddressSize::U32),
88            Architecture::Msp430 => Some(AddressSize::U16),
89            Architecture::PowerPc => Some(AddressSize::U32),
90            Architecture::PowerPc64 => Some(AddressSize::U64),
91            Architecture::Riscv32 => Some(AddressSize::U32),
92            Architecture::Riscv64 => Some(AddressSize::U64),
93            Architecture::S390x => Some(AddressSize::U64),
94            Architecture::Sbf => Some(AddressSize::U64),
95            Architecture::Sharc => Some(AddressSize::U32),
96            Architecture::Sparc => Some(AddressSize::U32),
97            Architecture::Sparc32Plus => Some(AddressSize::U32),
98            Architecture::Sparc64 => Some(AddressSize::U64),
99            Architecture::Wasm32 => Some(AddressSize::U32),
100            Architecture::Wasm64 => Some(AddressSize::U64),
101            Architecture::Xtensa => Some(AddressSize::U32),
102            Architecture::SuperH => Some(AddressSize::U32),
103        }
104    }
105}
106
107/// The size of an address value for an architecture.
108///
109/// This may differ from the address size supported by the file format (such as for COFF).
110#[allow(missing_docs)]
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
112#[non_exhaustive]
113#[repr(u8)]
114pub enum AddressSize {
115    U8 = 1,
116    U16 = 2,
117    U32 = 4,
118    U64 = 8,
119}
120
121impl AddressSize {
122    /// The size in bytes of an address value.
123    #[inline]
124    pub fn bytes(self) -> u8 {
125        self as u8
126    }
127}
128
129/// A binary file format.
130#[allow(missing_docs)]
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
132#[non_exhaustive]
133pub enum BinaryFormat {
134    Coff,
135    Elf,
136    MachO,
137    Pe,
138    Wasm,
139    Xcoff,
140}
141
142impl BinaryFormat {
143    /// The target's native binary format for relocatable object files.
144    ///
145    /// Defaults to `Elf` for unknown platforms.
146    pub fn native_object() -> BinaryFormat {
147        if cfg!(target_os = "windows") {
148            BinaryFormat::Coff
149        } else if cfg!(target_os = "macos") {
150            BinaryFormat::MachO
151        } else {
152            BinaryFormat::Elf
153        }
154    }
155}
156
157/// The kind of a section.
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
159#[non_exhaustive]
160pub enum SectionKind {
161    /// The section kind is unknown.
162    Unknown,
163    /// An executable code section.
164    ///
165    /// Example ELF sections: `.text`
166    ///
167    /// Example Mach-O sections: `__TEXT/__text`
168    Text,
169    /// A data section.
170    ///
171    /// Example ELF sections: `.data`
172    ///
173    /// Example Mach-O sections: `__DATA/__data`
174    Data,
175    /// A read only data section.
176    ///
177    /// Example ELF sections: `.rodata`
178    ///
179    /// Example Mach-O sections: `__TEXT/__const`, `__DATA/__const`, `__TEXT/__literal4`
180    ReadOnlyData,
181    /// A read only data section with relocations.
182    ///
183    /// This is the same as either `Data` or `ReadOnlyData`, depending on the file format.
184    /// This value is only used in the API for writing files. It is never returned when reading files.
185    ReadOnlyDataWithRel,
186    /// A loadable string section.
187    ///
188    /// Example ELF sections: `.rodata.str`
189    ///
190    /// Example Mach-O sections: `__TEXT/__cstring`
191    ReadOnlyString,
192    /// An uninitialized data section.
193    ///
194    /// Example ELF sections: `.bss`
195    ///
196    /// Example Mach-O sections: `__DATA/__bss`
197    UninitializedData,
198    /// An uninitialized common data section.
199    ///
200    /// Example Mach-O sections: `__DATA/__common`
201    Common,
202    /// A TLS data section.
203    ///
204    /// Example ELF sections: `.tdata`
205    ///
206    /// Example Mach-O sections: `__DATA/__thread_data`
207    Tls,
208    /// An uninitialized TLS data section.
209    ///
210    /// Example ELF sections: `.tbss`
211    ///
212    /// Example Mach-O sections: `__DATA/__thread_bss`
213    UninitializedTls,
214    /// A TLS variables section.
215    ///
216    /// This contains TLS variable structures, rather than the variable initializers.
217    ///
218    /// Example Mach-O sections: `__DATA/__thread_vars`
219    TlsVariables,
220    /// A non-loadable string section.
221    ///
222    /// Example ELF sections: `.comment`, `.debug_str`
223    OtherString,
224    /// Some other non-loadable section.
225    ///
226    /// Example ELF sections: `.debug_info`
227    Other,
228    /// Debug information.
229    ///
230    /// Example Mach-O sections: `__DWARF/__debug_info`
231    Debug,
232    /// Debug strings.
233    ///
234    /// This is the same as either `Debug` or `OtherString`, depending on the file format.
235    /// This value is only used in the API for writing files. It is never returned when reading files.
236    DebugString,
237    /// Information for the linker.
238    ///
239    /// Example COFF sections: `.drectve`
240    Linker,
241    /// ELF note section.
242    Note,
243    /// Metadata such as symbols or relocations.
244    ///
245    /// Example ELF sections: `.symtab`, `.strtab`, `.group`
246    Metadata,
247    /// Some other ELF section type.
248    ///
249    /// This is the `sh_type` field in the section header.
250    /// The meaning may be dependent on the architecture.
251    Elf(u32),
252}
253
254impl SectionKind {
255    /// Return true if this section contains zerofill data.
256    pub fn is_bss(self) -> bool {
257        self == SectionKind::UninitializedData
258            || self == SectionKind::UninitializedTls
259            || self == SectionKind::Common
260    }
261}
262
263/// The selection kind for a COMDAT section group.
264///
265/// This determines the way in which the linker resolves multiple definitions of the COMDAT
266/// sections.
267#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
268#[non_exhaustive]
269pub enum ComdatKind {
270    /// The selection kind is unknown.
271    Unknown,
272    /// Multiple definitions are allowed.
273    ///
274    /// An arbitrary definition is selected, and the rest are removed.
275    ///
276    /// This is the only supported selection kind for ELF.
277    Any,
278    /// Multiple definitions are not allowed.
279    ///
280    /// This is used to group sections without allowing duplicates.
281    NoDuplicates,
282    /// Multiple definitions must have the same size.
283    ///
284    /// An arbitrary definition is selected, and the rest are removed.
285    SameSize,
286    /// Multiple definitions must match exactly.
287    ///
288    /// An arbitrary definition is selected, and the rest are removed.
289    ExactMatch,
290    /// Multiple definitions are allowed, and the largest is selected.
291    ///
292    /// An arbitrary definition with the largest size is selected, and the rest are removed.
293    Largest,
294    /// Multiple definitions are allowed, and the newest is selected.
295    Newest,
296}
297
298/// The kind of a symbol.
299#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
300#[non_exhaustive]
301pub enum SymbolKind {
302    /// The symbol kind is unknown.
303    Unknown,
304    /// The symbol is for executable code.
305    Text,
306    /// The symbol is for a data object.
307    Data,
308    /// The symbol is for a section.
309    Section,
310    /// The symbol is the name of a file. It precedes symbols within that file.
311    File,
312    /// The symbol is for a code label.
313    Label,
314    /// The symbol is for a thread local storage entity.
315    Tls,
316}
317
318/// A symbol scope.
319#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
320pub enum SymbolScope {
321    /// Unknown scope.
322    Unknown,
323    /// Symbol is visible to the compilation unit.
324    Compilation,
325    /// Symbol is visible to the static linkage unit.
326    Linkage,
327    /// Symbol is visible to dynamically linked objects.
328    Dynamic,
329}
330
331/// The operation used to calculate the result of the relocation.
332///
333/// The relocation descriptions use the following definitions. Note that
334/// these definitions probably don't match any ELF ABI.
335///
336/// * A - The value of the addend.
337/// * G - The address of the symbol's entry within the global offset table.
338/// * L - The address of the symbol's entry within the procedure linkage table.
339/// * P - The address of the place of the relocation.
340/// * S - The address of the symbol.
341/// * GotBase - The address of the global offset table.
342/// * Image - The base address of the image.
343/// * Section - The address of the section containing the symbol.
344///
345/// 'XxxRelative' means 'Xxx + A - P'.  'XxxOffset' means 'S + A - Xxx'.
346#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
347#[non_exhaustive]
348pub enum RelocationKind {
349    /// The operation is unknown.
350    Unknown,
351    /// No relocation.
352    ///
353    /// Example: `elf::R_X86_64_NONE`
354    None,
355    /// S + A
356    ///
357    /// Example: `elf::R_X86_64_64`
358    Absolute,
359    /// S + A - P
360    ///
361    /// Example: `elf::R_X86_64_PC32`
362    Relative,
363    /// G + A - GotBase
364    ///
365    /// Example: `elf::R_X86_64_GOT32`
366    Got,
367    /// G + A - P
368    ///
369    /// Example: `elf::R_X86_64_GOTPCREL`
370    GotRelative,
371    /// GotBase + A - P
372    ///
373    /// Example: `elf::R_386_GOTPC`
374    GotBaseRelative,
375    /// S + A - GotBase
376    ///
377    /// Example: `elf::R_386_GOTOFF`
378    GotBaseOffset,
379    /// L + A - P
380    ///
381    /// Example: `elf::R_X86_64_PLT32`
382    PltRelative,
383    /// S + A - Image
384    ///
385    /// Example: `pe::IMAGE_REL_AMD64_ADDR32NB`
386    ImageOffset,
387    /// S + A - Section
388    ///
389    /// Example: `pe::IMAGE_REL_AMD64_SECREL`
390    SectionOffset,
391    /// The index of the section containing the symbol.
392    ///
393    /// Example: `pe::IMAGE_REL_AMD64_SECTION`
394    SectionIndex,
395}
396
397/// Information about how the result of the relocation operation is encoded in the place.
398///
399/// This is usually architecture specific, such as specifying an addressing mode or
400/// a specific instruction.
401#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
402#[non_exhaustive]
403pub enum RelocationEncoding {
404    /// The relocation encoding is unknown.
405    Unknown,
406    /// Generic encoding.
407    Generic,
408
409    /// x86 sign extension at runtime.
410    ///
411    /// Used with `RelocationKind::Absolute`.
412    X86Signed,
413    /// x86 rip-relative addressing.
414    ///
415    /// The `RelocationKind` must be PC relative.
416    X86RipRelative,
417    /// x86 rip-relative addressing in movq instruction.
418    ///
419    /// The `RelocationKind` must be PC relative.
420    X86RipRelativeMovq,
421    /// x86 call target.
422    ///
423    /// The `RelocationKind` must be PC relative.
424    // This name matches Mach-O, but might have been better named `X86Call`.
425    X86Branch,
426
427    /// s390x PC-relative offset shifted right by one bit.
428    ///
429    /// The `RelocationKind` must be PC relative.
430    S390xDbl,
431
432    /// AArch64 call target.
433    ///
434    /// The `RelocationKind` must be PC relative.
435    AArch64Call,
436
437    /// LoongArch branch offset with two trailing zeros.
438    ///
439    /// The `RelocationKind` must be PC relative.
440    LoongArchBranch,
441
442    /// SHARC+ 48-bit Type A instruction
443    ///
444    /// Represents these possible variants, each with a corresponding
445    /// `R_SHARC_*` constant:
446    ///
447    /// * 24-bit absolute address
448    /// * 32-bit absolute address
449    /// * 6-bit relative address
450    /// * 24-bit relative address
451    /// * 6-bit absolute address in the immediate value field
452    /// * 16-bit absolute address in the immediate value field
453    SharcTypeA,
454
455    /// SHARC+ 32-bit Type B instruction
456    ///
457    /// Represents these possible variants, each with a corresponding
458    /// `R_SHARC_*` constant:
459    ///
460    /// * 6-bit absolute address in the immediate value field
461    /// * 7-bit absolute address in the immediate value field
462    /// * 16-bit absolute address
463    /// * 6-bit relative address
464    SharcTypeB,
465
466    /// E2K 64-bit value stored in two LTS
467    ///
468    /// Memory representation:
469    /// ```text
470    /// 0: LTS1 = value[63:32]
471    /// 4: LTS0 = value[31:0]
472    /// ```
473    E2KLit,
474
475    /// E2K 28-bit value stored in CS0
476    E2KDisp,
477}
478
479/// File flags that are specific to each file format.
480#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
481#[non_exhaustive]
482pub enum FileFlags {
483    /// No file flags.
484    None,
485    /// ELF file flags.
486    Elf {
487        /// `os_abi` field in the ELF file header.
488        os_abi: u8,
489        /// `abi_version` field in the ELF file header.
490        abi_version: u8,
491        /// `e_flags` field in the ELF file header.
492        e_flags: u32,
493    },
494    /// Mach-O file flags.
495    MachO {
496        /// `flags` field in the Mach-O file header.
497        flags: u32,
498    },
499    /// COFF file flags.
500    Coff {
501        /// `Characteristics` field in the COFF file header.
502        characteristics: u16,
503    },
504    /// XCOFF file flags.
505    Xcoff {
506        /// `f_flags` field in the XCOFF file header.
507        f_flags: u16,
508    },
509}
510
511/// Segment flags that are specific to each file format.
512#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
513#[non_exhaustive]
514pub enum SegmentFlags {
515    /// No segment flags.
516    None,
517    /// ELF segment flags.
518    Elf {
519        /// `p_flags` field in the segment header.
520        p_flags: u32,
521    },
522    /// Mach-O segment flags.
523    MachO {
524        /// `flags` field in the segment header.
525        flags: u32,
526        /// `maxprot` field in the segment header.
527        maxprot: u32,
528        /// `initprot` field in the segment header.
529        initprot: u32,
530    },
531    /// COFF segment flags.
532    Coff {
533        /// `Characteristics` field in the segment header.
534        characteristics: u32,
535    },
536}
537
538/// Memory permissions for a segment.
539///
540/// This is a simplified representation of segment permissions that abstracts
541/// over format-specific flags.
542#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
543pub struct Permissions {
544    bits: u8,
545}
546
547impl core::fmt::Debug for Permissions {
548    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
549        write!(
550            f,
551            "{}{}{}",
552            if self.readable() { 'R' } else { '-' },
553            if self.writable() { 'W' } else { '-' },
554            if self.executable() { 'X' } else { '-' },
555        )
556    }
557}
558
559impl Permissions {
560    /// Permission bit for readable.
561    const R: u8 = 1 << 0;
562    /// Permission bit for writable.
563    const W: u8 = 1 << 1;
564    /// Permission bit for executable.
565    const X: u8 = 1 << 2;
566
567    /// Creates a new `Permissions` with the given flags.
568    pub fn new(readable: bool, writable: bool, executable: bool) -> Self {
569        let mut bits = 0;
570        if readable {
571            bits |= Self::R;
572        }
573        if writable {
574            bits |= Self::W;
575        }
576        if executable {
577            bits |= Self::X;
578        }
579        Permissions { bits }
580    }
581
582    /// Returns true if the segment is readable.
583    #[inline]
584    pub fn readable(&self) -> bool {
585        self.bits & Self::R != 0
586    }
587
588    /// Returns true if the segment is writable.
589    #[inline]
590    pub fn writable(&self) -> bool {
591        self.bits & Self::W != 0
592    }
593
594    /// Returns true if the segment is executable.
595    #[inline]
596    pub fn executable(&self) -> bool {
597        self.bits & Self::X != 0
598    }
599
600    /// Returns true if the segment is readable but not writable.
601    #[inline]
602    pub fn readonly(&self) -> bool {
603        self.readable() && !self.writable()
604    }
605}
606
607/// Section flags that are specific to each file format.
608#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
609#[non_exhaustive]
610pub enum SectionFlags {
611    /// No section flags.
612    None,
613    /// ELF section flags.
614    Elf {
615        /// `sh_flags` field in the section header.
616        sh_flags: u64,
617    },
618    /// Mach-O section flags.
619    MachO {
620        /// `flags` field in the section header.
621        flags: u32,
622    },
623    /// COFF section flags.
624    Coff {
625        /// `Characteristics` field in the section header.
626        characteristics: u32,
627    },
628    /// XCOFF section flags.
629    Xcoff {
630        /// `s_flags` field in the section header.
631        s_flags: u32,
632    },
633}
634
635/// Symbol flags that are specific to each file format.
636#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
637#[non_exhaustive]
638pub enum SymbolFlags<Section, Symbol> {
639    /// No symbol flags.
640    None,
641    /// ELF symbol flags.
642    Elf {
643        /// `st_info` field in the ELF symbol.
644        st_info: u8,
645        /// `st_other` field in the ELF symbol.
646        st_other: u8,
647    },
648    /// Mach-O symbol flags.
649    MachO {
650        /// `n_desc` field in the Mach-O symbol.
651        n_desc: u16,
652    },
653    /// COFF flags for a section symbol.
654    CoffSection {
655        /// `Selection` field in the auxiliary symbol for the section.
656        selection: u8,
657        /// `Number` field in the auxiliary symbol for the section.
658        associative_section: Option<Section>,
659    },
660    /// XCOFF symbol flags.
661    Xcoff {
662        /// `n_sclass` field in the XCOFF symbol.
663        n_sclass: u8,
664        /// `x_smtyp` field in the CSECT auxiliary symbol.
665        ///
666        /// Only valid if `n_sclass` is `C_EXT`, `C_WEAKEXT`, or `C_HIDEXT`.
667        x_smtyp: u8,
668        /// `x_smclas` field in the CSECT auxiliary symbol.
669        ///
670        /// Only valid if `n_sclass` is `C_EXT`, `C_WEAKEXT`, or `C_HIDEXT`.
671        x_smclas: u8,
672        /// The containing csect for the symbol.
673        ///
674        /// Only valid if `x_smtyp` is `XTY_LD`.
675        containing_csect: Option<Symbol>,
676    },
677}
678
679impl<Section, Symbol> SymbolFlags<Section, Symbol> {
680    /// Returns the ELF symbol visibility.
681    ///
682    /// This corresponds to the lower 2 bits of the `st_other` field,
683    /// and will be a value such as `elf::STV_DEFAULT`.
684    pub fn elf_visibility(&self) -> Option<u8> {
685        match self {
686            SymbolFlags::Elf { st_other, .. } => Some(st_other & 0x3),
687            _ => None,
688        }
689    }
690}
691
692/// Relocation fields that are specific to each file format and architecture.
693#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
694#[non_exhaustive]
695pub enum RelocationFlags {
696    /// Format independent representation.
697    Generic {
698        /// The operation used to calculate the result of the relocation.
699        kind: RelocationKind,
700        /// Information about how the result of the relocation operation is encoded in the place.
701        encoding: RelocationEncoding,
702        /// The size in bits of the place of relocation.
703        size: u8,
704    },
705    /// ELF relocation fields.
706    Elf {
707        /// `r_type` field in the ELF relocation.
708        r_type: u32,
709    },
710    /// Mach-O relocation fields.
711    MachO {
712        /// `r_type` field in the Mach-O relocation.
713        r_type: u8,
714        /// `r_pcrel` field in the Mach-O relocation.
715        r_pcrel: bool,
716        /// `r_length` field in the Mach-O relocation.
717        r_length: u8,
718    },
719    /// COFF relocation fields.
720    Coff {
721        /// `typ` field in the COFF relocation.
722        typ: u16,
723    },
724    /// XCOFF relocation fields.
725    Xcoff {
726        /// `r_rtype` field in the XCOFF relocation.
727        r_rtype: u8,
728        /// `r_rsize` field in the XCOFF relocation.
729        r_rsize: u8,
730    },
731}
732
733/// Wrapper to print as `[..]` without a manual `Debug` implementation, rather than dumping an
734/// entire byte array.
735#[allow(unused)]
736#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
737pub(crate) struct SkipDebugList<T>(pub T);
738
739impl<T> fmt::Debug for SkipDebugList<T> {
740    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
741        write!(f, "[..]")
742    }
743}
744
745impl<T> Deref for SkipDebugList<T> {
746    type Target = T;
747
748    fn deref(&self) -> &Self::Target {
749        &self.0
750    }
751}
752
753impl<T> DerefMut for SkipDebugList<T> {
754    fn deref_mut(&mut self) -> &mut Self::Target {
755        &mut self.0
756    }
757}