//! Interface for writing object files. //! //! This module provides a unified write API for relocatable object files //! using [`Object`]. This does not support writing executable files. //! This supports the following file formats: COFF, ELF, Mach-O, and XCOFF. //! //! The submodules define helpers for writing the raw structs. These support //! writing both relocatable and executable files. There are writers for //! the following file formats: [COFF](coff::Writer), [ELF](elf::Writer), //! and [PE](pe::Writer).
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};
/// Return the name for a standard segment. /// /// This will vary based on the file format. #[allow(unused_variables)] pubfn segment_name(&self, segment: StandardSegment) -> &e='color:blue'>'static [u8] { matchself.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] pubfn section(&self, section: SectionId) -> &Section<'a> {
&self.sections[section.0]
}
/// Mutably get the section with the given `SectionId`. #[inline] pubfn section_mut(&mutself, section: SectionId) -> &mut Section<'a> {
&mutself.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. /// `align` must be a power of two. pubfn set_section_data<T>(&mutself, section: SectionId, data: T, align: u64) where
T: Into<Cow<'a, [u8]>>,
{ self.sections[section.0].set_data(data, align)
}
/// Append data to an existing section. Returns the section offset of the data. /// /// Must not be called for sections that contain uninitialized data. /// `align` must be a power of two. pubfn append_section_data(&mutself, 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. /// /// Must not be called for sections that contain initialized data. /// `align` must be a power of two. pubfn append_section_bss(&mutself, 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. pubfn section_id(&mutself, 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. pubfn add_section(&mutself, segment: Vec<u8>, name: Vec<u8>, 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);
}
}
}
/// Add a subsection. Returns the `SectionId` and section offset of the data. /// /// For Mach-O, this does not create a subsection, and instead uses the /// section from [`Self::section_id`]. Use [`Self::set_subsections_via_symbols`] /// to enable subsections via symbols. pubfn add_subsection(&mutself, section: StandardSection, name: &[u8]) -> SectionId { ifself.has_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
}
}
/// Enable subsections via symbols if supported. /// /// This should be called before adding any subsections or symbols. /// /// For Mach-O, this sets the `MH_SUBSECTIONS_VIA_SYMBOLS` flag. /// For other formats, this does nothing. pubfn set_subsections_via_symbols(&mutself) { #[cfg(feature = "macho")] ifself.format == BinaryFormat::MachO { self.macho_subsections_via_symbols = true;
}
}
/// Get the COMDAT section group with the given `ComdatId`. #[inline] pubfn comdat(&self, comdat: ComdatId) -> &Comdat {
&self.comdats[comdat.0]
}
/// Mutably get the COMDAT section group with the given `ComdatId`. #[inline] pubfn comdat_mut(&mutself, comdat: ComdatId) -> &mut Comdat {
&mutself.comdats[comdat.0]
}
/// Add a new COMDAT section group and return its `ComdatId`. pubfn add_comdat(&mutself, 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. pubfn symbol_id(&self, name: &[u8]) -> Option<SymbolId> { self.symbol_map.get(name).cloned()
}
/// Get the symbol with the given `SymbolId`. #[inline] pubfn symbol(&self, symbol: SymbolId) -> &Symbol {
&self.symbols[symbol.0]
}
/// Mutably get the symbol with the given `SymbolId`. #[inline] pubfn symbol_mut(&mutself, symbol: SymbolId) -> &mut Symbol {
&mutself.symbols[symbol.0]
}
/// Add a new symbol and return its `SymbolId`. pubfn add_symbol(&mutself, 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(); iflet 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)
}
}
/// Return true if the file format supports `StandardSection::UninitializedTls`. #[inline] pubfn has_uninitialized_tls(&self) -> bool { self.format != BinaryFormat::Coff
}
/// Return true if the file format supports `StandardSection::Common`. #[inline] pubfn 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. /// /// `align` must be a power of two. pubfn add_common_symbol(&mutself, mut symbol: Symbol, size: u64, align: u64) -> SymbolId { ifself.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`. pubfn add_file_symbol(&mutself, name: Vec<u8>) -> 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. pubfn section_symbol(&mutself, section_id: SectionId) -> SymbolId { let section = &mutself.sections[section_id.0]; iflet Some(symbol) = section.symbol { return symbol;
} let name = ifself.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. /// /// For Mach-O, if [`Self::set_subsections_via_symbols`] is enabled, this will /// automatically ensure the data size is at least 1. /// /// Returns the section offset of the data. /// /// Must not be called for sections that contain uninitialized data. /// `align` must be a power of two. pubfn add_symbol_data(
&mutself,
symbol_id: SymbolId,
section: SectionId, #[cfg_attr(not(feature = "macho"), allow(unused_mut))] mut data: &[u8],
align: u64,
) -> u64 { #[cfg(feature = "macho")] if data.is_empty() && self.macho_subsections_via_symbols {
data = &[0];
} 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. /// /// For Mach-O, if [`Self::set_subsections_via_symbols`] is enabled, this will /// automatically ensure the data size is at least 1. /// /// Returns the section offset of the data. /// /// Must not be called for sections that contain initialized data. /// `align` must be a power of two. pubfn add_symbol_bss(
&mutself,
symbol_id: SymbolId,
section: SectionId, #[cfg_attr(not(feature = "macho"), allow(unused_mut))] mut size: u64,
align: u64,
) -> u64 { #[cfg(feature = "macho")] if size == 0 && self.macho_subsections_via_symbols {
size = 1;
} 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)] pubfn set_symbol_data(
&mutself, 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); matchself.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. pubfn symbol_section_and_offset(&mutself, 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). pubfn add_relocation(&mutself, section: SectionId, mut relocation: Relocation) -> Result<()> { matchself.format { #[cfg(feature = "coff")]
BinaryFormat::Coff => self.coff_translate_relocation(&mut relocation)?, #[cfg(feature = "elf")]
BinaryFormat::Elf => self.elf_translate_relocation(&mut relocation)?, #[cfg(feature = "macho")]
BinaryFormat::MachO => self.macho_translate_relocation(&mut relocation)?, #[cfg(feature = "xcoff")]
BinaryFormat::Xcoff => self.xcoff_translate_relocation(&mut relocation)?,
_ => unimplemented!(),
} let implicit = matchself.format { #[cfg(feature = "coff")]
BinaryFormat::Coff => self.coff_adjust_addend(&mut relocation)?, #[cfg(feature = "elf")]
BinaryFormat::Elf => self.elf_adjust_addend(&mut relocation)?, #[cfg(feature = "macho")]
BinaryFormat::MachO => self.macho_adjust_addend(&mut relocation)?, #[cfg(feature = "xcoff")]
BinaryFormat::Xcoff => self.xcoff_adjust_addend(&mut relocation)?,
_ => unimplemented!(),
}; if implicit && relocation.addend != 0 { self.write_relocation_addend(section, &relocation)?;
relocation.addend = 0;
} self.sections[section.0].relocations.push(relocation);
Ok(())
}
/// Write the object to a `Vec`. pubfn write(&self) -> Result<Vec<u8>> { letmut 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")] pubfn write_stream<W: io::Write>(&self, w: W) -> result::Result<(), Box<dyn error::Error>> { letmut stream = StreamingBuffer::new(w); self.emit(&mut stream)?;
stream.result()?;
stream.into_inner().flush()?;
Ok(())
}
// 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)] pubstruct SectionId(usize);
/// A section in an object file. #[derive(Debug)] pubstruct Section<'a> {
segment: Vec<u8>,
name: Vec<u8>,
kind: SectionKind,
size: u64,
align: u64,
data: Cow<'a, [u8]>,
relocations: Vec<Relocation>,
symbol: Option<SymbolId>, /// 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] pubfn name(&self) -> Option<&str> {
str::from_utf8(&self.name).ok()
}
/// Try to convert the segment to a utf8 string. #[inline] pubfn segment(&self) -> Option<&str> {
str::from_utf8(&self.segment).ok()
}
/// Return true if this section contains zerofill data. #[inline] pubfn 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. /// `align` must be a power of two. pubfn set_data<T>(&mutself, data: T, align: u64) where
T: Into<Cow<'a, [u8]>>,
{
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. /// `align` must be a power of two. pubfn append_data(&mutself, append_data: &[u8], align: u64) -> u64 {
debug_assert!(!self.is_bss());
debug_assert_eq!(align & (align - 1), 0); ifself.align < align { self.align = align;
} let align = align as usize; let data = self.data.to_mut(); letmut 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. /// `align` must be a power of two. pubfn append_bss(&mutself, size: u64, align: u64) -> u64 {
debug_assert!(self.is_bss());
debug_assert_eq!(align & (align - 1), 0); ifself.align < align { self.align = align;
} letmut 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. pubfn 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. pubfn data_mut(&mutself) -> &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] pubenum 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] pubfn id(self) -> Option<SectionId> { iflet SymbolSection::Section(id) = self {
Some(id)
} else {
None
}
}
}
/// An identifier used to reference a symbol. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pubstruct SymbolId(usize);
/// A symbol in an object file. #[derive(Debug)] pubstruct Symbol { /// The name of the symbol. pub name: Vec<u8>, /// 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<SectionId, SymbolId>,
}
impl Symbol { /// Try to convert the name to a utf8 string. #[inline] pubfn name(&self) -> Option<&str> {
str::from_utf8(&self.name).ok()
}
/// Return true if the symbol is undefined. #[inline] pubfn 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] pubfn is_common(&self) -> bool { self.section == SymbolSection::Common
}
/// Return true if the symbol scope is local. #[inline] pubfn is_local(&self) -> bool { self.scope == SymbolScope::Compilation
}
}
/// A relocation in an object file. #[derive(Debug)] pubstruct Relocation { /// The section offset of the place of the relocation. pub offset: u64, /// 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, /// The fields that define the relocation type. pub flags: RelocationFlags,
}
/// An identifier used to reference a COMDAT section group. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pubstruct ComdatId(usize);
/// A COMDAT section group. #[derive(Debug)] pubstruct 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<SectionId>,
}
/// The symbol name mangling scheme. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[non_exhaustive] pubenum 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. pubfn 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. pubfn global_prefix(self) -> Option<u8> { matchself {
Mangling::None | Mangling::Elf | Mangling::Coff | Mangling::Xcoff => None,
Mangling::CoffI386 | Mangling::MachO => Some(b'_'),
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.