Skip to main content

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 if self.format == BinaryFormat::MachO {
576            // Use LLVM's convention for section symbols.
577            format!("ltmp{}", section_id.0).into_bytes()
578        } else {
579            Vec::new()
580        };
581        let symbol_id = SymbolId(self.symbols.len());
582        self.symbols.push(Symbol {
583            name,
584            value: 0,
585            size: 0,
586            kind: SymbolKind::Section,
587            scope: SymbolScope::Compilation,
588            weak: false,
589            section: SymbolSection::Section(section_id),
590            flags: SymbolFlags::None,
591        });
592        section.symbol = Some(symbol_id);
593        symbol_id
594    }
595
596    /// Append data to an existing section, and update a symbol to refer to it.
597    ///
598    /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the
599    /// symbol will indirectly point to the added data via the `__thread_vars` entry.
600    ///
601    /// For Mach-O, if [`Self::set_subsections_via_symbols`] is enabled, this will
602    /// automatically ensure the data size is at least 1.
603    ///
604    /// Returns the section offset of the data.
605    ///
606    /// Must not be called for sections that contain uninitialized data.
607    /// `align` must be a power of two.
608    pub fn add_symbol_data(
609        &mut self,
610        symbol_id: SymbolId,
611        section: SectionId,
612        #[cfg_attr(not(feature = "macho"), allow(unused_mut))] mut data: &[u8],
613        align: u64,
614    ) -> u64 {
615        #[cfg(feature = "macho")]
616        if data.is_empty() && self.macho_subsections_via_symbols {
617            data = &[0];
618        }
619        let offset = self.append_section_data(section, data, align);
620        self.set_symbol_data(symbol_id, section, offset, data.len() as u64);
621        offset
622    }
623
624    /// Append zero-initialized data to an existing section, and update a symbol to refer to it.
625    ///
626    /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the
627    /// symbol will indirectly point to the added data via the `__thread_vars` entry.
628    ///
629    /// For Mach-O, if [`Self::set_subsections_via_symbols`] is enabled, this will
630    /// automatically ensure the data size is at least 1.
631    ///
632    /// Returns the section offset of the data.
633    ///
634    /// Must not be called for sections that contain initialized data.
635    /// `align` must be a power of two.
636    pub fn add_symbol_bss(
637        &mut self,
638        symbol_id: SymbolId,
639        section: SectionId,
640        #[cfg_attr(not(feature = "macho"), allow(unused_mut))] mut size: u64,
641        align: u64,
642    ) -> u64 {
643        #[cfg(feature = "macho")]
644        if size == 0 && self.macho_subsections_via_symbols {
645            size = 1;
646        }
647        let offset = self.append_section_bss(section, size, align);
648        self.set_symbol_data(symbol_id, section, offset, size);
649        offset
650    }
651
652    /// Update a symbol to refer to the given data within a section.
653    ///
654    /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the
655    /// symbol will indirectly point to the data via the `__thread_vars` entry.
656    #[allow(unused_mut)]
657    pub fn set_symbol_data(
658        &mut self,
659        mut symbol_id: SymbolId,
660        section: SectionId,
661        offset: u64,
662        size: u64,
663    ) {
664        // Defined symbols must have a scope.
665        debug_assert!(self.symbol(symbol_id).scope != SymbolScope::Unknown);
666        match self.format {
667            #[cfg(feature = "macho")]
668            BinaryFormat::MachO => symbol_id = self.macho_add_thread_var(symbol_id),
669            _ => {}
670        }
671        let symbol = self.symbol_mut(symbol_id);
672        symbol.value = offset;
673        symbol.size = size;
674        symbol.section = SymbolSection::Section(section);
675    }
676
677    /// Convert a symbol to a section symbol and offset.
678    ///
679    /// Returns `None` if the symbol does not have a section.
680    pub fn symbol_section_and_offset(&mut self, symbol_id: SymbolId) -> Option<(SymbolId, u64)> {
681        let symbol = self.symbol(symbol_id);
682        if symbol.kind == SymbolKind::Section {
683            return Some((symbol_id, 0));
684        }
685        let symbol_offset = symbol.value;
686        let section = symbol.section.id()?;
687        let section_symbol = self.section_symbol(section);
688        Some((section_symbol, symbol_offset))
689    }
690
691    /// Add a relocation to a section.
692    ///
693    /// Relocations must only be added after the referenced symbols have been added
694    /// and defined (if applicable).
695    pub fn add_relocation(&mut self, section: SectionId, relocation: Relocation) -> Result<()> {
696        self.add_relocation_internal(section, relocation.into())
697    }
698
699    /// Add a relocation with a subtractor to a section.
700    ///
701    /// Relocations must only be added after the referenced symbols have been added
702    /// and defined (if applicable).
703    ///
704    /// This is like [`Self::add_relocation`], but the relocation operation
705    /// calculates the difference of two symbols. Currently, only some Mach-O
706    /// targets support this.
707    pub fn add_relocation_with_subtractor(
708        &mut self,
709        section: SectionId,
710        relocation: Relocation,
711        subtractor: Option<SymbolId>,
712    ) -> Result<()> {
713        if let Some(subtractor) = subtractor {
714            if self.format != BinaryFormat::MachO {
715                return Err(Error(format!(
716                    "unsupported relocation subtractor {:?} for {:?}",
717                    subtractor, relocation,
718                )));
719            }
720        }
721        self.add_relocation_internal(
722            section,
723            RelocationInternal {
724                subtractor,
725                ..relocation.into()
726            },
727        )
728    }
729
730    fn add_relocation_internal(
731        &mut self,
732        section: SectionId,
733        mut relocation: RelocationInternal,
734    ) -> Result<()> {
735        match self.format {
736            #[cfg(feature = "coff")]
737            BinaryFormat::Coff => self.coff_translate_relocation(&mut relocation)?,
738            #[cfg(feature = "elf")]
739            BinaryFormat::Elf => self.elf_translate_relocation(&mut relocation)?,
740            #[cfg(feature = "macho")]
741            BinaryFormat::MachO => self.macho_translate_relocation(section, &mut relocation)?,
742            #[cfg(feature = "xcoff")]
743            BinaryFormat::Xcoff => self.xcoff_translate_relocation(&mut relocation)?,
744            _ => unimplemented!(),
745        }
746        let implicit = match self.format {
747            #[cfg(feature = "coff")]
748            BinaryFormat::Coff => self.coff_adjust_addend(&mut relocation)?,
749            #[cfg(feature = "elf")]
750            BinaryFormat::Elf => self.elf_adjust_addend(&mut relocation)?,
751            #[cfg(feature = "macho")]
752            BinaryFormat::MachO => self.macho_adjust_addend(&mut relocation)?,
753            #[cfg(feature = "xcoff")]
754            BinaryFormat::Xcoff => self.xcoff_adjust_addend(&mut relocation)?,
755            _ => unimplemented!(),
756        };
757        if implicit && relocation.addend != 0 {
758            self.write_relocation_addend(section, &relocation)?;
759            relocation.addend = 0;
760        }
761        self.sections[section.0].relocations.push(relocation);
762        Ok(())
763    }
764
765    fn write_relocation_addend(
766        &mut self,
767        section: SectionId,
768        relocation: &RelocationInternal,
769    ) -> Result<()> {
770        let size = match self.format {
771            #[cfg(feature = "coff")]
772            BinaryFormat::Coff => self.coff_relocation_size(relocation)?,
773            #[cfg(feature = "elf")]
774            BinaryFormat::Elf => self.elf_relocation_size(relocation)?,
775            #[cfg(feature = "macho")]
776            BinaryFormat::MachO => self.macho_relocation_size(relocation)?,
777            #[cfg(feature = "xcoff")]
778            BinaryFormat::Xcoff => self.xcoff_relocation_size(relocation)?,
779            _ => unimplemented!(),
780        };
781        let data = self.sections[section.0].data_mut();
782        let offset = relocation.offset as usize;
783        match size {
784            32 => data.write_at(offset, &U32::new(self.endian, relocation.addend as u32)),
785            64 => data.write_at(offset, &U64::new(self.endian, relocation.addend as u64)),
786            _ => {
787                return Err(Error(format!(
788                    "unimplemented relocation addend {:?}",
789                    relocation
790                )));
791            }
792        }
793        .map_err(|_| {
794            Error(format!(
795                "invalid relocation offset {}+{} (max {})",
796                relocation.offset,
797                size,
798                data.len()
799            ))
800        })
801    }
802
803    /// Write the object to a `Vec`.
804    pub fn write(&self) -> Result<Vec<u8>> {
805        let mut buffer = Vec::new();
806        self.emit(&mut buffer)?;
807        Ok(buffer)
808    }
809
810    /// Write the object to a `Write` implementation.
811    ///
812    /// Also flushes the writer.
813    ///
814    /// It is advisable to use a buffered writer like [`BufWriter`](std::io::BufWriter)
815    /// instead of an unbuffered writer like [`File`](std::fs::File).
816    #[cfg(feature = "std")]
817    pub fn write_stream<W: io::Write>(&self, w: W) -> result::Result<(), Box<dyn error::Error>> {
818        let mut stream = StreamingBuffer::new(w);
819        self.emit(&mut stream)?;
820        stream.flush()?;
821        Ok(())
822    }
823
824    /// Write the object to a `WritableBuffer`.
825    pub fn emit(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
826        match self.format {
827            #[cfg(feature = "coff")]
828            BinaryFormat::Coff => self.coff_write(buffer),
829            #[cfg(feature = "elf")]
830            BinaryFormat::Elf => self.elf_write(buffer),
831            #[cfg(feature = "macho")]
832            BinaryFormat::MachO => self.macho_write(buffer),
833            #[cfg(feature = "xcoff")]
834            BinaryFormat::Xcoff => self.xcoff_write(buffer),
835            _ => unimplemented!(),
836        }
837    }
838}
839
840/// A standard segment kind.
841#[allow(missing_docs)]
842#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
843#[non_exhaustive]
844pub enum StandardSegment {
845    Text,
846    Data,
847    Debug,
848}
849
850/// A standard section kind.
851#[allow(missing_docs)]
852#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
853#[non_exhaustive]
854pub enum StandardSection {
855    Text,
856    Data,
857    ReadOnlyData,
858    ReadOnlyDataWithRel,
859    ReadOnlyString,
860    UninitializedData,
861    Tls,
862    /// Zero-fill TLS initializers. Unsupported for COFF.
863    UninitializedTls,
864    /// TLS variable structures. Only supported for Mach-O.
865    TlsVariables,
866    /// Common data. Only supported for Mach-O.
867    Common,
868    /// Notes for GNU properties. Only supported for ELF.
869    GnuProperty,
870    EhFrame,
871}
872
873impl StandardSection {
874    /// Return the section kind of a standard section.
875    pub fn kind(self) -> SectionKind {
876        match self {
877            StandardSection::Text => SectionKind::Text,
878            StandardSection::Data => SectionKind::Data,
879            StandardSection::ReadOnlyData => SectionKind::ReadOnlyData,
880            StandardSection::ReadOnlyDataWithRel => SectionKind::ReadOnlyDataWithRel,
881            StandardSection::ReadOnlyString => SectionKind::ReadOnlyString,
882            StandardSection::UninitializedData => SectionKind::UninitializedData,
883            StandardSection::Tls => SectionKind::Tls,
884            StandardSection::UninitializedTls => SectionKind::UninitializedTls,
885            StandardSection::TlsVariables => SectionKind::TlsVariables,
886            StandardSection::Common => SectionKind::Common,
887            StandardSection::GnuProperty => SectionKind::Note,
888            StandardSection::EhFrame => SectionKind::ReadOnlyData,
889        }
890    }
891
892    // TODO: remembering to update this is error-prone, can we do better?
893    fn all() -> &'static [StandardSection] {
894        &[
895            StandardSection::Text,
896            StandardSection::Data,
897            StandardSection::ReadOnlyData,
898            StandardSection::ReadOnlyDataWithRel,
899            StandardSection::ReadOnlyString,
900            StandardSection::UninitializedData,
901            StandardSection::Tls,
902            StandardSection::UninitializedTls,
903            StandardSection::TlsVariables,
904            StandardSection::Common,
905            StandardSection::GnuProperty,
906            StandardSection::EhFrame,
907        ]
908    }
909}
910
911/// An identifier used to reference a section.
912#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
913pub struct SectionId(usize);
914
915/// A section in an object file.
916#[derive(Debug)]
917pub struct Section<'a> {
918    segment: Vec<u8>,
919    name: Vec<u8>,
920    kind: SectionKind,
921    size: u64,
922    align: u64,
923    data: Cow<'a, [u8]>,
924    relocations: Vec<RelocationInternal>,
925    symbol: Option<SymbolId>,
926    /// Section flags that are specific to each file format.
927    pub flags: SectionFlags,
928}
929
930impl<'a> Section<'a> {
931    /// Try to convert the name to a utf8 string.
932    #[inline]
933    pub fn name(&self) -> Option<&str> {
934        str::from_utf8(&self.name).ok()
935    }
936
937    /// Try to convert the segment to a utf8 string.
938    #[inline]
939    pub fn segment(&self) -> Option<&str> {
940        str::from_utf8(&self.segment).ok()
941    }
942
943    /// Return true if this section contains zerofill data.
944    #[inline]
945    pub fn is_bss(&self) -> bool {
946        self.kind.is_bss()
947    }
948
949    /// Set the data for a section.
950    ///
951    /// Must not be called for sections that already have data, or that contain uninitialized data.
952    /// `align` must be a power of two.
953    pub fn set_data<T>(&mut self, data: T, align: u64)
954    where
955        T: Into<Cow<'a, [u8]>>,
956    {
957        debug_assert!(!self.is_bss());
958        debug_assert_eq!(align & (align - 1), 0);
959        debug_assert!(self.data.is_empty());
960        self.data = data.into();
961        self.size = self.data.len() as u64;
962        self.align = align;
963    }
964
965    /// Append data to a section.
966    ///
967    /// Must not be called for sections that contain uninitialized data.
968    /// `align` must be a power of two.
969    pub fn append_data(&mut self, append_data: &[u8], align: u64) -> u64 {
970        debug_assert!(!self.is_bss());
971        debug_assert_eq!(align & (align - 1), 0);
972        if self.align < align {
973            self.align = align;
974        }
975        let align = align as usize;
976        let data = self.data.to_mut();
977        let mut offset = data.len();
978        if offset & (align - 1) != 0 {
979            offset += align - (offset & (align - 1));
980            data.resize(offset, 0);
981        }
982        data.extend_from_slice(append_data);
983        self.size = data.len() as u64;
984        offset as u64
985    }
986
987    /// Append uninitialized data to a section.
988    ///
989    /// Must not be called for sections that contain initialized data.
990    /// `align` must be a power of two.
991    pub fn append_bss(&mut self, size: u64, align: u64) -> u64 {
992        debug_assert!(self.is_bss());
993        debug_assert_eq!(align & (align - 1), 0);
994        if self.align < align {
995            self.align = align;
996        }
997        let mut offset = self.size;
998        if offset & (align - 1) != 0 {
999            offset += align - (offset & (align - 1));
1000            self.size = offset;
1001        }
1002        self.size += size;
1003        offset
1004    }
1005
1006    /// Returns the section as-built so far.
1007    ///
1008    /// This requires that the section is not a bss section.
1009    pub fn data(&self) -> &[u8] {
1010        debug_assert!(!self.is_bss());
1011        &self.data
1012    }
1013
1014    /// Returns the section as-built so far.
1015    ///
1016    /// This requires that the section is not a bss section.
1017    pub fn data_mut(&mut self) -> &mut [u8] {
1018        debug_assert!(!self.is_bss());
1019        self.data.to_mut()
1020    }
1021}
1022
1023/// The section where a symbol is defined.
1024#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1025#[non_exhaustive]
1026pub enum SymbolSection {
1027    /// The section is not applicable for this symbol (such as file symbols).
1028    None,
1029    /// The symbol is undefined.
1030    Undefined,
1031    /// The symbol has an absolute value.
1032    Absolute,
1033    /// The symbol is a zero-initialized symbol that will be combined with duplicate definitions.
1034    Common,
1035    /// The symbol is defined in the given section.
1036    Section(SectionId),
1037}
1038
1039impl SymbolSection {
1040    /// Returns the section id for the section where the symbol is defined.
1041    ///
1042    /// May return `None` if the symbol is not defined in a section.
1043    #[inline]
1044    pub fn id(self) -> Option<SectionId> {
1045        if let SymbolSection::Section(id) = self {
1046            Some(id)
1047        } else {
1048            None
1049        }
1050    }
1051}
1052
1053/// An identifier used to reference a symbol.
1054#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1055pub struct SymbolId(usize);
1056
1057/// A symbol in an object file.
1058#[derive(Debug)]
1059pub struct Symbol {
1060    /// The name of the symbol.
1061    pub name: Vec<u8>,
1062    /// The value of the symbol.
1063    ///
1064    /// If the symbol defined in a section, then this is the section offset of the symbol.
1065    pub value: u64,
1066    /// The size of the symbol.
1067    pub size: u64,
1068    /// The kind of the symbol.
1069    pub kind: SymbolKind,
1070    /// The scope of the symbol.
1071    pub scope: SymbolScope,
1072    /// Whether the symbol has weak binding.
1073    pub weak: bool,
1074    /// The section containing the symbol.
1075    pub section: SymbolSection,
1076    /// Symbol flags that are specific to each file format.
1077    pub flags: SymbolFlags<SectionId, SymbolId>,
1078}
1079
1080impl Symbol {
1081    /// Try to convert the name to a utf8 string.
1082    #[inline]
1083    pub fn name(&self) -> Option<&str> {
1084        str::from_utf8(&self.name).ok()
1085    }
1086
1087    /// Return true if the symbol is undefined.
1088    #[inline]
1089    pub fn is_undefined(&self) -> bool {
1090        self.section == SymbolSection::Undefined
1091    }
1092
1093    /// Return true if the symbol is common data.
1094    ///
1095    /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`.
1096    #[inline]
1097    pub fn is_common(&self) -> bool {
1098        self.section == SymbolSection::Common
1099    }
1100
1101    /// Return true if the symbol scope is local.
1102    #[inline]
1103    pub fn is_local(&self) -> bool {
1104        self.scope == SymbolScope::Compilation
1105    }
1106}
1107
1108/// A relocation in an object file.
1109#[derive(Debug)]
1110pub struct Relocation {
1111    /// The section offset of the place of the relocation.
1112    pub offset: u64,
1113    /// The symbol referred to by the relocation.
1114    ///
1115    /// This may be a section symbol.
1116    pub symbol: SymbolId,
1117    /// The addend to use in the relocation calculation.
1118    ///
1119    /// This may be in addition to an implicit addend stored at the place of the relocation.
1120    pub addend: i64,
1121    /// The fields that define the relocation type.
1122    pub flags: RelocationFlags,
1123}
1124
1125#[derive(Debug)]
1126pub(crate) struct RelocationInternal {
1127    offset: u64,
1128    symbol: SymbolId,
1129    #[cfg_attr(not(feature = "macho"), allow(unused))]
1130    subtractor: Option<SymbolId>,
1131    addend: i64,
1132    flags: RelocationFlags,
1133}
1134
1135impl From<Relocation> for RelocationInternal {
1136    fn from(value: Relocation) -> Self {
1137        RelocationInternal {
1138            offset: value.offset,
1139            symbol: value.symbol,
1140            subtractor: None,
1141            addend: value.addend,
1142            flags: value.flags,
1143        }
1144    }
1145}
1146
1147/// An identifier used to reference a COMDAT section group.
1148#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1149pub struct ComdatId(usize);
1150
1151/// A COMDAT section group.
1152#[derive(Debug)]
1153pub struct Comdat {
1154    /// The COMDAT selection kind.
1155    ///
1156    /// This determines the way in which the linker resolves multiple definitions of the COMDAT
1157    /// sections.
1158    pub kind: ComdatKind,
1159    /// The COMDAT symbol.
1160    ///
1161    /// If this symbol is referenced, then all sections in the group will be included by the
1162    /// linker.
1163    pub symbol: SymbolId,
1164    /// The sections in the group.
1165    pub sections: Vec<SectionId>,
1166}
1167
1168/// The symbol name mangling scheme.
1169#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1170#[non_exhaustive]
1171pub enum Mangling {
1172    /// No symbol mangling.
1173    None,
1174    /// Windows COFF symbol mangling.
1175    Coff,
1176    /// Windows COFF i386 symbol mangling.
1177    CoffI386,
1178    /// ELF symbol mangling.
1179    Elf,
1180    /// Mach-O symbol mangling.
1181    MachO,
1182    /// Xcoff symbol mangling.
1183    Xcoff,
1184}
1185
1186impl Mangling {
1187    /// Return the default symboling mangling for the given format and architecture.
1188    pub fn default(format: BinaryFormat, architecture: Architecture) -> Self {
1189        match (format, architecture) {
1190            (BinaryFormat::Coff, Architecture::I386) => Mangling::CoffI386,
1191            (BinaryFormat::Coff, _) => Mangling::Coff,
1192            (BinaryFormat::Elf, _) => Mangling::Elf,
1193            (BinaryFormat::MachO, _) => Mangling::MachO,
1194            (BinaryFormat::Xcoff, _) => Mangling::Xcoff,
1195            _ => Mangling::None,
1196        }
1197    }
1198
1199    /// Return the prefix to use for global symbols.
1200    pub fn global_prefix(self) -> Option<u8> {
1201        match self {
1202            Mangling::None | Mangling::Elf | Mangling::Coff | Mangling::Xcoff => None,
1203            Mangling::CoffI386 | Mangling::MachO => Some(b'_'),
1204        }
1205    }
1206}