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    /// Return the default flags for a section.
337    ///
338    /// The default flags are the section flags that will be written if
339    /// the section flags are set to `SectionFlags::None`.
340    /// These flags are determined by the file format and fields in the section
341    /// such as the section kind.
342    ///
343    /// This may return `SectionFlags::None` if the file format does not support
344    /// the section kind.
345    pub fn default_section_flags(&self, section: &Section<'_>) -> SectionFlags {
346        match self.format {
347            #[cfg(feature = "coff")]
348            BinaryFormat::Coff => self.coff_section_flags(section),
349            #[cfg(feature = "elf")]
350            BinaryFormat::Elf => self.elf_section_flags(section),
351            #[cfg(feature = "macho")]
352            BinaryFormat::MachO => self.macho_section_flags(section),
353            #[cfg(feature = "xcoff")]
354            BinaryFormat::Xcoff => self.xcoff_section_flags(section),
355            _ => SectionFlags::None,
356        }
357    }
358
359    /// Return the flags for a section.
360    ///
361    /// If `section.flags` is `SectionFlags::None`, then returns
362    /// [`Self::default_section_flags`].
363    /// Otherwise, `section.flags` is returned as is.
364    pub fn section_flags(&self, section: &Section<'_>) -> SectionFlags {
365        if section.flags != SectionFlags::None {
366            section.flags
367        } else {
368            self.default_section_flags(section)
369        }
370    }
371
372    /// Mutably get the flags for a section.
373    ///
374    /// If `section.flags` is `SectionFlags::None`, then replace it with
375    /// [`Self::default_section_flags`] first.
376    /// Otherwise, `&mut section.flags` is returned as is.
377    pub fn section_flags_mut(&mut self, section_id: SectionId) -> &mut SectionFlags {
378        if self.section(section_id).flags != SectionFlags::None {
379            &mut self.section_mut(section_id).flags
380        } else {
381            let flags = self.default_section_flags(self.section(section_id));
382            let section = self.section_mut(section_id);
383            section.flags = flags;
384            &mut section.flags
385        }
386    }
387
388    /// Get the COMDAT section group with the given `ComdatId`.
389    #[inline]
390    pub fn comdat(&self, comdat: ComdatId) -> &Comdat {
391        &self.comdats[comdat.0]
392    }
393
394    /// Mutably get the COMDAT section group with the given `ComdatId`.
395    #[inline]
396    pub fn comdat_mut(&mut self, comdat: ComdatId) -> &mut Comdat {
397        &mut self.comdats[comdat.0]
398    }
399
400    /// Add a new COMDAT section group and return its `ComdatId`.
401    pub fn add_comdat(&mut self, comdat: Comdat) -> ComdatId {
402        let comdat_id = ComdatId(self.comdats.len());
403        self.comdats.push(comdat);
404        comdat_id
405    }
406
407    /// Get the `SymbolId` of the symbol with the given name.
408    pub fn symbol_id(&self, name: &[u8]) -> Option<SymbolId> {
409        self.symbol_map.get(name).cloned()
410    }
411
412    /// Get the symbol with the given `SymbolId`.
413    #[inline]
414    pub fn symbol(&self, symbol: SymbolId) -> &Symbol {
415        &self.symbols[symbol.0]
416    }
417
418    /// Mutably get the symbol with the given `SymbolId`.
419    #[inline]
420    pub fn symbol_mut(&mut self, symbol: SymbolId) -> &mut Symbol {
421        &mut self.symbols[symbol.0]
422    }
423
424    /// Add a new symbol and return its `SymbolId`.
425    ///
426    /// If the symbol is a section symbol that is already defined,
427    /// it will update the flags of the existing section symbol
428    /// instead of creating adding a new symbol.
429    ///
430    /// The symbol name will be modified to include the global prefix
431    /// if the mangling scheme has one.
432    pub fn add_symbol(&mut self, mut symbol: Symbol) -> SymbolId {
433        // Defined symbols must have a scope.
434        debug_assert!(symbol.is_undefined() || symbol.scope != SymbolScope::Unknown);
435        if symbol.kind == SymbolKind::Section {
436            // There can only be one section symbol, but update its flags, since
437            // the automatically generated section symbol will have none.
438            let symbol_id = self.section_symbol(symbol.section.id().unwrap());
439            if symbol.flags != SymbolFlags::None {
440                self.symbol_mut(symbol_id).flags = symbol.flags;
441            }
442            return symbol_id;
443        }
444        if !symbol.name.is_empty()
445            && (symbol.kind == SymbolKind::Text
446                || symbol.kind == SymbolKind::Data
447                || symbol.kind == SymbolKind::Tls)
448        {
449            let unmangled_name = symbol.name.clone();
450            if let Some(prefix) = self.mangling.global_prefix() {
451                symbol.name.insert(0, prefix);
452            }
453            let symbol_id = self.add_raw_symbol(symbol);
454            self.symbol_map.insert(unmangled_name, symbol_id);
455            symbol_id
456        } else {
457            self.add_raw_symbol(symbol)
458        }
459    }
460
461    fn add_raw_symbol(&mut self, symbol: Symbol) -> SymbolId {
462        let symbol_id = SymbolId(self.symbols.len());
463        self.symbols.push(symbol);
464        symbol_id
465    }
466
467    /// Return the default flags for a symbol.
468    ///
469    /// The default flags are the symbol flags that will be written if the
470    /// symbol flags are set to `SymbolFlags::None`. These flags are determined
471    /// by the file format and fields in the symbol such as the symbol kind and
472    /// scope. Therefore you should call this function after the symbol
473    /// has been fully defined.
474    ///
475    /// This may return `SymbolFlags::None` if the file format does not
476    /// support symbol flags, or does not support the symbol kind or scope.
477    pub fn default_symbol_flags(&self, symbol: &Symbol) -> SymbolFlags<SectionId, SymbolId> {
478        match self.format {
479            #[cfg(feature = "coff")]
480            BinaryFormat::Coff => self.coff_symbol_flags(symbol),
481            #[cfg(feature = "elf")]
482            BinaryFormat::Elf => self.elf_symbol_flags(symbol),
483            #[cfg(feature = "macho")]
484            BinaryFormat::MachO => self.macho_symbol_flags(symbol),
485            #[cfg(feature = "xcoff")]
486            BinaryFormat::Xcoff => self.xcoff_symbol_flags(symbol),
487            _ => SymbolFlags::None,
488        }
489    }
490
491    /// Return the flags for a symbol.
492    ///
493    /// If `symbol.flags` is `SymbolFlags::None`, then returns
494    /// [`Self::default_symbol_flags`].
495    /// Otherwise, `symbol.flags` is returned as is.
496    pub fn symbol_flags(&self, symbol: &Symbol) -> SymbolFlags<SectionId, SymbolId> {
497        if symbol.flags != SymbolFlags::None {
498            symbol.flags
499        } else {
500            self.default_symbol_flags(symbol)
501        }
502    }
503
504    /// Mutably get the flags for a symbol.
505    ///
506    /// If `symbol.flags` is `SymbolFlags::None`, then replace it with
507    /// [`Self::default_symbol_flags`].
508    /// Otherwise, `&mut symbol.flags` is returned as is.
509    pub fn symbol_flags_mut(
510        &mut self,
511        symbol_id: SymbolId,
512    ) -> &mut SymbolFlags<SectionId, SymbolId> {
513        if self.symbol(symbol_id).flags != SymbolFlags::None {
514            &mut self.symbol_mut(symbol_id).flags
515        } else {
516            let flags = self.default_symbol_flags(self.symbol(symbol_id));
517            let symbol = self.symbol_mut(symbol_id);
518            symbol.flags = flags;
519            &mut symbol.flags
520        }
521    }
522
523    /// Return true if the file format supports `StandardSection::UninitializedTls`.
524    #[inline]
525    pub fn has_uninitialized_tls(&self) -> bool {
526        self.format != BinaryFormat::Coff
527    }
528
529    /// Return true if the file format supports `StandardSection::Common`.
530    #[inline]
531    pub fn has_common(&self) -> bool {
532        self.format == BinaryFormat::MachO
533    }
534
535    /// Add a new common symbol and return its `SymbolId`.
536    ///
537    /// For Mach-O, this appends the symbol to the `__common` section.
538    ///
539    /// `align` must be a power of two.
540    pub fn add_common_symbol(&mut self, mut symbol: Symbol, size: u64, align: u64) -> SymbolId {
541        if self.has_common() {
542            let symbol_id = self.add_symbol(symbol);
543            let section = self.section_id(StandardSection::Common);
544            self.add_symbol_bss(symbol_id, section, size, align);
545            symbol_id
546        } else {
547            symbol.section = SymbolSection::Common;
548            symbol.size = size;
549            self.add_symbol(symbol)
550        }
551    }
552
553    /// Add a new file symbol and return its `SymbolId`.
554    pub fn add_file_symbol(&mut self, name: Vec<u8>) -> SymbolId {
555        self.add_raw_symbol(Symbol {
556            name,
557            value: 0,
558            size: 0,
559            kind: SymbolKind::File,
560            scope: SymbolScope::Compilation,
561            weak: false,
562            section: SymbolSection::None,
563            flags: SymbolFlags::None,
564        })
565    }
566
567    /// Get the symbol for a section.
568    pub fn section_symbol(&mut self, section_id: SectionId) -> SymbolId {
569        let section = &mut self.sections[section_id.0];
570        if let Some(symbol) = section.symbol {
571            return symbol;
572        }
573        let name = if self.format == BinaryFormat::Coff {
574            section.name.clone()
575        } else {
576            Vec::new()
577        };
578        let symbol_id = SymbolId(self.symbols.len());
579        self.symbols.push(Symbol {
580            name,
581            value: 0,
582            size: 0,
583            kind: SymbolKind::Section,
584            scope: SymbolScope::Compilation,
585            weak: false,
586            section: SymbolSection::Section(section_id),
587            flags: SymbolFlags::None,
588        });
589        section.symbol = Some(symbol_id);
590        symbol_id
591    }
592
593    /// Append data to an existing section, and update a symbol to refer to it.
594    ///
595    /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the
596    /// symbol will indirectly point to the added data via the `__thread_vars` entry.
597    ///
598    /// For Mach-O, if [`Self::set_subsections_via_symbols`] is enabled, this will
599    /// automatically ensure the data size is at least 1.
600    ///
601    /// Returns the section offset of the data.
602    ///
603    /// Must not be called for sections that contain uninitialized data.
604    /// `align` must be a power of two.
605    pub fn add_symbol_data(
606        &mut self,
607        symbol_id: SymbolId,
608        section: SectionId,
609        #[cfg_attr(not(feature = "macho"), allow(unused_mut))] mut data: &[u8],
610        align: u64,
611    ) -> u64 {
612        #[cfg(feature = "macho")]
613        if data.is_empty() && self.macho_subsections_via_symbols {
614            data = &[0];
615        }
616        let offset = self.append_section_data(section, data, align);
617        self.set_symbol_data(symbol_id, section, offset, data.len() as u64);
618        offset
619    }
620
621    /// Append zero-initialized data to an existing section, and update a symbol to refer to it.
622    ///
623    /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the
624    /// symbol will indirectly point to the added data via the `__thread_vars` entry.
625    ///
626    /// For Mach-O, if [`Self::set_subsections_via_symbols`] is enabled, this will
627    /// automatically ensure the data size is at least 1.
628    ///
629    /// Returns the section offset of the data.
630    ///
631    /// Must not be called for sections that contain initialized data.
632    /// `align` must be a power of two.
633    pub fn add_symbol_bss(
634        &mut self,
635        symbol_id: SymbolId,
636        section: SectionId,
637        #[cfg_attr(not(feature = "macho"), allow(unused_mut))] mut size: u64,
638        align: u64,
639    ) -> u64 {
640        #[cfg(feature = "macho")]
641        if size == 0 && self.macho_subsections_via_symbols {
642            size = 1;
643        }
644        let offset = self.append_section_bss(section, size, align);
645        self.set_symbol_data(symbol_id, section, offset, size);
646        offset
647    }
648
649    /// Update a symbol to refer to the given data within a section.
650    ///
651    /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the
652    /// symbol will indirectly point to the data via the `__thread_vars` entry.
653    #[allow(unused_mut)]
654    pub fn set_symbol_data(
655        &mut self,
656        mut symbol_id: SymbolId,
657        section: SectionId,
658        offset: u64,
659        size: u64,
660    ) {
661        // Defined symbols must have a scope.
662        debug_assert!(self.symbol(symbol_id).scope != SymbolScope::Unknown);
663        match self.format {
664            #[cfg(feature = "macho")]
665            BinaryFormat::MachO => symbol_id = self.macho_add_thread_var(symbol_id),
666            _ => {}
667        }
668        let symbol = self.symbol_mut(symbol_id);
669        symbol.value = offset;
670        symbol.size = size;
671        symbol.section = SymbolSection::Section(section);
672    }
673
674    /// Convert a symbol to a section symbol and offset.
675    ///
676    /// Returns `None` if the symbol does not have a section.
677    pub fn symbol_section_and_offset(&mut self, symbol_id: SymbolId) -> Option<(SymbolId, u64)> {
678        let symbol = self.symbol(symbol_id);
679        if symbol.kind == SymbolKind::Section {
680            return Some((symbol_id, 0));
681        }
682        let symbol_offset = symbol.value;
683        let section = symbol.section.id()?;
684        let section_symbol = self.section_symbol(section);
685        Some((section_symbol, symbol_offset))
686    }
687
688    /// Add a relocation to a section.
689    ///
690    /// Relocations must only be added after the referenced symbols have been added
691    /// and defined (if applicable).
692    pub fn add_relocation(&mut self, section: SectionId, mut relocation: Relocation) -> Result<()> {
693        match self.format {
694            #[cfg(feature = "coff")]
695            BinaryFormat::Coff => self.coff_translate_relocation(&mut relocation)?,
696            #[cfg(feature = "elf")]
697            BinaryFormat::Elf => self.elf_translate_relocation(&mut relocation)?,
698            #[cfg(feature = "macho")]
699            BinaryFormat::MachO => self.macho_translate_relocation(&mut relocation)?,
700            #[cfg(feature = "xcoff")]
701            BinaryFormat::Xcoff => self.xcoff_translate_relocation(&mut relocation)?,
702            _ => unimplemented!(),
703        }
704        let implicit = match self.format {
705            #[cfg(feature = "coff")]
706            BinaryFormat::Coff => self.coff_adjust_addend(&mut relocation)?,
707            #[cfg(feature = "elf")]
708            BinaryFormat::Elf => self.elf_adjust_addend(&mut relocation)?,
709            #[cfg(feature = "macho")]
710            BinaryFormat::MachO => self.macho_adjust_addend(&mut relocation)?,
711            #[cfg(feature = "xcoff")]
712            BinaryFormat::Xcoff => self.xcoff_adjust_addend(&mut relocation)?,
713            _ => unimplemented!(),
714        };
715        if implicit && relocation.addend != 0 {
716            self.write_relocation_addend(section, &relocation)?;
717            relocation.addend = 0;
718        }
719        self.sections[section.0].relocations.push(relocation);
720        Ok(())
721    }
722
723    fn write_relocation_addend(
724        &mut self,
725        section: SectionId,
726        relocation: &Relocation,
727    ) -> Result<()> {
728        let size = match self.format {
729            #[cfg(feature = "coff")]
730            BinaryFormat::Coff => self.coff_relocation_size(relocation)?,
731            #[cfg(feature = "elf")]
732            BinaryFormat::Elf => self.elf_relocation_size(relocation)?,
733            #[cfg(feature = "macho")]
734            BinaryFormat::MachO => self.macho_relocation_size(relocation)?,
735            #[cfg(feature = "xcoff")]
736            BinaryFormat::Xcoff => self.xcoff_relocation_size(relocation)?,
737            _ => unimplemented!(),
738        };
739        let data = self.sections[section.0].data_mut();
740        let offset = relocation.offset as usize;
741        match size {
742            32 => data.write_at(offset, &U32::new(self.endian, relocation.addend as u32)),
743            64 => data.write_at(offset, &U64::new(self.endian, relocation.addend as u64)),
744            _ => {
745                return Err(Error(format!(
746                    "unimplemented relocation addend {:?}",
747                    relocation
748                )));
749            }
750        }
751        .map_err(|_| {
752            Error(format!(
753                "invalid relocation offset {}+{} (max {})",
754                relocation.offset,
755                size,
756                data.len()
757            ))
758        })
759    }
760
761    /// Write the object to a `Vec`.
762    pub fn write(&self) -> Result<Vec<u8>> {
763        let mut buffer = Vec::new();
764        self.emit(&mut buffer)?;
765        Ok(buffer)
766    }
767
768    /// Write the object to a `Write` implementation.
769    ///
770    /// Also flushes the writer.
771    ///
772    /// It is advisable to use a buffered writer like [`BufWriter`](std::io::BufWriter)
773    /// instead of an unbuffered writer like [`File`](std::fs::File).
774    #[cfg(feature = "std")]
775    pub fn write_stream<W: io::Write>(&self, w: W) -> result::Result<(), Box<dyn error::Error>> {
776        let mut stream = StreamingBuffer::new(w);
777        self.emit(&mut stream)?;
778        stream.result()?;
779        stream.into_inner().flush()?;
780        Ok(())
781    }
782
783    /// Write the object to a `WritableBuffer`.
784    pub fn emit(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
785        match self.format {
786            #[cfg(feature = "coff")]
787            BinaryFormat::Coff => self.coff_write(buffer),
788            #[cfg(feature = "elf")]
789            BinaryFormat::Elf => self.elf_write(buffer),
790            #[cfg(feature = "macho")]
791            BinaryFormat::MachO => self.macho_write(buffer),
792            #[cfg(feature = "xcoff")]
793            BinaryFormat::Xcoff => self.xcoff_write(buffer),
794            _ => unimplemented!(),
795        }
796    }
797}
798
799/// A standard segment kind.
800#[allow(missing_docs)]
801#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
802#[non_exhaustive]
803pub enum StandardSegment {
804    Text,
805    Data,
806    Debug,
807}
808
809/// A standard section kind.
810#[allow(missing_docs)]
811#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
812#[non_exhaustive]
813pub enum StandardSection {
814    Text,
815    Data,
816    ReadOnlyData,
817    ReadOnlyDataWithRel,
818    ReadOnlyString,
819    UninitializedData,
820    Tls,
821    /// Zero-fill TLS initializers. Unsupported for COFF.
822    UninitializedTls,
823    /// TLS variable structures. Only supported for Mach-O.
824    TlsVariables,
825    /// Common data. Only supported for Mach-O.
826    Common,
827    /// Notes for GNU properties. Only supported for ELF.
828    GnuProperty,
829}
830
831impl StandardSection {
832    /// Return the section kind of a standard section.
833    pub fn kind(self) -> SectionKind {
834        match self {
835            StandardSection::Text => SectionKind::Text,
836            StandardSection::Data => SectionKind::Data,
837            StandardSection::ReadOnlyData => SectionKind::ReadOnlyData,
838            StandardSection::ReadOnlyDataWithRel => SectionKind::ReadOnlyDataWithRel,
839            StandardSection::ReadOnlyString => SectionKind::ReadOnlyString,
840            StandardSection::UninitializedData => SectionKind::UninitializedData,
841            StandardSection::Tls => SectionKind::Tls,
842            StandardSection::UninitializedTls => SectionKind::UninitializedTls,
843            StandardSection::TlsVariables => SectionKind::TlsVariables,
844            StandardSection::Common => SectionKind::Common,
845            StandardSection::GnuProperty => SectionKind::Note,
846        }
847    }
848
849    // TODO: remembering to update this is error-prone, can we do better?
850    fn all() -> &'static [StandardSection] {
851        &[
852            StandardSection::Text,
853            StandardSection::Data,
854            StandardSection::ReadOnlyData,
855            StandardSection::ReadOnlyDataWithRel,
856            StandardSection::ReadOnlyString,
857            StandardSection::UninitializedData,
858            StandardSection::Tls,
859            StandardSection::UninitializedTls,
860            StandardSection::TlsVariables,
861            StandardSection::Common,
862            StandardSection::GnuProperty,
863        ]
864    }
865}
866
867/// An identifier used to reference a section.
868#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
869pub struct SectionId(usize);
870
871/// A section in an object file.
872#[derive(Debug)]
873pub struct Section<'a> {
874    segment: Vec<u8>,
875    name: Vec<u8>,
876    kind: SectionKind,
877    size: u64,
878    align: u64,
879    data: Cow<'a, [u8]>,
880    relocations: Vec<Relocation>,
881    symbol: Option<SymbolId>,
882    /// Section flags that are specific to each file format.
883    pub flags: SectionFlags,
884}
885
886impl<'a> Section<'a> {
887    /// Try to convert the name to a utf8 string.
888    #[inline]
889    pub fn name(&self) -> Option<&str> {
890        str::from_utf8(&self.name).ok()
891    }
892
893    /// Try to convert the segment to a utf8 string.
894    #[inline]
895    pub fn segment(&self) -> Option<&str> {
896        str::from_utf8(&self.segment).ok()
897    }
898
899    /// Return true if this section contains zerofill data.
900    #[inline]
901    pub fn is_bss(&self) -> bool {
902        self.kind.is_bss()
903    }
904
905    /// Set the data for a section.
906    ///
907    /// Must not be called for sections that already have data, or that contain uninitialized data.
908    /// `align` must be a power of two.
909    pub fn set_data<T>(&mut self, data: T, align: u64)
910    where
911        T: Into<Cow<'a, [u8]>>,
912    {
913        debug_assert!(!self.is_bss());
914        debug_assert_eq!(align & (align - 1), 0);
915        debug_assert!(self.data.is_empty());
916        self.data = data.into();
917        self.size = self.data.len() as u64;
918        self.align = align;
919    }
920
921    /// Append data to a section.
922    ///
923    /// Must not be called for sections that contain uninitialized data.
924    /// `align` must be a power of two.
925    pub fn append_data(&mut self, append_data: &[u8], align: u64) -> u64 {
926        debug_assert!(!self.is_bss());
927        debug_assert_eq!(align & (align - 1), 0);
928        if self.align < align {
929            self.align = align;
930        }
931        let align = align as usize;
932        let data = self.data.to_mut();
933        let mut offset = data.len();
934        if offset & (align - 1) != 0 {
935            offset += align - (offset & (align - 1));
936            data.resize(offset, 0);
937        }
938        data.extend_from_slice(append_data);
939        self.size = data.len() as u64;
940        offset as u64
941    }
942
943    /// Append uninitialized data to a section.
944    ///
945    /// Must not be called for sections that contain initialized data.
946    /// `align` must be a power of two.
947    pub fn append_bss(&mut self, size: u64, align: u64) -> u64 {
948        debug_assert!(self.is_bss());
949        debug_assert_eq!(align & (align - 1), 0);
950        if self.align < align {
951            self.align = align;
952        }
953        let mut offset = self.size;
954        if offset & (align - 1) != 0 {
955            offset += align - (offset & (align - 1));
956            self.size = offset;
957        }
958        self.size += size;
959        offset
960    }
961
962    /// Returns the section as-built so far.
963    ///
964    /// This requires that the section is not a bss section.
965    pub fn data(&self) -> &[u8] {
966        debug_assert!(!self.is_bss());
967        &self.data
968    }
969
970    /// Returns the section as-built so far.
971    ///
972    /// This requires that the section is not a bss section.
973    pub fn data_mut(&mut self) -> &mut [u8] {
974        debug_assert!(!self.is_bss());
975        self.data.to_mut()
976    }
977}
978
979/// The section where a symbol is defined.
980#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
981#[non_exhaustive]
982pub enum SymbolSection {
983    /// The section is not applicable for this symbol (such as file symbols).
984    None,
985    /// The symbol is undefined.
986    Undefined,
987    /// The symbol has an absolute value.
988    Absolute,
989    /// The symbol is a zero-initialized symbol that will be combined with duplicate definitions.
990    Common,
991    /// The symbol is defined in the given section.
992    Section(SectionId),
993}
994
995impl SymbolSection {
996    /// Returns the section id for the section where the symbol is defined.
997    ///
998    /// May return `None` if the symbol is not defined in a section.
999    #[inline]
1000    pub fn id(self) -> Option<SectionId> {
1001        if let SymbolSection::Section(id) = self {
1002            Some(id)
1003        } else {
1004            None
1005        }
1006    }
1007}
1008
1009/// An identifier used to reference a symbol.
1010#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1011pub struct SymbolId(usize);
1012
1013/// A symbol in an object file.
1014#[derive(Debug)]
1015pub struct Symbol {
1016    /// The name of the symbol.
1017    pub name: Vec<u8>,
1018    /// The value of the symbol.
1019    ///
1020    /// If the symbol defined in a section, then this is the section offset of the symbol.
1021    pub value: u64,
1022    /// The size of the symbol.
1023    pub size: u64,
1024    /// The kind of the symbol.
1025    pub kind: SymbolKind,
1026    /// The scope of the symbol.
1027    pub scope: SymbolScope,
1028    /// Whether the symbol has weak binding.
1029    pub weak: bool,
1030    /// The section containing the symbol.
1031    pub section: SymbolSection,
1032    /// Symbol flags that are specific to each file format.
1033    pub flags: SymbolFlags<SectionId, SymbolId>,
1034}
1035
1036impl Symbol {
1037    /// Try to convert the name to a utf8 string.
1038    #[inline]
1039    pub fn name(&self) -> Option<&str> {
1040        str::from_utf8(&self.name).ok()
1041    }
1042
1043    /// Return true if the symbol is undefined.
1044    #[inline]
1045    pub fn is_undefined(&self) -> bool {
1046        self.section == SymbolSection::Undefined
1047    }
1048
1049    /// Return true if the symbol is common data.
1050    ///
1051    /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`.
1052    #[inline]
1053    pub fn is_common(&self) -> bool {
1054        self.section == SymbolSection::Common
1055    }
1056
1057    /// Return true if the symbol scope is local.
1058    #[inline]
1059    pub fn is_local(&self) -> bool {
1060        self.scope == SymbolScope::Compilation
1061    }
1062}
1063
1064/// A relocation in an object file.
1065#[derive(Debug)]
1066pub struct Relocation {
1067    /// The section offset of the place of the relocation.
1068    pub offset: u64,
1069    /// The symbol referred to by the relocation.
1070    ///
1071    /// This may be a section symbol.
1072    pub symbol: SymbolId,
1073    /// The addend to use in the relocation calculation.
1074    ///
1075    /// This may be in addition to an implicit addend stored at the place of the relocation.
1076    pub addend: i64,
1077    /// The fields that define the relocation type.
1078    pub flags: RelocationFlags,
1079}
1080
1081/// An identifier used to reference a COMDAT section group.
1082#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1083pub struct ComdatId(usize);
1084
1085/// A COMDAT section group.
1086#[derive(Debug)]
1087pub struct Comdat {
1088    /// The COMDAT selection kind.
1089    ///
1090    /// This determines the way in which the linker resolves multiple definitions of the COMDAT
1091    /// sections.
1092    pub kind: ComdatKind,
1093    /// The COMDAT symbol.
1094    ///
1095    /// If this symbol is referenced, then all sections in the group will be included by the
1096    /// linker.
1097    pub symbol: SymbolId,
1098    /// The sections in the group.
1099    pub sections: Vec<SectionId>,
1100}
1101
1102/// The symbol name mangling scheme.
1103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1104#[non_exhaustive]
1105pub enum Mangling {
1106    /// No symbol mangling.
1107    None,
1108    /// Windows COFF symbol mangling.
1109    Coff,
1110    /// Windows COFF i386 symbol mangling.
1111    CoffI386,
1112    /// ELF symbol mangling.
1113    Elf,
1114    /// Mach-O symbol mangling.
1115    MachO,
1116    /// Xcoff symbol mangling.
1117    Xcoff,
1118}
1119
1120impl Mangling {
1121    /// Return the default symboling mangling for the given format and architecture.
1122    pub fn default(format: BinaryFormat, architecture: Architecture) -> Self {
1123        match (format, architecture) {
1124            (BinaryFormat::Coff, Architecture::I386) => Mangling::CoffI386,
1125            (BinaryFormat::Coff, _) => Mangling::Coff,
1126            (BinaryFormat::Elf, _) => Mangling::Elf,
1127            (BinaryFormat::MachO, _) => Mangling::MachO,
1128            (BinaryFormat::Xcoff, _) => Mangling::Xcoff,
1129            _ => Mangling::None,
1130        }
1131    }
1132
1133    /// Return the prefix to use for global symbols.
1134    pub fn global_prefix(self) -> Option<u8> {
1135        match self {
1136            Mangling::None | Mangling::Elf | Mangling::Coff | Mangling::Xcoff => None,
1137            Mangling::CoffI386 | Mangling::MachO => Some(b'_'),
1138        }
1139    }
1140}