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}