//! Interface for writing object files. use alloc::borrow::Cow; use alloc::string::String; use alloc::vec::Vec; use core::{fmt, result, str}; #[cfg(not(feature = "std"))] use hashbrown::HashMap; #[cfg(feature = "std")] use std::{boxed::Box, collections::HashMap, error, io}; use crate::endian::{Endianness, U32, U64}; use crate::{ Architecture, BinaryFormat, ComdatKind, FileFlags, RelocationEncoding, RelocationKind, SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope, }; #[cfg(feature = "coff")] mod coff; #[cfg(feature = "coff")] pub use coff::CoffExportStyle; #[cfg(feature = "elf")] pub mod elf; #[cfg(feature = "macho")] mod macho; #[cfg(feature = "macho")] pub use macho::MachOBuildVersion; #[cfg(feature = "pe")] pub mod pe; #[cfg(feature = "xcoff")] mod xcoff; mod string; pub use string::StringId; mod util; pub use util::*; /// The error type used within the write module. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Error(String); impl fmt::Display for Error { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.0) } } #[cfg(feature = "std")] impl error::Error for Error {} /// The result type used within the write module. pub type Result = result::Result; /// A writable relocatable object file. #[derive(Debug)] pub struct Object<'a> { format: BinaryFormat, architecture: Architecture, endian: Endianness, sections: Vec>, standard_sections: HashMap, symbols: Vec, symbol_map: HashMap, SymbolId>, stub_symbols: HashMap, comdats: Vec, /// File flags that are specific to each file format. pub flags: FileFlags, /// The symbol name mangling scheme. pub mangling: Mangling, /// Mach-O "_tlv_bootstrap" symbol. tlv_bootstrap: Option, #[cfg(feature = "macho")] macho_build_version: Option, } impl<'a> Object<'a> { /// Create an empty object file. pub fn new(format: BinaryFormat, architecture: Architecture, endian: Endianness) -> Object<'a> { Object { format, architecture, endian, sections: Vec::new(), standard_sections: HashMap::new(), symbols: Vec::new(), symbol_map: HashMap::new(), stub_symbols: HashMap::new(), comdats: Vec::new(), flags: FileFlags::None, mangling: Mangling::default(format, architecture), tlv_bootstrap: None, #[cfg(feature = "macho")] macho_build_version: None, } } /// Return the file format. #[inline] pub fn format(&self) -> BinaryFormat { self.format } /// Return the architecture. #[inline] pub fn architecture(&self) -> Architecture { self.architecture } /// Return the current mangling setting. #[inline] pub fn mangling(&self) -> Mangling { self.mangling } /// Specify the mangling setting. #[inline] pub fn set_mangling(&mut self, mangling: Mangling) { self.mangling = mangling; } /// Return the name for a standard segment. /// /// This will vary based on the file format. #[allow(unused_variables)] pub fn segment_name(&self, segment: StandardSegment) -> &'static [u8] { match self.format { #[cfg(feature = "coff")] BinaryFormat::Coff => &[], #[cfg(feature = "elf")] BinaryFormat::Elf => &[], #[cfg(feature = "macho")] BinaryFormat::MachO => self.macho_segment_name(segment), _ => unimplemented!(), } } /// Get the section with the given `SectionId`. #[inline] pub fn section(&self, section: SectionId) -> &Section<'a> { &self.sections[section.0] } /// Mutably get the section with the given `SectionId`. #[inline] pub fn section_mut(&mut self, section: SectionId) -> &mut Section<'a> { &mut self.sections[section.0] } /// Set the data for an existing section. /// /// Must not be called for sections that already have data, or that contain uninitialized data. pub fn set_section_data(&mut self, section: SectionId, data: T, align: u64) where T: Into>, { self.sections[section.0].set_data(data, align) } /// Append data to an existing section. Returns the section offset of the data. pub fn append_section_data(&mut self, section: SectionId, data: &[u8], align: u64) -> u64 { self.sections[section.0].append_data(data, align) } /// Append zero-initialized data to an existing section. Returns the section offset of the data. pub fn append_section_bss(&mut self, section: SectionId, size: u64, align: u64) -> u64 { self.sections[section.0].append_bss(size, align) } /// Return the `SectionId` of a standard section. /// /// If the section doesn't already exist then it is created. pub fn section_id(&mut self, section: StandardSection) -> SectionId { self.standard_sections .get(§ion) .cloned() .unwrap_or_else(|| { let (segment, name, kind, flags) = self.section_info(section); let id = self.add_section(segment.to_vec(), name.to_vec(), kind); self.section_mut(id).flags = flags; id }) } /// Add a new section and return its `SectionId`. /// /// This also creates a section symbol. pub fn add_section(&mut self, segment: Vec, name: Vec, kind: SectionKind) -> SectionId { let id = SectionId(self.sections.len()); self.sections.push(Section { segment, name, kind, size: 0, align: 1, data: Cow::Borrowed(&[]), relocations: Vec::new(), symbol: None, flags: SectionFlags::None, }); // Add to self.standard_sections if required. This may match multiple standard sections. let section = &self.sections[id.0]; for standard_section in StandardSection::all() { if !self.standard_sections.contains_key(standard_section) { let (segment, name, kind, _flags) = self.section_info(*standard_section); if segment == &*section.segment && name == &*section.name && kind == section.kind { self.standard_sections.insert(*standard_section, id); } } } id } fn section_info( &self, section: StandardSection, ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { match self.format { #[cfg(feature = "coff")] BinaryFormat::Coff => self.coff_section_info(section), #[cfg(feature = "elf")] BinaryFormat::Elf => self.elf_section_info(section), #[cfg(feature = "macho")] BinaryFormat::MachO => self.macho_section_info(section), #[cfg(feature = "xcoff")] BinaryFormat::Xcoff => self.xcoff_section_info(section), _ => unimplemented!(), } } /// Add a subsection. Returns the `SectionId` and section offset of the data. pub fn add_subsection( &mut self, section: StandardSection, name: &[u8], data: &[u8], align: u64, ) -> (SectionId, u64) { let section_id = if self.has_subsections_via_symbols() { self.set_subsections_via_symbols(); self.section_id(section) } else { let (segment, name, kind, flags) = self.subsection_info(section, name); let id = self.add_section(segment.to_vec(), name, kind); self.section_mut(id).flags = flags; id }; let offset = self.append_section_data(section_id, data, align); (section_id, offset) } fn has_subsections_via_symbols(&self) -> bool { match self.format { BinaryFormat::Coff | BinaryFormat::Elf | BinaryFormat::Xcoff => false, BinaryFormat::MachO => true, _ => unimplemented!(), } } fn set_subsections_via_symbols(&mut self) { match self.format { #[cfg(feature = "macho")] BinaryFormat::MachO => self.macho_set_subsections_via_symbols(), _ => unimplemented!(), } } fn subsection_info( &self, section: StandardSection, value: &[u8], ) -> (&'static [u8], Vec, SectionKind, SectionFlags) { let (segment, section, kind, flags) = self.section_info(section); let name = self.subsection_name(section, value); (segment, name, kind, flags) } #[allow(unused_variables)] fn subsection_name(&self, section: &[u8], value: &[u8]) -> Vec { debug_assert!(!self.has_subsections_via_symbols()); match self.format { #[cfg(feature = "coff")] BinaryFormat::Coff => self.coff_subsection_name(section, value), #[cfg(feature = "elf")] BinaryFormat::Elf => self.elf_subsection_name(section, value), _ => unimplemented!(), } } /// Get the COMDAT section group with the given `ComdatId`. #[inline] pub fn comdat(&self, comdat: ComdatId) -> &Comdat { &self.comdats[comdat.0] } /// Mutably get the COMDAT section group with the given `ComdatId`. #[inline] pub fn comdat_mut(&mut self, comdat: ComdatId) -> &mut Comdat { &mut self.comdats[comdat.0] } /// Add a new COMDAT section group and return its `ComdatId`. pub fn add_comdat(&mut self, comdat: Comdat) -> ComdatId { let comdat_id = ComdatId(self.comdats.len()); self.comdats.push(comdat); comdat_id } /// Get the `SymbolId` of the symbol with the given name. pub fn symbol_id(&self, name: &[u8]) -> Option { self.symbol_map.get(name).cloned() } /// Get the symbol with the given `SymbolId`. #[inline] pub fn symbol(&self, symbol: SymbolId) -> &Symbol { &self.symbols[symbol.0] } /// Mutably get the symbol with the given `SymbolId`. #[inline] pub fn symbol_mut(&mut self, symbol: SymbolId) -> &mut Symbol { &mut self.symbols[symbol.0] } /// Add a new symbol and return its `SymbolId`. pub fn add_symbol(&mut self, mut symbol: Symbol) -> SymbolId { // Defined symbols must have a scope. debug_assert!(symbol.is_undefined() || symbol.scope != SymbolScope::Unknown); if symbol.kind == SymbolKind::Section { // There can only be one section symbol, but update its flags, since // the automatically generated section symbol will have none. let symbol_id = self.section_symbol(symbol.section.id().unwrap()); if symbol.flags != SymbolFlags::None { self.symbol_mut(symbol_id).flags = symbol.flags; } return symbol_id; } if !symbol.name.is_empty() && (symbol.kind == SymbolKind::Text || symbol.kind == SymbolKind::Data || symbol.kind == SymbolKind::Tls) { let unmangled_name = symbol.name.clone(); if let Some(prefix) = self.mangling.global_prefix() { symbol.name.insert(0, prefix); } let symbol_id = self.add_raw_symbol(symbol); self.symbol_map.insert(unmangled_name, symbol_id); symbol_id } else { self.add_raw_symbol(symbol) } } fn add_raw_symbol(&mut self, symbol: Symbol) -> SymbolId { let symbol_id = SymbolId(self.symbols.len()); self.symbols.push(symbol); symbol_id } /// Return true if the file format supports `StandardSection::UninitializedTls`. #[inline] pub fn has_uninitialized_tls(&self) -> bool { self.format != BinaryFormat::Coff } /// Return true if the file format supports `StandardSection::Common`. #[inline] pub fn has_common(&self) -> bool { self.format == BinaryFormat::MachO } /// Add a new common symbol and return its `SymbolId`. /// /// For Mach-O, this appends the symbol to the `__common` section. pub fn add_common_symbol(&mut self, mut symbol: Symbol, size: u64, align: u64) -> SymbolId { if self.has_common() { let symbol_id = self.add_symbol(symbol); let section = self.section_id(StandardSection::Common); self.add_symbol_bss(symbol_id, section, size, align); symbol_id } else { symbol.section = SymbolSection::Common; symbol.size = size; self.add_symbol(symbol) } } /// Add a new file symbol and return its `SymbolId`. pub fn add_file_symbol(&mut self, name: Vec) -> SymbolId { self.add_raw_symbol(Symbol { name, value: 0, size: 0, kind: SymbolKind::File, scope: SymbolScope::Compilation, weak: false, section: SymbolSection::None, flags: SymbolFlags::None, }) } /// Get the symbol for a section. pub fn section_symbol(&mut self, section_id: SectionId) -> SymbolId { let section = &mut self.sections[section_id.0]; if let Some(symbol) = section.symbol { return symbol; } let name = if self.format == BinaryFormat::Coff { section.name.clone() } else { Vec::new() }; let symbol_id = SymbolId(self.symbols.len()); self.symbols.push(Symbol { name, value: 0, size: 0, kind: SymbolKind::Section, scope: SymbolScope::Compilation, weak: false, section: SymbolSection::Section(section_id), flags: SymbolFlags::None, }); section.symbol = Some(symbol_id); symbol_id } /// Append data to an existing section, and update a symbol to refer to it. /// /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the /// symbol will indirectly point to the added data via the `__thread_vars` entry. /// /// Returns the section offset of the data. pub fn add_symbol_data( &mut self, symbol_id: SymbolId, section: SectionId, data: &[u8], align: u64, ) -> u64 { let offset = self.append_section_data(section, data, align); self.set_symbol_data(symbol_id, section, offset, data.len() as u64); offset } /// Append zero-initialized data to an existing section, and update a symbol to refer to it. /// /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the /// symbol will indirectly point to the added data via the `__thread_vars` entry. /// /// Returns the section offset of the data. pub fn add_symbol_bss( &mut self, symbol_id: SymbolId, section: SectionId, size: u64, align: u64, ) -> u64 { let offset = self.append_section_bss(section, size, align); self.set_symbol_data(symbol_id, section, offset, size); offset } /// Update a symbol to refer to the given data within a section. /// /// For Mach-O, this also creates a `__thread_vars` entry for TLS symbols, and the /// symbol will indirectly point to the data via the `__thread_vars` entry. #[allow(unused_mut)] pub fn set_symbol_data( &mut self, mut symbol_id: SymbolId, section: SectionId, offset: u64, size: u64, ) { // Defined symbols must have a scope. debug_assert!(self.symbol(symbol_id).scope != SymbolScope::Unknown); match self.format { #[cfg(feature = "macho")] BinaryFormat::MachO => symbol_id = self.macho_add_thread_var(symbol_id), _ => {} } let symbol = self.symbol_mut(symbol_id); symbol.value = offset; symbol.size = size; symbol.section = SymbolSection::Section(section); } /// Convert a symbol to a section symbol and offset. /// /// Returns `None` if the symbol does not have a section. pub fn symbol_section_and_offset(&mut self, symbol_id: SymbolId) -> Option<(SymbolId, u64)> { let symbol = self.symbol(symbol_id); if symbol.kind == SymbolKind::Section { return Some((symbol_id, 0)); } let symbol_offset = symbol.value; let section = symbol.section.id()?; let section_symbol = self.section_symbol(section); Some((section_symbol, symbol_offset)) } /// Add a relocation to a section. /// /// Relocations must only be added after the referenced symbols have been added /// and defined (if applicable). pub fn add_relocation(&mut self, section: SectionId, mut relocation: Relocation) -> Result<()> { let addend = match self.format { #[cfg(feature = "coff")] BinaryFormat::Coff => self.coff_fixup_relocation(&mut relocation), #[cfg(feature = "elf")] BinaryFormat::Elf => self.elf_fixup_relocation(&mut relocation)?, #[cfg(feature = "macho")] BinaryFormat::MachO => self.macho_fixup_relocation(&mut relocation), #[cfg(feature = "xcoff")] BinaryFormat::Xcoff => self.xcoff_fixup_relocation(&mut relocation), _ => unimplemented!(), }; if addend != 0 { self.write_relocation_addend(section, &relocation, addend)?; } self.sections[section.0].relocations.push(relocation); Ok(()) } fn write_relocation_addend( &mut self, section: SectionId, relocation: &Relocation, addend: i64, ) -> Result<()> { let data = self.sections[section.0].data_mut(); let offset = relocation.offset as usize; match relocation.size { 32 => data.write_at(offset, &U32::new(self.endian, addend as u32)), 64 => data.write_at(offset, &U64::new(self.endian, addend as u64)), _ => { return Err(Error(format!( "unimplemented relocation addend {:?}", relocation ))); } } .map_err(|_| { Error(format!( "invalid relocation offset {}+{} (max {})", relocation.offset, relocation.size, data.len() )) }) } /// Write the object to a `Vec`. pub fn write(&self) -> Result> { let mut buffer = Vec::new(); self.emit(&mut buffer)?; Ok(buffer) } /// Write the object to a `Write` implementation. /// /// Also flushes the writer. /// /// It is advisable to use a buffered writer like [`BufWriter`](std::io::BufWriter) /// instead of an unbuffered writer like [`File`](std::fs::File). #[cfg(feature = "std")] pub fn write_stream(&self, w: W) -> result::Result<(), Box> { let mut stream = StreamingBuffer::new(w); self.emit(&mut stream)?; stream.result()?; stream.into_inner().flush()?; Ok(()) } /// Write the object to a `WritableBuffer`. pub fn emit(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { match self.format { #[cfg(feature = "coff")] BinaryFormat::Coff => self.coff_write(buffer), #[cfg(feature = "elf")] BinaryFormat::Elf => self.elf_write(buffer), #[cfg(feature = "macho")] BinaryFormat::MachO => self.macho_write(buffer), #[cfg(feature = "xcoff")] BinaryFormat::Xcoff => self.xcoff_write(buffer), _ => unimplemented!(), } } } /// A standard segment kind. #[allow(missing_docs)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[non_exhaustive] pub enum StandardSegment { Text, Data, Debug, } /// A standard section kind. #[allow(missing_docs)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[non_exhaustive] pub enum StandardSection { Text, Data, ReadOnlyData, ReadOnlyDataWithRel, ReadOnlyString, UninitializedData, Tls, /// Zero-fill TLS initializers. Unsupported for COFF. UninitializedTls, /// TLS variable structures. Only supported for Mach-O. TlsVariables, /// Common data. Only supported for Mach-O. Common, /// Notes for GNU properties. Only supported for ELF. GnuProperty, } impl StandardSection { /// Return the section kind of a standard section. pub fn kind(self) -> SectionKind { match self { StandardSection::Text => SectionKind::Text, StandardSection::Data => SectionKind::Data, StandardSection::ReadOnlyData => SectionKind::ReadOnlyData, StandardSection::ReadOnlyDataWithRel => SectionKind::ReadOnlyDataWithRel, StandardSection::ReadOnlyString => SectionKind::ReadOnlyString, StandardSection::UninitializedData => SectionKind::UninitializedData, StandardSection::Tls => SectionKind::Tls, StandardSection::UninitializedTls => SectionKind::UninitializedTls, StandardSection::TlsVariables => SectionKind::TlsVariables, StandardSection::Common => SectionKind::Common, StandardSection::GnuProperty => SectionKind::Note, } } // TODO: remembering to update this is error-prone, can we do better? fn all() -> &'static [StandardSection] { &[ StandardSection::Text, StandardSection::Data, StandardSection::ReadOnlyData, StandardSection::ReadOnlyDataWithRel, StandardSection::ReadOnlyString, StandardSection::UninitializedData, StandardSection::Tls, StandardSection::UninitializedTls, StandardSection::TlsVariables, StandardSection::Common, StandardSection::GnuProperty, ] } } /// An identifier used to reference a section. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SectionId(usize); /// A section in an object file. #[derive(Debug)] pub struct Section<'a> { segment: Vec, name: Vec, kind: SectionKind, size: u64, align: u64, data: Cow<'a, [u8]>, relocations: Vec, symbol: Option, /// Section flags that are specific to each file format. pub flags: SectionFlags, } impl<'a> Section<'a> { /// Try to convert the name to a utf8 string. #[inline] pub fn name(&self) -> Option<&str> { str::from_utf8(&self.name).ok() } /// Try to convert the segment to a utf8 string. #[inline] pub fn segment(&self) -> Option<&str> { str::from_utf8(&self.segment).ok() } /// Return true if this section contains zerofill data. #[inline] pub fn is_bss(&self) -> bool { self.kind.is_bss() } /// Set the data for a section. /// /// Must not be called for sections that already have data, or that contain uninitialized data. pub fn set_data(&mut self, data: T, align: u64) where T: Into>, { debug_assert!(!self.is_bss()); debug_assert_eq!(align & (align - 1), 0); debug_assert!(self.data.is_empty()); self.data = data.into(); self.size = self.data.len() as u64; self.align = align; } /// Append data to a section. /// /// Must not be called for sections that contain uninitialized data. pub fn append_data(&mut self, append_data: &[u8], align: u64) -> u64 { debug_assert!(!self.is_bss()); debug_assert_eq!(align & (align - 1), 0); if self.align < align { self.align = align; } let align = align as usize; let data = self.data.to_mut(); let mut offset = data.len(); if offset & (align - 1) != 0 { offset += align - (offset & (align - 1)); data.resize(offset, 0); } data.extend_from_slice(append_data); self.size = data.len() as u64; offset as u64 } /// Append uninitialized data to a section. /// /// Must not be called for sections that contain initialized data. pub fn append_bss(&mut self, size: u64, align: u64) -> u64 { debug_assert!(self.is_bss()); debug_assert_eq!(align & (align - 1), 0); if self.align < align { self.align = align; } let mut offset = self.size; if offset & (align - 1) != 0 { offset += align - (offset & (align - 1)); self.size = offset; } self.size += size; offset } /// Returns the section as-built so far. /// /// This requires that the section is not a bss section. pub fn data(&self) -> &[u8] { debug_assert!(!self.is_bss()); &self.data } /// Returns the section as-built so far. /// /// This requires that the section is not a bss section. pub fn data_mut(&mut self) -> &mut [u8] { debug_assert!(!self.is_bss()); self.data.to_mut() } } /// The section where a symbol is defined. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum SymbolSection { /// The section is not applicable for this symbol (such as file symbols). None, /// The symbol is undefined. Undefined, /// The symbol has an absolute value. Absolute, /// The symbol is a zero-initialized symbol that will be combined with duplicate definitions. Common, /// The symbol is defined in the given section. Section(SectionId), } impl SymbolSection { /// Returns the section id for the section where the symbol is defined. /// /// May return `None` if the symbol is not defined in a section. #[inline] pub fn id(self) -> Option { if let SymbolSection::Section(id) = self { Some(id) } else { None } } } /// An identifier used to reference a symbol. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SymbolId(usize); /// A symbol in an object file. #[derive(Debug)] pub struct Symbol { /// The name of the symbol. pub name: Vec, /// The value of the symbol. /// /// If the symbol defined in a section, then this is the section offset of the symbol. pub value: u64, /// The size of the symbol. pub size: u64, /// The kind of the symbol. pub kind: SymbolKind, /// The scope of the symbol. pub scope: SymbolScope, /// Whether the symbol has weak binding. pub weak: bool, /// The section containing the symbol. pub section: SymbolSection, /// Symbol flags that are specific to each file format. pub flags: SymbolFlags, } impl Symbol { /// Try to convert the name to a utf8 string. #[inline] pub fn name(&self) -> Option<&str> { str::from_utf8(&self.name).ok() } /// Return true if the symbol is undefined. #[inline] pub fn is_undefined(&self) -> bool { self.section == SymbolSection::Undefined } /// Return true if the symbol is common data. /// /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`. #[inline] pub fn is_common(&self) -> bool { self.section == SymbolSection::Common } /// Return true if the symbol scope is local. #[inline] pub fn is_local(&self) -> bool { self.scope == SymbolScope::Compilation } } /// A relocation in an object file. #[derive(Debug)] pub struct Relocation { /// The section offset of the place of the relocation. pub offset: u64, /// The size in bits of the place of relocation. pub size: u8, /// The operation used to calculate the result of the relocation. pub kind: RelocationKind, /// Information about how the result of the relocation operation is encoded in the place. pub encoding: RelocationEncoding, /// The symbol referred to by the relocation. /// /// This may be a section symbol. pub symbol: SymbolId, /// The addend to use in the relocation calculation. /// /// This may be in addition to an implicit addend stored at the place of the relocation. pub addend: i64, } /// An identifier used to reference a COMDAT section group. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ComdatId(usize); /// A COMDAT section group. #[derive(Debug)] pub struct Comdat { /// The COMDAT selection kind. /// /// This determines the way in which the linker resolves multiple definitions of the COMDAT /// sections. pub kind: ComdatKind, /// The COMDAT symbol. /// /// If this symbol is referenced, then all sections in the group will be included by the /// linker. pub symbol: SymbolId, /// The sections in the group. pub sections: Vec, } /// The symbol name mangling scheme. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] pub enum Mangling { /// No symbol mangling. None, /// Windows COFF symbol mangling. Coff, /// Windows COFF i386 symbol mangling. CoffI386, /// ELF symbol mangling. Elf, /// Mach-O symbol mangling. MachO, /// Xcoff symbol mangling. Xcoff, } impl Mangling { /// Return the default symboling mangling for the given format and architecture. pub fn default(format: BinaryFormat, architecture: Architecture) -> Self { match (format, architecture) { (BinaryFormat::Coff, Architecture::I386) => Mangling::CoffI386, (BinaryFormat::Coff, _) => Mangling::Coff, (BinaryFormat::Elf, _) => Mangling::Elf, (BinaryFormat::MachO, _) => Mangling::MachO, (BinaryFormat::Xcoff, _) => Mangling::Xcoff, _ => Mangling::None, } } /// Return the prefix to use for global symbols. pub fn global_prefix(self) -> Option { match self { Mangling::None | Mangling::Elf | Mangling::Coff | Mangling::Xcoff => None, Mangling::CoffI386 | Mangling::MachO => Some(b'_'), } } }