object/write/
mod.rs

1//! Interface for writing object files.
2//!
3//! This module provides a unified write API for relocatable object files
4//! using [`Object`]. This does not support writing executable files.
5//! This supports the following file formats: COFF, ELF, Mach-O, and XCOFF.
6//!
7//! The submodules define helpers for writing the raw structs. These support
8//! writing both relocatable and executable files. There are writers for
9//! the following file formats: [COFF](coff::Writer), [ELF](elf::Writer),
10//! and [PE](pe::Writer).
11
12use alloc::borrow::Cow;
13use alloc::string::String;
14use alloc::vec::Vec;
15use core::{fmt, result, str};
16#[cfg(not(feature = "std"))]
17use hashbrown::HashMap;
18#[cfg(feature = "std")]
19use std::{boxed::Box, collections::HashMap, error, io};
20
21use crate::endian::{Endianness, U32, U64};
22
23pub use crate::common::*;
24
25#[cfg(feature = "coff")]
26pub mod coff;
27#[cfg(feature = "coff")]
28pub use coff::CoffExportStyle;
29
30#[cfg(feature = "elf")]
31pub mod elf;
32
33#[cfg(feature = "macho")]
34mod macho;
35#[cfg(feature = "macho")]
36pub use macho::MachOBuildVersion;
37
38#[cfg(feature = "pe")]
39pub mod pe;
40
41#[cfg(feature = "xcoff")]
42mod xcoff;
43
44pub(crate) mod string;
45pub use string::StringId;
46
47mod util;
48pub use util::*;
49
50/// The error type used within the write module.
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct Error(pub(crate) String);
53
54impl fmt::Display for Error {
55    #[inline]
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        f.write_str(&self.0)
58    }
59}
60
61#[cfg(feature = "std")]
62impl error::Error for Error {}
63#[cfg(all(not(feature = "std"), core_error))]
64impl core::error::Error for Error {}
65
66/// The result type used within the write module.
67pub type Result<T> = result::Result<T, Error>;
68
69/// A writable relocatable object file.
70#[derive(Debug)]
71pub struct Object<'a> {
72    format: BinaryFormat,
73    architecture: Architecture,
74    sub_architecture: Option<SubArchitecture>,
75    endian: Endianness,
76    sections: Vec<Section<'a>>,
77    standard_sections: HashMap<StandardSection, SectionId>,
78    symbols: Vec<Symbol>,
79    symbol_map: HashMap<Vec<u8>, SymbolId>,
80    comdats: Vec<Comdat>,
81    /// File flags that are specific to each file format.
82    pub flags: FileFlags,
83    /// The symbol name mangling scheme.
84    pub mangling: Mangling,
85    #[cfg(feature = "coff")]
86    stub_symbols: HashMap<SymbolId, SymbolId>,
87    /// Mach-O "_tlv_bootstrap" symbol.
88    #[cfg(feature = "macho")]
89    tlv_bootstrap: Option<SymbolId>,
90    /// Mach-O CPU subtype.
91    #[cfg(feature = "macho")]
92    macho_cpu_subtype: Option<u32>,
93    #[cfg(feature = "macho")]
94    macho_build_version: Option<MachOBuildVersion>,
95    /// Mach-O MH_SUBSECTIONS_VIA_SYMBOLS flag. Only ever set if format is Mach-O.
96    #[cfg(feature = "macho")]
97    macho_subsections_via_symbols: bool,
98}
99
100impl<'a> Object<'a> {
101    /// Create an empty object file.
102    pub fn new(format: BinaryFormat, architecture: Architecture, endian: Endianness) -> Object<'a> {
103        Object {
104            format,
105            architecture,
106            sub_architecture: None,
107            endian,
108            sections: Vec::new(),
109            standard_sections: HashMap::new(),
110            symbols: Vec::new(),
111            symbol_map: HashMap::new(),
112            comdats: Vec::new(),
113            flags: FileFlags::None,
114            mangling: Mangling::default(format, architecture),
115            #[cfg(feature = "coff")]
116            stub_symbols: HashMap::new(),
117            #[cfg(feature = "macho")]
118            tlv_bootstrap: None,
119            #[cfg(feature = "macho")]
120            macho_cpu_subtype: None,
121            #[cfg(feature = "macho")]
122            macho_build_version: None,
123            #[cfg(feature = "macho")]
124            macho_subsections_via_symbols: false,
125        }
126    }
127
128    /// Return the file format.
129    #[inline]
130    pub fn format(&self) -> BinaryFormat {
131        self.format
132    }
133
134    /// Return the architecture.
135    #[inline]
136    pub fn architecture(&self) -> Architecture {
137        self.architecture
138    }
139
140    /// Return the sub-architecture.
141    #[inline]
142    pub fn sub_architecture(&self) -> Option<SubArchitecture> {
143        self.sub_architecture
144    }
145
146    /// Specify the sub-architecture.
147    pub fn set_sub_architecture(&mut self, sub_architecture: Option<SubArchitecture>) {
148        self.sub_architecture = sub_architecture;
149    }
150
151    /// Return the current mangling setting.
152    #[inline]
153    pub fn mangling(&self) -> Mangling {
154        self.mangling
155    }
156
157    /// Specify the mangling setting.
158    #[inline]
159    pub fn set_mangling(&mut self, mangling: Mangling) {
160        self.mangling = mangling;
161    }
162
163    /// Return the name for a standard segment.
164    ///
165    /// This will vary based on the file format.
166    #[allow(unused_variables)]
167    pub fn segment_name(&self, segment: StandardSegment) -> &'static [u8] {
168        match self.format {
169            #[cfg(feature = "coff")]
170            BinaryFormat::Coff => &[],
171            #[cfg(feature = "elf")]
172            BinaryFormat::Elf => &[],
173            #[cfg(feature = "macho")]
174            BinaryFormat::MachO => self.macho_segment_name(segment),
175            _ => unimplemented!(),
176        }
177    }
178
179    /// Get the section with the given `SectionId`.
180    #[inline]
181    pub fn section(&self, section: SectionId) -> &Section<'a> {
182        &self.sections[section.0]
183    }
184
185    /// Mutably get the section with the given `SectionId`.
186    #[inline]
187    pub fn section_mut(&mut self, section: SectionId) -> &mut Section<'a> {
188        &mut self.sections[section.0]
189    }
190
191    /// Set the data for an existing section.
192    ///
193    /// Must not be called for sections that already have data, or that contain uninitialized data.
194    /// `align` must be a power of two.
195    pub fn set_section_data<T>(&mut self, section: SectionId, data: T, align: u64)
196    where
197        T: Into<Cow<'a, [u8]>>,
198    {
199        self.sections[section.0].set_data(data, align)
200    }
201
202    /// Append data to an existing section. Returns the section offset of the data.
203    ///
204    /// Must not be called for sections that contain uninitialized data.
205    /// `align` must be a power of two.
206    pub fn append_section_data(&mut self, section: SectionId, data: &[u8], align: u64) -> u64 {
207        self.sections[section.0].append_data(data, align)
208    }
209
210    /// Append zero-initialized data to an existing section. Returns the section offset of the data.
211    ///
212    /// Must not be called for sections that contain initialized data.
213    /// `align` must be a power of two.
214    pub fn append_section_bss(&mut self, section: SectionId, size: u64, align: u64) -> u64 {
215        self.sections[section.0].append_bss(size, align)
216    }
217
218    /// Return the `SectionId` of a standard section.
219    ///
220    /// If the section doesn't already exist then it is created.
221    pub fn section_id(&mut self, section: StandardSection) -> SectionId {
222        self.standard_sections
223            .get(&section)
224            .cloned()
225            .unwrap_or_else(|| {
226                let (segment, name, kind, flags) = self.section_info(section);
227                let id = self.add_section(segment.to_vec(), name.to_vec(), kind);
228                self.section_mut(id).flags = flags;
229                id
230            })
231    }
232
233    /// Add a new section and return its `SectionId`.
234    ///
235    /// This also creates a section symbol.
236    pub fn add_section(&mut self, segment: Vec<u8>, name: Vec<u8>, kind: SectionKind) -> SectionId {
237        let id = SectionId(self.sections.len());
238        self.sections.push(Section {
239            segment,
240            name,
241            kind,
242            size: 0,
243            align: 1,
244            data: Cow::Borrowed(&[]),
245            relocations: Vec::new(),
246            symbol: None,
247            flags: SectionFlags::None,
248        });
249
250        // Add to self.standard_sections if required. This may match multiple standard sections.
251        let section = &self.sections[id.0];
252        for standard_section in StandardSection::all() {
253            if !self.standard_sections.contains_key(standard_section) {
254                let (segment, name, kind, _flags) = self.section_info(*standard_section);
255                if segment == &*section.segment && name == &*section.name && kind == section.kind {
256                    self.standard_sections.insert(*standard_section, id);
257                }
258            }
259        }
260
261        id
262    }
263
264    fn section_info(
265        &self,
266        section: StandardSection,
267    ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
268        match self.format {
269            #[cfg(feature = "coff")]
270            BinaryFormat::Coff => self.coff_section_info(section),
271            #[cfg(feature = "elf")]
272            BinaryFormat::Elf => self.elf_section_info(section),
273            #[cfg(feature = "macho")]
274            BinaryFormat::MachO => self.macho_section_info(section),
275            #[cfg(feature = "xcoff")]
276            BinaryFormat::Xcoff => self.xcoff_section_info(section),
277            _ => unimplemented!(),
278        }
279    }
280
281    /// Add a subsection. Returns the `SectionId` and section offset of the data.
282    ///
283    /// For Mach-O, this does not create a subsection, and instead uses the
284    /// section from [`Self::section_id`]. Use [`Self::set_subsections_via_symbols`]
285    /// to enable subsections via symbols.
286    pub fn add_subsection(&mut self, section: StandardSection, name: &[u8]) -> SectionId {
287        if self.has_subsections_via_symbols() {
288            self.section_id(section)
289        } else {
290            let (segment, name, kind, flags) = self.subsection_info(section, name);
291            let id = self.add_section(segment.to_vec(), name, kind);
292            self.section_mut(id).flags = flags;
293            id
294        }
295    }
296
297    fn has_subsections_via_symbols(&self) -> bool {
298        self.format == BinaryFormat::MachO
299    }
300
301    /// Enable subsections via symbols if supported.
302    ///
303    /// This should be called before adding any subsections or symbols.
304    ///
305    /// For Mach-O, this sets the `MH_SUBSECTIONS_VIA_SYMBOLS` flag.
306    /// For other formats, this does nothing.
307    pub fn set_subsections_via_symbols(&mut self) {
308        #[cfg(feature = "macho")]
309        if self.format == BinaryFormat::MachO {
310            self.macho_subsections_via_symbols = true;
311        }
312    }
313
314    fn subsection_info(
315        &self,
316        section: StandardSection,
317        value: &[u8],
318    ) -> (&'static [u8], Vec<u8>, SectionKind, SectionFlags) {
319        let (segment, section, kind, flags) = self.section_info(section);
320        let name = self.subsection_name(section, value);
321        (segment, name, kind, flags)
322    }
323
324    #[allow(unused_variables)]
325    fn subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> {
326        debug_assert!(!self.has_subsections_via_symbols());
327        match self.format {
328            #[cfg(feature = "coff")]
329            BinaryFormat::Coff => self.coff_subsection_name(section, value),
330            #[cfg(feature = "elf")]
331            BinaryFormat::Elf => self.elf_subsection_name(section, value),
332            _ => unimplemented!(),
333        }
334    }
335
336    /// Get the COMDAT section group with the given `ComdatId`.
337    #[inline]
338    pub fn comdat(&self, comdat: ComdatId) -> &Comdat {
339        &self.comdats[comdat.0]
340    }
341
342    /// Mutably get the COMDAT section group with the given `ComdatId`.
343    #[inline]
344    pub fn comdat_mut(&mut self, comdat: ComdatId) -> &mut Comdat {
345        &mut self.comdats[comdat.0]
346    }
347
348    /// Add a new COMDAT section group and return its `ComdatId`.
349    pub fn add_comdat(&mut self, comdat: Comdat) -> ComdatId {
350        let comdat_id = ComdatId(self.comdats.len());
351        self.comdats.push(comdat);
352        comdat_id
353    }
354
355    /// Get the `SymbolId` of the symbol with the given name.
356    pub fn symbol_id(&self, name: &[u8]) -> Option<SymbolId> {
357        self.symbol_map.get(name).cloned()
358    }
359
360    /// Get the symbol with the given `SymbolId`.
361    #[inline]
362    pub fn symbol(&self, symbol: SymbolId) -> &Symbol {
363        &self.symbols[symbol.0]
364    }
365
366    /// Mutably get the symbol with the given `SymbolId`.
367    #[inline]
368    pub fn symbol_mut(&mut self, symbol: SymbolId) -> &mut Symbol {
369        &mut self.symbols[symbol.0]
370    }
371
372    /// Add a new symbol and return its `SymbolId`.
373    pub fn add_symbol(&mut self, mut symbol: Symbol) -> SymbolId {
374        // Defined symbols must have a scope.
375        debug_assert!(symbol.is_undefined() || symbol.scope != SymbolScope::Unknown);
376        if symbol.kind == SymbolKind::Section {
377            // There can only be one section symbol, but update its flags, since
378            // the automatically generated section symbol will have none.
379            let symbol_id = self.section_symbol(symbol.section.id().unwrap());
380            if symbol.flags != SymbolFlags::None {
381                self.symbol_mut(symbol_id).flags = symbol.flags;
382            }
383            return symbol_id;
384        }
385        if !symbol.name.is_empty()
386            && (symbol.kind == SymbolKind::Text
387                || symbol.kind == SymbolKind::Data
388                || symbol.kind == SymbolKind::Tls)
389        {
390            let unmangled_name = symbol.name.clone();
391            if let Some(prefix) = self.mangling.global_prefix() {
392                symbol.name.insert(0, prefix);
393            }
394            let symbol_id = self.add_raw_symbol(symbol);
395            self.symbol_map.insert(unmangled_name, symbol_id);
396            symbol_id
397        } else {
398            self.add_raw_symbol(symbol)
399        }
400    }
401
402    fn add_raw_symbol(&mut self, symbol: Symbol) -> SymbolId {
403        let symbol_id = SymbolId(self.symbols.len());
404        self.symbols.push(symbol);
405        symbol_id
406    }
407
408    /// Return true if the file format supports `StandardSection::UninitializedTls`.
409    #[inline]
410    pub fn has_uninitialized_tls(&self) -> bool {
411        self.format != BinaryFormat::Coff
412    }
413
414    /// Return true if the file format supports `StandardSection::Common`.
415    #[inline]
416    pub fn has_common(&self) -> bool {
417        self.format == BinaryFormat::MachO
418    }
419
420    /// Add a new common symbol and return its `SymbolId`.
421    ///
422    /// For Mach-O, this appends the symbol to the `__common` section.
423    ///
424    /// `align` must be a power of two.
425    pub fn add_common_symbol(&mut self, mut symbol: Symbol, size: u64, align: u64) -> SymbolId {
426        if self.has_common() {
427            let symbol_id = self.add_symbol(symbol);
428            let section = self.section_id(StandardSection::Common);
429            self.add_symbol_bss(symbol_id, section, size, align);
430            symbol_id
431        } else {
432            symbol.section = SymbolSection::Common;
433            symbol.size = size;
434            self.add_symbol(symbol)
435        }
436    }
437
438    /// Add a new file symbol and return its `SymbolId`.
439    pub fn add_file_symbol(&mut self, name: Vec<u8>) -> SymbolId {
440        self.add_raw_symbol(Symbol {
441            name,
442            value: 0,
443            size: 0,
444            kind: SymbolKind::File,
445            scope: SymbolScope::Compilation,
446            weak: false,
447            section: SymbolSection::None,
448            flags: SymbolFlags::None,
449        })
450    }
451
452    /// Get the symbol for a section.
453    pub fn section_symbol(&mut self, section_id: SectionId) -> SymbolId {
454        let section = &mut self.sections[section_id.0];
455        if let Some(symbol) = section.symbol {
456            return symbol;
457        }
458        let name = if self.format == BinaryFormat::Coff {
459            section.name.clone()
460        } else {
461            Vec::new()
462        };
463        let symbol_id = SymbolId(self.symbols.len());
464        self.symbols.push(Symbol {
465            name,
466            value: 0,
467            size: 0,
468            kind: SymbolKind::Section,
469            scope: SymbolScope::Compilation,
470            weak: false,
471            section: SymbolSection::Section(section_id),
472            flags: SymbolFlags::None,
473        });
474        section.symbol = Some(symbol_id);
475        symbol_id
476    }
477
478    /// Append data to an existing section, and update a symbol to refer to it.
479    ///
480    /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the
481    /// symbol will indirectly point to the added data via the `__thread_vars` entry.
482    ///
483    /// For Mach-O, if [`Self::set_subsections_via_symbols`] is enabled, this will
484    /// automatically ensure the data size is at least 1.
485    ///
486    /// Returns the section offset of the data.
487    ///
488    /// Must not be called for sections that contain uninitialized data.
489    /// `align` must be a power of two.
490    pub fn add_symbol_data(
491        &mut self,
492        symbol_id: SymbolId,
493        section: SectionId,
494        #[cfg_attr(not(feature = "macho"), allow(unused_mut))] mut data: &[u8],
495        align: u64,
496    ) -> u64 {
497        #[cfg(feature = "macho")]
498        if data.is_empty() && self.macho_subsections_via_symbols {
499            data = &[0];
500        }
501        let offset = self.append_section_data(section, data, align);
502        self.set_symbol_data(symbol_id, section, offset, data.len() as u64);
503        offset
504    }
505
506    /// Append zero-initialized data to an existing section, and update a symbol to refer to it.
507    ///
508    /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the
509    /// symbol will indirectly point to the added data via the `__thread_vars` entry.
510    ///
511    /// For Mach-O, if [`Self::set_subsections_via_symbols`] is enabled, this will
512    /// automatically ensure the data size is at least 1.
513    ///
514    /// Returns the section offset of the data.
515    ///
516    /// Must not be called for sections that contain initialized data.
517    /// `align` must be a power of two.
518    pub fn add_symbol_bss(
519        &mut self,
520        symbol_id: SymbolId,
521        section: SectionId,
522        #[cfg_attr(not(feature = "macho"), allow(unused_mut))] mut size: u64,
523        align: u64,
524    ) -> u64 {
525        #[cfg(feature = "macho")]
526        if size == 0 && self.macho_subsections_via_symbols {
527            size = 1;
528        }
529        let offset = self.append_section_bss(section, size, align);
530        self.set_symbol_data(symbol_id, section, offset, size);
531        offset
532    }
533
534    /// Update a symbol to refer to the given data within a section.
535    ///
536    /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the
537    /// symbol will indirectly point to the data via the `__thread_vars` entry.
538    #[allow(unused_mut)]
539    pub fn set_symbol_data(
540        &mut self,
541        mut symbol_id: SymbolId,
542        section: SectionId,
543        offset: u64,
544        size: u64,
545    ) {
546        // Defined symbols must have a scope.
547        debug_assert!(self.symbol(symbol_id).scope != SymbolScope::Unknown);
548        match self.format {
549            #[cfg(feature = "macho")]
550            BinaryFormat::MachO => symbol_id = self.macho_add_thread_var(symbol_id),
551            _ => {}
552        }
553        let symbol = self.symbol_mut(symbol_id);
554        symbol.value = offset;
555        symbol.size = size;
556        symbol.section = SymbolSection::Section(section);
557    }
558
559    /// Convert a symbol to a section symbol and offset.
560    ///
561    /// Returns `None` if the symbol does not have a section.
562    pub fn symbol_section_and_offset(&mut self, symbol_id: SymbolId) -> Option<(SymbolId, u64)> {
563        let symbol = self.symbol(symbol_id);
564        if symbol.kind == SymbolKind::Section {
565            return Some((symbol_id, 0));
566        }
567        let symbol_offset = symbol.value;
568        let section = symbol.section.id()?;
569        let section_symbol = self.section_symbol(section);
570        Some((section_symbol, symbol_offset))
571    }
572
573    /// Add a relocation to a section.
574    ///
575    /// Relocations must only be added after the referenced symbols have been added
576    /// and defined (if applicable).
577    pub fn add_relocation(&mut self, section: SectionId, mut relocation: Relocation) -> Result<()> {
578        match self.format {
579            #[cfg(feature = "coff")]
580            BinaryFormat::Coff => self.coff_translate_relocation(&mut relocation)?,
581            #[cfg(feature = "elf")]
582            BinaryFormat::Elf => self.elf_translate_relocation(&mut relocation)?,
583            #[cfg(feature = "macho")]
584            BinaryFormat::MachO => self.macho_translate_relocation(&mut relocation)?,
585            #[cfg(feature = "xcoff")]
586            BinaryFormat::Xcoff => self.xcoff_translate_relocation(&mut relocation)?,
587            _ => unimplemented!(),
588        }
589        let implicit = match self.format {
590            #[cfg(feature = "coff")]
591            BinaryFormat::Coff => self.coff_adjust_addend(&mut relocation)?,
592            #[cfg(feature = "elf")]
593            BinaryFormat::Elf => self.elf_adjust_addend(&mut relocation)?,
594            #[cfg(feature = "macho")]
595            BinaryFormat::MachO => self.macho_adjust_addend(&mut relocation)?,
596            #[cfg(feature = "xcoff")]
597            BinaryFormat::Xcoff => self.xcoff_adjust_addend(&mut relocation)?,
598            _ => unimplemented!(),
599        };
600        if implicit && relocation.addend != 0 {
601            self.write_relocation_addend(section, &relocation)?;
602            relocation.addend = 0;
603        }
604        self.sections[section.0].relocations.push(relocation);
605        Ok(())
606    }
607
608    fn write_relocation_addend(
609        &mut self,
610        section: SectionId,
611        relocation: &Relocation,
612    ) -> Result<()> {
613        let size = match self.format {
614            #[cfg(feature = "coff")]
615            BinaryFormat::Coff => self.coff_relocation_size(relocation)?,
616            #[cfg(feature = "elf")]
617            BinaryFormat::Elf => self.elf_relocation_size(relocation)?,
618            #[cfg(feature = "macho")]
619            BinaryFormat::MachO => self.macho_relocation_size(relocation)?,
620            #[cfg(feature = "xcoff")]
621            BinaryFormat::Xcoff => self.xcoff_relocation_size(relocation)?,
622            _ => unimplemented!(),
623        };
624        let data = self.sections[section.0].data_mut();
625        let offset = relocation.offset as usize;
626        match size {
627            32 => data.write_at(offset, &U32::new(self.endian, relocation.addend as u32)),
628            64 => data.write_at(offset, &U64::new(self.endian, relocation.addend as u64)),
629            _ => {
630                return Err(Error(format!(
631                    "unimplemented relocation addend {:?}",
632                    relocation
633                )));
634            }
635        }
636        .map_err(|_| {
637            Error(format!(
638                "invalid relocation offset {}+{} (max {})",
639                relocation.offset,
640                size,
641                data.len()
642            ))
643        })
644    }
645
646    /// Write the object to a `Vec`.
647    pub fn write(&self) -> Result<Vec<u8>> {
648        let mut buffer = Vec::new();
649        self.emit(&mut buffer)?;
650        Ok(buffer)
651    }
652
653    /// Write the object to a `Write` implementation.
654    ///
655    /// Also flushes the writer.
656    ///
657    /// It is advisable to use a buffered writer like [`BufWriter`](std::io::BufWriter)
658    /// instead of an unbuffered writer like [`File`](std::fs::File).
659    #[cfg(feature = "std")]
660    pub fn write_stream<W: io::Write>(&self, w: W) -> result::Result<(), Box<dyn error::Error>> {
661        let mut stream = StreamingBuffer::new(w);
662        self.emit(&mut stream)?;
663        stream.result()?;
664        stream.into_inner().flush()?;
665        Ok(())
666    }
667
668    /// Write the object to a `WritableBuffer`.
669    pub fn emit(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
670        match self.format {
671            #[cfg(feature = "coff")]
672            BinaryFormat::Coff => self.coff_write(buffer),
673            #[cfg(feature = "elf")]
674            BinaryFormat::Elf => self.elf_write(buffer),
675            #[cfg(feature = "macho")]
676            BinaryFormat::MachO => self.macho_write(buffer),
677            #[cfg(feature = "xcoff")]
678            BinaryFormat::Xcoff => self.xcoff_write(buffer),
679            _ => unimplemented!(),
680        }
681    }
682}
683
684/// A standard segment kind.
685#[allow(missing_docs)]
686#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
687#[non_exhaustive]
688pub enum StandardSegment {
689    Text,
690    Data,
691    Debug,
692}
693
694/// A standard section kind.
695#[allow(missing_docs)]
696#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
697#[non_exhaustive]
698pub enum StandardSection {
699    Text,
700    Data,
701    ReadOnlyData,
702    ReadOnlyDataWithRel,
703    ReadOnlyString,
704    UninitializedData,
705    Tls,
706    /// Zero-fill TLS initializers. Unsupported for COFF.
707    UninitializedTls,
708    /// TLS variable structures. Only supported for Mach-O.
709    TlsVariables,
710    /// Common data. Only supported for Mach-O.
711    Common,
712    /// Notes for GNU properties. Only supported for ELF.
713    GnuProperty,
714}
715
716impl StandardSection {
717    /// Return the section kind of a standard section.
718    pub fn kind(self) -> SectionKind {
719        match self {
720            StandardSection::Text => SectionKind::Text,
721            StandardSection::Data => SectionKind::Data,
722            StandardSection::ReadOnlyData => SectionKind::ReadOnlyData,
723            StandardSection::ReadOnlyDataWithRel => SectionKind::ReadOnlyDataWithRel,
724            StandardSection::ReadOnlyString => SectionKind::ReadOnlyString,
725            StandardSection::UninitializedData => SectionKind::UninitializedData,
726            StandardSection::Tls => SectionKind::Tls,
727            StandardSection::UninitializedTls => SectionKind::UninitializedTls,
728            StandardSection::TlsVariables => SectionKind::TlsVariables,
729            StandardSection::Common => SectionKind::Common,
730            StandardSection::GnuProperty => SectionKind::Note,
731        }
732    }
733
734    // TODO: remembering to update this is error-prone, can we do better?
735    fn all() -> &'static [StandardSection] {
736        &[
737            StandardSection::Text,
738            StandardSection::Data,
739            StandardSection::ReadOnlyData,
740            StandardSection::ReadOnlyDataWithRel,
741            StandardSection::ReadOnlyString,
742            StandardSection::UninitializedData,
743            StandardSection::Tls,
744            StandardSection::UninitializedTls,
745            StandardSection::TlsVariables,
746            StandardSection::Common,
747            StandardSection::GnuProperty,
748        ]
749    }
750}
751
752/// An identifier used to reference a section.
753#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
754pub struct SectionId(usize);
755
756/// A section in an object file.
757#[derive(Debug)]
758pub struct Section<'a> {
759    segment: Vec<u8>,
760    name: Vec<u8>,
761    kind: SectionKind,
762    size: u64,
763    align: u64,
764    data: Cow<'a, [u8]>,
765    relocations: Vec<Relocation>,
766    symbol: Option<SymbolId>,
767    /// Section flags that are specific to each file format.
768    pub flags: SectionFlags,
769}
770
771impl<'a> Section<'a> {
772    /// Try to convert the name to a utf8 string.
773    #[inline]
774    pub fn name(&self) -> Option<&str> {
775        str::from_utf8(&self.name).ok()
776    }
777
778    /// Try to convert the segment to a utf8 string.
779    #[inline]
780    pub fn segment(&self) -> Option<&str> {
781        str::from_utf8(&self.segment).ok()
782    }
783
784    /// Return true if this section contains zerofill data.
785    #[inline]
786    pub fn is_bss(&self) -> bool {
787        self.kind.is_bss()
788    }
789
790    /// Set the data for a section.
791    ///
792    /// Must not be called for sections that already have data, or that contain uninitialized data.
793    /// `align` must be a power of two.
794    pub fn set_data<T>(&mut self, data: T, align: u64)
795    where
796        T: Into<Cow<'a, [u8]>>,
797    {
798        debug_assert!(!self.is_bss());
799        debug_assert_eq!(align & (align - 1), 0);
800        debug_assert!(self.data.is_empty());
801        self.data = data.into();
802        self.size = self.data.len() as u64;
803        self.align = align;
804    }
805
806    /// Append data to a section.
807    ///
808    /// Must not be called for sections that contain uninitialized data.
809    /// `align` must be a power of two.
810    pub fn append_data(&mut self, append_data: &[u8], align: u64) -> u64 {
811        debug_assert!(!self.is_bss());
812        debug_assert_eq!(align & (align - 1), 0);
813        if self.align < align {
814            self.align = align;
815        }
816        let align = align as usize;
817        let data = self.data.to_mut();
818        let mut offset = data.len();
819        if offset & (align - 1) != 0 {
820            offset += align - (offset & (align - 1));
821            data.resize(offset, 0);
822        }
823        data.extend_from_slice(append_data);
824        self.size = data.len() as u64;
825        offset as u64
826    }
827
828    /// Append uninitialized data to a section.
829    ///
830    /// Must not be called for sections that contain initialized data.
831    /// `align` must be a power of two.
832    pub fn append_bss(&mut self, size: u64, align: u64) -> u64 {
833        debug_assert!(self.is_bss());
834        debug_assert_eq!(align & (align - 1), 0);
835        if self.align < align {
836            self.align = align;
837        }
838        let mut offset = self.size;
839        if offset & (align - 1) != 0 {
840            offset += align - (offset & (align - 1));
841            self.size = offset;
842        }
843        self.size += size;
844        offset
845    }
846
847    /// Returns the section as-built so far.
848    ///
849    /// This requires that the section is not a bss section.
850    pub fn data(&self) -> &[u8] {
851        debug_assert!(!self.is_bss());
852        &self.data
853    }
854
855    /// Returns the section as-built so far.
856    ///
857    /// This requires that the section is not a bss section.
858    pub fn data_mut(&mut self) -> &mut [u8] {
859        debug_assert!(!self.is_bss());
860        self.data.to_mut()
861    }
862}
863
864/// The section where a symbol is defined.
865#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
866#[non_exhaustive]
867pub enum SymbolSection {
868    /// The section is not applicable for this symbol (such as file symbols).
869    None,
870    /// The symbol is undefined.
871    Undefined,
872    /// The symbol has an absolute value.
873    Absolute,
874    /// The symbol is a zero-initialized symbol that will be combined with duplicate definitions.
875    Common,
876    /// The symbol is defined in the given section.
877    Section(SectionId),
878}
879
880impl SymbolSection {
881    /// Returns the section id for the section where the symbol is defined.
882    ///
883    /// May return `None` if the symbol is not defined in a section.
884    #[inline]
885    pub fn id(self) -> Option<SectionId> {
886        if let SymbolSection::Section(id) = self {
887            Some(id)
888        } else {
889            None
890        }
891    }
892}
893
894/// An identifier used to reference a symbol.
895#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
896pub struct SymbolId(usize);
897
898/// A symbol in an object file.
899#[derive(Debug)]
900pub struct Symbol {
901    /// The name of the symbol.
902    pub name: Vec<u8>,
903    /// The value of the symbol.
904    ///
905    /// If the symbol defined in a section, then this is the section offset of the symbol.
906    pub value: u64,
907    /// The size of the symbol.
908    pub size: u64,
909    /// The kind of the symbol.
910    pub kind: SymbolKind,
911    /// The scope of the symbol.
912    pub scope: SymbolScope,
913    /// Whether the symbol has weak binding.
914    pub weak: bool,
915    /// The section containing the symbol.
916    pub section: SymbolSection,
917    /// Symbol flags that are specific to each file format.
918    pub flags: SymbolFlags<SectionId, SymbolId>,
919}
920
921impl Symbol {
922    /// Try to convert the name to a utf8 string.
923    #[inline]
924    pub fn name(&self) -> Option<&str> {
925        str::from_utf8(&self.name).ok()
926    }
927
928    /// Return true if the symbol is undefined.
929    #[inline]
930    pub fn is_undefined(&self) -> bool {
931        self.section == SymbolSection::Undefined
932    }
933
934    /// Return true if the symbol is common data.
935    ///
936    /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`.
937    #[inline]
938    pub fn is_common(&self) -> bool {
939        self.section == SymbolSection::Common
940    }
941
942    /// Return true if the symbol scope is local.
943    #[inline]
944    pub fn is_local(&self) -> bool {
945        self.scope == SymbolScope::Compilation
946    }
947}
948
949/// A relocation in an object file.
950#[derive(Debug)]
951pub struct Relocation {
952    /// The section offset of the place of the relocation.
953    pub offset: u64,
954    /// The symbol referred to by the relocation.
955    ///
956    /// This may be a section symbol.
957    pub symbol: SymbolId,
958    /// The addend to use in the relocation calculation.
959    ///
960    /// This may be in addition to an implicit addend stored at the place of the relocation.
961    pub addend: i64,
962    /// The fields that define the relocation type.
963    pub flags: RelocationFlags,
964}
965
966/// An identifier used to reference a COMDAT section group.
967#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
968pub struct ComdatId(usize);
969
970/// A COMDAT section group.
971#[derive(Debug)]
972pub struct Comdat {
973    /// The COMDAT selection kind.
974    ///
975    /// This determines the way in which the linker resolves multiple definitions of the COMDAT
976    /// sections.
977    pub kind: ComdatKind,
978    /// The COMDAT symbol.
979    ///
980    /// If this symbol is referenced, then all sections in the group will be included by the
981    /// linker.
982    pub symbol: SymbolId,
983    /// The sections in the group.
984    pub sections: Vec<SectionId>,
985}
986
987/// The symbol name mangling scheme.
988#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
989#[non_exhaustive]
990pub enum Mangling {
991    /// No symbol mangling.
992    None,
993    /// Windows COFF symbol mangling.
994    Coff,
995    /// Windows COFF i386 symbol mangling.
996    CoffI386,
997    /// ELF symbol mangling.
998    Elf,
999    /// Mach-O symbol mangling.
1000    MachO,
1001    /// Xcoff symbol mangling.
1002    Xcoff,
1003}
1004
1005impl Mangling {
1006    /// Return the default symboling mangling for the given format and architecture.
1007    pub fn default(format: BinaryFormat, architecture: Architecture) -> Self {
1008        match (format, architecture) {
1009            (BinaryFormat::Coff, Architecture::I386) => Mangling::CoffI386,
1010            (BinaryFormat::Coff, _) => Mangling::Coff,
1011            (BinaryFormat::Elf, _) => Mangling::Elf,
1012            (BinaryFormat::MachO, _) => Mangling::MachO,
1013            (BinaryFormat::Xcoff, _) => Mangling::Xcoff,
1014            _ => Mangling::None,
1015        }
1016    }
1017
1018    /// Return the prefix to use for global symbols.
1019    pub fn global_prefix(self) -> Option<u8> {
1020        match self {
1021            Mangling::None | Mangling::Elf | Mangling::Coff | Mangling::Xcoff => None,
1022            Mangling::CoffI386 | Mangling::MachO => Some(b'_'),
1023        }
1024    }
1025}