aboutsummaryrefslogtreecommitdiff
path: root/vendor/object/src/write/coff
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/object/src/write/coff')
-rw-r--r--vendor/object/src/write/coff/mod.rs10
-rw-r--r--vendor/object/src/write/coff/object.rs583
-rw-r--r--vendor/object/src/write/coff/writer.rs518
3 files changed, 1111 insertions, 0 deletions
diff --git a/vendor/object/src/write/coff/mod.rs b/vendor/object/src/write/coff/mod.rs
new file mode 100644
index 0000000..6e0f5ed
--- /dev/null
+++ b/vendor/object/src/write/coff/mod.rs
@@ -0,0 +1,10 @@
+//! Support for writing COFF files.
+//!
+//! Provides [`Writer`] for low level writing of COFF files.
+//! This is also used to provide COFF support for [`write::Object`](crate::write::Object).
+
+mod object;
+pub use self::object::*;
+
+mod writer;
+pub use writer::*;
diff --git a/vendor/object/src/write/coff/object.rs b/vendor/object/src/write/coff/object.rs
new file mode 100644
index 0000000..5229665
--- /dev/null
+++ b/vendor/object/src/write/coff/object.rs
@@ -0,0 +1,583 @@
+use alloc::vec::Vec;
+
+use crate::pe as coff;
+use crate::write::coff::writer;
+use crate::write::util::*;
+use crate::write::*;
+
+#[derive(Default, Clone, Copy)]
+struct SectionOffsets {
+ name: writer::Name,
+ offset: u32,
+ reloc_offset: u32,
+ selection: u8,
+ associative_section: u32,
+}
+
+#[derive(Default, Clone, Copy)]
+struct SymbolOffsets {
+ name: writer::Name,
+ index: u32,
+ aux_count: u8,
+}
+
+/// Internal format to use for the `.drectve` section containing linker
+/// directives for symbol exports.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum CoffExportStyle {
+ /// MSVC format supported by link.exe and LLD.
+ Msvc,
+ /// Gnu format supported by GNU LD and LLD.
+ Gnu,
+}
+
+impl<'a> Object<'a> {
+ pub(crate) fn coff_section_info(
+ &self,
+ section: StandardSection,
+ ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
+ match section {
+ StandardSection::Text => (&[], &b".text"[..], SectionKind::Text, SectionFlags::None),
+ StandardSection::Data => (&[], &b".data"[..], SectionKind::Data, SectionFlags::None),
+ StandardSection::ReadOnlyData
+ | StandardSection::ReadOnlyDataWithRel
+ | StandardSection::ReadOnlyString => (
+ &[],
+ &b".rdata"[..],
+ SectionKind::ReadOnlyData,
+ SectionFlags::None,
+ ),
+ StandardSection::UninitializedData => (
+ &[],
+ &b".bss"[..],
+ SectionKind::UninitializedData,
+ SectionFlags::None,
+ ),
+ // TLS sections are data sections with a special name.
+ StandardSection::Tls => (&[], &b".tls$"[..], SectionKind::Data, SectionFlags::None),
+ StandardSection::UninitializedTls => {
+ // Unsupported section.
+ (&[], &[], SectionKind::UninitializedTls, SectionFlags::None)
+ }
+ StandardSection::TlsVariables => {
+ // Unsupported section.
+ (&[], &[], SectionKind::TlsVariables, SectionFlags::None)
+ }
+ StandardSection::Common => {
+ // Unsupported section.
+ (&[], &[], SectionKind::Common, SectionFlags::None)
+ }
+ StandardSection::GnuProperty => {
+ // Unsupported section.
+ (&[], &[], SectionKind::Note, SectionFlags::None)
+ }
+ }
+ }
+
+ pub(crate) fn coff_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> {
+ let mut name = section.to_vec();
+ name.push(b'$');
+ name.extend_from_slice(value);
+ name
+ }
+
+ pub(crate) fn coff_fixup_relocation(&mut self, relocation: &mut Relocation) -> i64 {
+ if relocation.kind == RelocationKind::GotRelative {
+ // Use a stub symbol for the relocation instead.
+ // This isn't really a GOT, but it's a similar purpose.
+ // TODO: need to handle DLL imports differently?
+ relocation.kind = RelocationKind::Relative;
+ relocation.symbol = self.coff_add_stub_symbol(relocation.symbol);
+ } else if relocation.kind == RelocationKind::PltRelative {
+ // Windows doesn't need a separate relocation type for
+ // references to functions in import libraries.
+ // For convenience, treat this the same as Relative.
+ relocation.kind = RelocationKind::Relative;
+ }
+
+ let constant = match self.architecture {
+ Architecture::I386 | Architecture::Arm | Architecture::Aarch64 => match relocation.kind
+ {
+ RelocationKind::Relative => {
+ // IMAGE_REL_I386_REL32, IMAGE_REL_ARM_REL32, IMAGE_REL_ARM64_REL32
+ relocation.addend + 4
+ }
+ _ => relocation.addend,
+ },
+ Architecture::X86_64 => match relocation.kind {
+ RelocationKind::Relative => {
+ // IMAGE_REL_AMD64_REL32 through to IMAGE_REL_AMD64_REL32_5
+ if relocation.addend <= -4 && relocation.addend >= -9 {
+ 0
+ } else {
+ relocation.addend + 4
+ }
+ }
+ _ => relocation.addend,
+ },
+ _ => unimplemented!(),
+ };
+ relocation.addend -= constant;
+ constant
+ }
+
+ fn coff_add_stub_symbol(&mut self, symbol_id: SymbolId) -> SymbolId {
+ if let Some(stub_id) = self.stub_symbols.get(&symbol_id) {
+ return *stub_id;
+ }
+ let stub_size = self.architecture.address_size().unwrap().bytes();
+
+ let name = b".rdata$.refptr".to_vec();
+ let section_id = self.add_section(Vec::new(), name, SectionKind::ReadOnlyData);
+ let section = self.section_mut(section_id);
+ section.set_data(vec![0; stub_size as usize], u64::from(stub_size));
+ section.relocations = vec![Relocation {
+ offset: 0,
+ size: stub_size * 8,
+ kind: RelocationKind::Absolute,
+ encoding: RelocationEncoding::Generic,
+ symbol: symbol_id,
+ addend: 0,
+ }];
+
+ let mut name = b".refptr.".to_vec();
+ name.extend_from_slice(&self.symbol(symbol_id).name);
+ let stub_id = self.add_raw_symbol(Symbol {
+ name,
+ value: 0,
+ size: u64::from(stub_size),
+ kind: SymbolKind::Data,
+ scope: SymbolScope::Compilation,
+ weak: false,
+ section: SymbolSection::Section(section_id),
+ flags: SymbolFlags::None,
+ });
+ self.stub_symbols.insert(symbol_id, stub_id);
+
+ stub_id
+ }
+
+ /// Appends linker directives to the `.drectve` section to tell the linker
+ /// to export all symbols with `SymbolScope::Dynamic`.
+ ///
+ /// This must be called after all symbols have been defined.
+ pub fn add_coff_exports(&mut self, style: CoffExportStyle) {
+ assert_eq!(self.format, BinaryFormat::Coff);
+
+ let mut directives = vec![];
+ for symbol in &self.symbols {
+ if symbol.scope == SymbolScope::Dynamic {
+ match style {
+ CoffExportStyle::Msvc => directives.extend(b" /EXPORT:\""),
+ CoffExportStyle::Gnu => directives.extend(b" -export:\""),
+ }
+ directives.extend(&symbol.name);
+ directives.extend(b"\"");
+ if symbol.kind != SymbolKind::Text {
+ match style {
+ CoffExportStyle::Msvc => directives.extend(b",DATA"),
+ CoffExportStyle::Gnu => directives.extend(b",data"),
+ }
+ }
+ }
+ }
+ let drectve = self.add_section(vec![], b".drectve".to_vec(), SectionKind::Linker);
+ self.append_section_data(drectve, &directives, 1);
+ }
+
+ pub(crate) fn coff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
+ let mut writer = writer::Writer::new(buffer);
+
+ // Add section strings to strtab.
+ let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
+ for (index, section) in self.sections.iter().enumerate() {
+ section_offsets[index].name = writer.add_name(&section.name);
+ }
+
+ // Set COMDAT flags.
+ for comdat in &self.comdats {
+ let symbol = &self.symbols[comdat.symbol.0];
+ let comdat_section = match symbol.section {
+ SymbolSection::Section(id) => id.0,
+ _ => {
+ return Err(Error(format!(
+ "unsupported COMDAT symbol `{}` section {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.section
+ )));
+ }
+ };
+ section_offsets[comdat_section].selection = match comdat.kind {
+ ComdatKind::NoDuplicates => coff::IMAGE_COMDAT_SELECT_NODUPLICATES,
+ ComdatKind::Any => coff::IMAGE_COMDAT_SELECT_ANY,
+ ComdatKind::SameSize => coff::IMAGE_COMDAT_SELECT_SAME_SIZE,
+ ComdatKind::ExactMatch => coff::IMAGE_COMDAT_SELECT_EXACT_MATCH,
+ ComdatKind::Largest => coff::IMAGE_COMDAT_SELECT_LARGEST,
+ ComdatKind::Newest => coff::IMAGE_COMDAT_SELECT_NEWEST,
+ ComdatKind::Unknown => {
+ return Err(Error(format!(
+ "unsupported COMDAT symbol `{}` kind {:?}",
+ symbol.name().unwrap_or(""),
+ comdat.kind
+ )));
+ }
+ };
+ for id in &comdat.sections {
+ let section = &self.sections[id.0];
+ if section.symbol.is_none() {
+ return Err(Error(format!(
+ "missing symbol for COMDAT section `{}`",
+ section.name().unwrap_or(""),
+ )));
+ }
+ if id.0 != comdat_section {
+ section_offsets[id.0].selection = coff::IMAGE_COMDAT_SELECT_ASSOCIATIVE;
+ section_offsets[id.0].associative_section = comdat_section as u32 + 1;
+ }
+ }
+ }
+
+ // Reserve symbol indices and add symbol strings to strtab.
+ let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ symbol_offsets[index].index = writer.reserve_symbol_index();
+ let mut name = &*symbol.name;
+ match symbol.kind {
+ SymbolKind::File => {
+ // Name goes in auxiliary symbol records.
+ symbol_offsets[index].aux_count = writer.reserve_aux_file_name(&symbol.name);
+ name = b".file";
+ }
+ SymbolKind::Section if symbol.section.id().is_some() => {
+ symbol_offsets[index].aux_count = writer.reserve_aux_section();
+ }
+ _ => {}
+ };
+ symbol_offsets[index].name = writer.add_name(name);
+ }
+
+ // Reserve file ranges.
+ writer.reserve_file_header();
+ writer.reserve_section_headers(self.sections.len() as u16);
+ for (index, section) in self.sections.iter().enumerate() {
+ section_offsets[index].offset = writer.reserve_section(section.data.len());
+ section_offsets[index].reloc_offset =
+ writer.reserve_relocations(section.relocations.len());
+ }
+ writer.reserve_symtab_strtab();
+
+ // Start writing.
+ writer.write_file_header(writer::FileHeader {
+ machine: match (self.architecture, self.sub_architecture) {
+ (Architecture::Arm, None) => coff::IMAGE_FILE_MACHINE_ARMNT,
+ (Architecture::Aarch64, None) => coff::IMAGE_FILE_MACHINE_ARM64,
+ (Architecture::Aarch64, Some(SubArchitecture::Arm64EC)) => {
+ coff::IMAGE_FILE_MACHINE_ARM64EC
+ }
+ (Architecture::I386, None) => coff::IMAGE_FILE_MACHINE_I386,
+ (Architecture::X86_64, None) => coff::IMAGE_FILE_MACHINE_AMD64,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?} with sub-architecture {:?}",
+ self.architecture, self.sub_architecture
+ )));
+ }
+ },
+ time_date_stamp: 0,
+ characteristics: match self.flags {
+ FileFlags::Coff { characteristics } => characteristics,
+ _ => 0,
+ },
+ })?;
+
+ // Write section headers.
+ for (index, section) in self.sections.iter().enumerate() {
+ let mut characteristics = if let SectionFlags::Coff {
+ characteristics, ..
+ } = section.flags
+ {
+ characteristics
+ } else {
+ match section.kind {
+ SectionKind::Text => {
+ coff::IMAGE_SCN_CNT_CODE
+ | coff::IMAGE_SCN_MEM_EXECUTE
+ | coff::IMAGE_SCN_MEM_READ
+ }
+ SectionKind::Data => {
+ coff::IMAGE_SCN_CNT_INITIALIZED_DATA
+ | coff::IMAGE_SCN_MEM_READ
+ | coff::IMAGE_SCN_MEM_WRITE
+ }
+ SectionKind::UninitializedData => {
+ coff::IMAGE_SCN_CNT_UNINITIALIZED_DATA
+ | coff::IMAGE_SCN_MEM_READ
+ | coff::IMAGE_SCN_MEM_WRITE
+ }
+ SectionKind::ReadOnlyData
+ | SectionKind::ReadOnlyDataWithRel
+ | SectionKind::ReadOnlyString => {
+ coff::IMAGE_SCN_CNT_INITIALIZED_DATA | coff::IMAGE_SCN_MEM_READ
+ }
+ SectionKind::Debug | SectionKind::Other | SectionKind::OtherString => {
+ coff::IMAGE_SCN_CNT_INITIALIZED_DATA
+ | coff::IMAGE_SCN_MEM_READ
+ | coff::IMAGE_SCN_MEM_DISCARDABLE
+ }
+ SectionKind::Linker => coff::IMAGE_SCN_LNK_INFO | coff::IMAGE_SCN_LNK_REMOVE,
+ SectionKind::Common
+ | SectionKind::Tls
+ | SectionKind::UninitializedTls
+ | SectionKind::TlsVariables
+ | SectionKind::Note
+ | SectionKind::Unknown
+ | SectionKind::Metadata
+ | SectionKind::Elf(_) => {
+ return Err(Error(format!(
+ "unimplemented section `{}` kind {:?}",
+ section.name().unwrap_or(""),
+ section.kind
+ )));
+ }
+ }
+ };
+ if section_offsets[index].selection != 0 {
+ characteristics |= coff::IMAGE_SCN_LNK_COMDAT;
+ };
+ if section.relocations.len() > 0xffff {
+ characteristics |= coff::IMAGE_SCN_LNK_NRELOC_OVFL;
+ }
+ characteristics |= match section.align {
+ 1 => coff::IMAGE_SCN_ALIGN_1BYTES,
+ 2 => coff::IMAGE_SCN_ALIGN_2BYTES,
+ 4 => coff::IMAGE_SCN_ALIGN_4BYTES,
+ 8 => coff::IMAGE_SCN_ALIGN_8BYTES,
+ 16 => coff::IMAGE_SCN_ALIGN_16BYTES,
+ 32 => coff::IMAGE_SCN_ALIGN_32BYTES,
+ 64 => coff::IMAGE_SCN_ALIGN_64BYTES,
+ 128 => coff::IMAGE_SCN_ALIGN_128BYTES,
+ 256 => coff::IMAGE_SCN_ALIGN_256BYTES,
+ 512 => coff::IMAGE_SCN_ALIGN_512BYTES,
+ 1024 => coff::IMAGE_SCN_ALIGN_1024BYTES,
+ 2048 => coff::IMAGE_SCN_ALIGN_2048BYTES,
+ 4096 => coff::IMAGE_SCN_ALIGN_4096BYTES,
+ 8192 => coff::IMAGE_SCN_ALIGN_8192BYTES,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented section `{}` align {}",
+ section.name().unwrap_or(""),
+ section.align
+ )));
+ }
+ };
+ writer.write_section_header(writer::SectionHeader {
+ name: section_offsets[index].name,
+ size_of_raw_data: section.size as u32,
+ pointer_to_raw_data: section_offsets[index].offset,
+ pointer_to_relocations: section_offsets[index].reloc_offset,
+ pointer_to_linenumbers: 0,
+ number_of_relocations: section.relocations.len() as u32,
+ number_of_linenumbers: 0,
+ characteristics,
+ });
+ }
+
+ // Write section data and relocations.
+ for section in &self.sections {
+ writer.write_section(&section.data);
+
+ if !section.relocations.is_empty() {
+ //debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
+ writer.write_relocations_count(section.relocations.len());
+ for reloc in &section.relocations {
+ //assert!(reloc.implicit_addend);
+ let typ = match self.architecture {
+ Architecture::I386 => match (reloc.kind, reloc.size, reloc.addend) {
+ (RelocationKind::Absolute, 16, 0) => coff::IMAGE_REL_I386_DIR16,
+ (RelocationKind::Relative, 16, 0) => coff::IMAGE_REL_I386_REL16,
+ (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_I386_DIR32,
+ (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_I386_DIR32NB,
+ (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_I386_SECTION,
+ (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_I386_SECREL,
+ (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_I386_SECREL7,
+ (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_I386_REL32,
+ (RelocationKind::Coff(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::X86_64 => match (reloc.kind, reloc.size, reloc.addend) {
+ (RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_AMD64_ADDR64,
+ (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32,
+ (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32NB,
+ (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_AMD64_REL32,
+ (RelocationKind::Relative, 32, -5) => coff::IMAGE_REL_AMD64_REL32_1,
+ (RelocationKind::Relative, 32, -6) => coff::IMAGE_REL_AMD64_REL32_2,
+ (RelocationKind::Relative, 32, -7) => coff::IMAGE_REL_AMD64_REL32_3,
+ (RelocationKind::Relative, 32, -8) => coff::IMAGE_REL_AMD64_REL32_4,
+ (RelocationKind::Relative, 32, -9) => coff::IMAGE_REL_AMD64_REL32_5,
+ (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_AMD64_SECTION,
+ (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_AMD64_SECREL,
+ (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_AMD64_SECREL7,
+ (RelocationKind::Coff(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Arm => match (reloc.kind, reloc.size, reloc.addend) {
+ (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_ARM_ADDR32,
+ (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_ARM_ADDR32NB,
+ (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_ARM_REL32,
+ (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_ARM_SECTION,
+ (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_ARM_SECREL,
+ (RelocationKind::Coff(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::Aarch64 => match (reloc.kind, reloc.size, reloc.addend) {
+ (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_ARM64_ADDR32,
+ (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_ARM64_ADDR32NB,
+ (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_ARM64_SECTION,
+ (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_ARM64_SECREL,
+ (RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_ARM64_ADDR64,
+ (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_ARM64_REL32,
+ (RelocationKind::Coff(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?}",
+ self.architecture
+ )));
+ }
+ };
+ writer.write_relocation(writer::Relocation {
+ virtual_address: reloc.offset as u32,
+ symbol: symbol_offsets[reloc.symbol.0].index,
+ typ,
+ });
+ }
+ }
+ }
+
+ // Write symbols.
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ let section_number = match symbol.section {
+ SymbolSection::None => {
+ debug_assert_eq!(symbol.kind, SymbolKind::File);
+ coff::IMAGE_SYM_DEBUG as u16
+ }
+ SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED as u16,
+ SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE as u16,
+ SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED as u16,
+ SymbolSection::Section(id) => id.0 as u16 + 1,
+ };
+ let typ = if symbol.kind == SymbolKind::Text {
+ coff::IMAGE_SYM_DTYPE_FUNCTION << coff::IMAGE_SYM_DTYPE_SHIFT
+ } else {
+ coff::IMAGE_SYM_TYPE_NULL
+ };
+ let storage_class = match symbol.kind {
+ SymbolKind::File => coff::IMAGE_SYM_CLASS_FILE,
+ SymbolKind::Section => {
+ if symbol.section.id().is_some() {
+ coff::IMAGE_SYM_CLASS_STATIC
+ } else {
+ coff::IMAGE_SYM_CLASS_SECTION
+ }
+ }
+ SymbolKind::Label => coff::IMAGE_SYM_CLASS_LABEL,
+ SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => {
+ match symbol.section {
+ SymbolSection::None => {
+ return Err(Error(format!(
+ "missing section for symbol `{}`",
+ symbol.name().unwrap_or("")
+ )));
+ }
+ SymbolSection::Undefined | SymbolSection::Common => {
+ coff::IMAGE_SYM_CLASS_EXTERNAL
+ }
+ SymbolSection::Absolute | SymbolSection::Section(_) => {
+ match symbol.scope {
+ // TODO: does this need aux symbol records too?
+ _ if symbol.weak => coff::IMAGE_SYM_CLASS_WEAK_EXTERNAL,
+ SymbolScope::Unknown => {
+ return Err(Error(format!(
+ "unimplemented symbol `{}` scope {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.scope
+ )));
+ }
+ SymbolScope::Compilation => coff::IMAGE_SYM_CLASS_STATIC,
+ SymbolScope::Linkage | SymbolScope::Dynamic => {
+ coff::IMAGE_SYM_CLASS_EXTERNAL
+ }
+ }
+ }
+ }
+ }
+ SymbolKind::Unknown | SymbolKind::Null => {
+ return Err(Error(format!(
+ "unimplemented symbol `{}` kind {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.kind
+ )));
+ }
+ };
+ let number_of_aux_symbols = symbol_offsets[index].aux_count;
+ let value = if symbol.section == SymbolSection::Common {
+ symbol.size as u32
+ } else {
+ symbol.value as u32
+ };
+ writer.write_symbol(writer::Symbol {
+ name: symbol_offsets[index].name,
+ value,
+ section_number,
+ typ,
+ storage_class,
+ number_of_aux_symbols,
+ });
+
+ // Write auxiliary symbols.
+ match symbol.kind {
+ SymbolKind::File => {
+ writer.write_aux_file_name(&symbol.name, number_of_aux_symbols);
+ }
+ SymbolKind::Section if symbol.section.id().is_some() => {
+ debug_assert_eq!(number_of_aux_symbols, 1);
+ let section_index = symbol.section.id().unwrap().0;
+ let section = &self.sections[section_index];
+ writer.write_aux_section(writer::AuxSymbolSection {
+ length: section.size as u32,
+ number_of_relocations: section.relocations.len() as u32,
+ number_of_linenumbers: 0,
+ check_sum: checksum(section.data()),
+ number: section_offsets[section_index].associative_section,
+ selection: section_offsets[section_index].selection,
+ });
+ }
+ _ => {
+ debug_assert_eq!(number_of_aux_symbols, 0);
+ }
+ }
+ }
+
+ writer.write_strtab();
+
+ debug_assert_eq!(writer.reserved_len(), writer.len());
+
+ Ok(())
+ }
+}
+
+// JamCRC
+fn checksum(data: &[u8]) -> u32 {
+ let mut hasher = crc32fast::Hasher::new_with_initial(0xffff_ffff);
+ hasher.update(data);
+ !hasher.finalize()
+}
diff --git a/vendor/object/src/write/coff/writer.rs b/vendor/object/src/write/coff/writer.rs
new file mode 100644
index 0000000..8c7ada3
--- /dev/null
+++ b/vendor/object/src/write/coff/writer.rs
@@ -0,0 +1,518 @@
+//! Helper for writing COFF files.
+use alloc::string::String;
+use alloc::vec::Vec;
+use core::mem;
+
+use crate::endian::{LittleEndian as LE, U16Bytes, U32Bytes, U16, U32};
+use crate::pe;
+use crate::write::string::{StringId, StringTable};
+use crate::write::util;
+use crate::write::{Error, Result, WritableBuffer};
+
+/// A helper for writing COFF files.
+///
+/// Writing uses a two phase approach. The first phase builds up all of the information
+/// that may need to be known ahead of time:
+/// - build string table
+/// - reserve section indices
+/// - reserve symbol indices
+/// - reserve file ranges for headers and sections
+///
+/// Some of the information has ordering requirements. For example, strings must be added
+/// to the string table before reserving the file range for the string table. There are debug
+/// asserts to check some of these requirements.
+///
+/// The second phase writes everything out in order. Thus the caller must ensure writing
+/// is in the same order that file ranges were reserved. There are debug asserts to assist
+/// with checking this.
+#[allow(missing_debug_implementations)]
+pub struct Writer<'a> {
+ buffer: &'a mut dyn WritableBuffer,
+ len: usize,
+
+ section_num: u16,
+
+ symtab_offset: u32,
+ symtab_num: u32,
+
+ strtab: StringTable<'a>,
+ strtab_len: usize,
+ strtab_offset: u32,
+ strtab_data: Vec<u8>,
+}
+
+impl<'a> Writer<'a> {
+ /// Create a new `Writer`.
+ pub fn new(buffer: &'a mut dyn WritableBuffer) -> Self {
+ Writer {
+ buffer,
+ len: 0,
+
+ section_num: 0,
+
+ symtab_offset: 0,
+ symtab_num: 0,
+
+ strtab: StringTable::default(),
+ strtab_len: 0,
+ strtab_offset: 0,
+ strtab_data: Vec::new(),
+ }
+ }
+
+ /// Return the current file length that has been reserved.
+ pub fn reserved_len(&self) -> usize {
+ self.len
+ }
+
+ /// Return the current file length that has been written.
+ #[allow(clippy::len_without_is_empty)]
+ pub fn len(&self) -> usize {
+ self.buffer.len()
+ }
+
+ /// Reserve a file range with the given size and starting alignment.
+ ///
+ /// Returns the aligned offset of the start of the range.
+ pub fn reserve(&mut self, len: usize, align_start: usize) -> u32 {
+ if align_start > 1 {
+ self.len = util::align(self.len, align_start);
+ }
+ let offset = self.len;
+ self.len += len;
+ offset as u32
+ }
+
+ /// Write alignment padding bytes.
+ pub fn write_align(&mut self, align_start: usize) {
+ if align_start > 1 {
+ util::write_align(self.buffer, align_start);
+ }
+ }
+
+ /// Write data.
+ pub fn write(&mut self, data: &[u8]) {
+ self.buffer.write_bytes(data);
+ }
+
+ /// Reserve the file range up to the given file offset.
+ pub fn reserve_until(&mut self, offset: usize) {
+ debug_assert!(self.len <= offset);
+ self.len = offset;
+ }
+
+ /// Write padding up to the given file offset.
+ pub fn pad_until(&mut self, offset: usize) {
+ debug_assert!(self.buffer.len() <= offset);
+ self.buffer.resize(offset);
+ }
+
+ /// Reserve the range for the file header.
+ ///
+ /// This must be at the start of the file.
+ pub fn reserve_file_header(&mut self) {
+ debug_assert_eq!(self.len, 0);
+ self.reserve(mem::size_of::<pe::ImageFileHeader>(), 1);
+ }
+
+ /// Write the file header.
+ ///
+ /// This must be at the start of the file.
+ ///
+ /// Fields that can be derived from known information are automatically set by this function.
+ pub fn write_file_header(&mut self, header: FileHeader) -> Result<()> {
+ debug_assert_eq!(self.buffer.len(), 0);
+
+ // Start writing.
+ self.buffer
+ .reserve(self.len)
+ .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
+
+ // Write file header.
+ let header = pe::ImageFileHeader {
+ machine: U16::new(LE, header.machine),
+ number_of_sections: U16::new(LE, self.section_num),
+ time_date_stamp: U32::new(LE, header.time_date_stamp),
+ pointer_to_symbol_table: U32::new(LE, self.symtab_offset),
+ number_of_symbols: U32::new(LE, self.symtab_num),
+ size_of_optional_header: U16::default(),
+ characteristics: U16::new(LE, header.characteristics),
+ };
+ self.buffer.write(&header);
+
+ Ok(())
+ }
+
+ /// Reserve the range for the section headers.
+ pub fn reserve_section_headers(&mut self, section_num: u16) {
+ debug_assert_eq!(self.section_num, 0);
+ self.section_num = section_num;
+ self.reserve(
+ section_num as usize * mem::size_of::<pe::ImageSectionHeader>(),
+ 1,
+ );
+ }
+
+ /// Write a section header.
+ pub fn write_section_header(&mut self, section: SectionHeader) {
+ let mut coff_section = pe::ImageSectionHeader {
+ name: [0; 8],
+ virtual_size: U32::default(),
+ virtual_address: U32::default(),
+ size_of_raw_data: U32::new(LE, section.size_of_raw_data),
+ pointer_to_raw_data: U32::new(LE, section.pointer_to_raw_data),
+ pointer_to_relocations: U32::new(LE, section.pointer_to_relocations),
+ pointer_to_linenumbers: U32::new(LE, section.pointer_to_linenumbers),
+ number_of_relocations: if section.number_of_relocations > 0xffff {
+ U16::new(LE, 0xffff)
+ } else {
+ U16::new(LE, section.number_of_relocations as u16)
+ },
+ number_of_linenumbers: U16::default(),
+ characteristics: U32::new(LE, section.characteristics),
+ };
+ match section.name {
+ Name::Short(name) => coff_section.name = name,
+ Name::Long(str_id) => {
+ let mut str_offset = self.strtab.get_offset(str_id);
+ if str_offset <= 9_999_999 {
+ let mut name = [0; 7];
+ let mut len = 0;
+ if str_offset == 0 {
+ name[6] = b'0';
+ len = 1;
+ } else {
+ while str_offset != 0 {
+ let rem = (str_offset % 10) as u8;
+ str_offset /= 10;
+ name[6 - len] = b'0' + rem;
+ len += 1;
+ }
+ }
+ coff_section.name = [0; 8];
+ coff_section.name[0] = b'/';
+ coff_section.name[1..][..len].copy_from_slice(&name[7 - len..]);
+ } else {
+ debug_assert!(str_offset as u64 <= 0xf_ffff_ffff);
+ coff_section.name[0] = b'/';
+ coff_section.name[1] = b'/';
+ for i in 0..6 {
+ let rem = (str_offset % 64) as u8;
+ str_offset /= 64;
+ let c = match rem {
+ 0..=25 => b'A' + rem,
+ 26..=51 => b'a' + rem - 26,
+ 52..=61 => b'0' + rem - 52,
+ 62 => b'+',
+ 63 => b'/',
+ _ => unreachable!(),
+ };
+ coff_section.name[7 - i] = c;
+ }
+ }
+ }
+ }
+ self.buffer.write(&coff_section);
+ }
+
+ /// Reserve the range for the section data.
+ ///
+ /// Returns the aligned offset of the start of the range.
+ /// Does nothing and returns 0 if the length is zero.
+ pub fn reserve_section(&mut self, len: usize) -> u32 {
+ if len == 0 {
+ return 0;
+ }
+ // TODO: not sure what alignment is required here, but this seems to match LLVM
+ self.reserve(len, 4)
+ }
+
+ /// Write the alignment bytes prior to section data.
+ ///
+ /// This is unneeded if you are using `write_section` or `write_section_zeroes`
+ /// for the data.
+ pub fn write_section_align(&mut self) {
+ util::write_align(self.buffer, 4);
+ }
+
+ /// Write the section data.
+ ///
+ /// Writes alignment bytes prior to the data.
+ /// Does nothing if the data is empty.
+ pub fn write_section(&mut self, data: &[u8]) {
+ if data.is_empty() {
+ return;
+ }
+ self.write_section_align();
+ self.buffer.write_bytes(data);
+ }
+
+ /// Write the section data using zero bytes.
+ ///
+ /// Writes alignment bytes prior to the data.
+ /// Does nothing if the length is zero.
+ pub fn write_section_zeroes(&mut self, len: usize) {
+ if len == 0 {
+ return;
+ }
+ self.write_section_align();
+ self.buffer.resize(self.buffer.len() + len);
+ }
+
+ /// Reserve a file range for the given number of relocations.
+ ///
+ /// This will automatically reserve an extra relocation if there are more than 0xffff.
+ ///
+ /// Returns the offset of the range.
+ /// Does nothing and returns 0 if the count is zero.
+ pub fn reserve_relocations(&mut self, mut count: usize) -> u32 {
+ if count == 0 {
+ return 0;
+ }
+ if count > 0xffff {
+ count += 1;
+ }
+ self.reserve(count * mem::size_of::<pe::ImageRelocation>(), 1)
+ }
+
+ /// Write a relocation containing the count if required.
+ ///
+ /// This should be called before writing the first relocation for a section.
+ pub fn write_relocations_count(&mut self, count: usize) {
+ if count > 0xffff {
+ let coff_relocation = pe::ImageRelocation {
+ virtual_address: U32Bytes::new(LE, count as u32 + 1),
+ symbol_table_index: U32Bytes::new(LE, 0),
+ typ: U16Bytes::new(LE, 0),
+ };
+ self.buffer.write(&coff_relocation);
+ }
+ }
+
+ /// Write a relocation.
+ pub fn write_relocation(&mut self, reloc: Relocation) {
+ let coff_relocation = pe::ImageRelocation {
+ virtual_address: U32Bytes::new(LE, reloc.virtual_address),
+ symbol_table_index: U32Bytes::new(LE, reloc.symbol),
+ typ: U16Bytes::new(LE, reloc.typ),
+ };
+ self.buffer.write(&coff_relocation);
+ }
+
+ /// Reserve a symbol table entry.
+ ///
+ /// This must be called before [`Self::reserve_symtab_strtab`].
+ pub fn reserve_symbol_index(&mut self) -> u32 {
+ debug_assert_eq!(self.symtab_offset, 0);
+ let index = self.symtab_num;
+ self.symtab_num += 1;
+ index
+ }
+
+ /// Reserve a number of symbol table entries.
+ pub fn reserve_symbol_indices(&mut self, count: u32) {
+ debug_assert_eq!(self.symtab_offset, 0);
+ self.symtab_num += count;
+ }
+
+ /// Write a symbol table entry.
+ pub fn write_symbol(&mut self, symbol: Symbol) {
+ let mut coff_symbol = pe::ImageSymbol {
+ name: [0; 8],
+ value: U32Bytes::new(LE, symbol.value),
+ section_number: U16Bytes::new(LE, symbol.section_number),
+ typ: U16Bytes::new(LE, symbol.typ),
+ storage_class: symbol.storage_class,
+ number_of_aux_symbols: symbol.number_of_aux_symbols,
+ };
+ match symbol.name {
+ Name::Short(name) => coff_symbol.name = name,
+ Name::Long(str_id) => {
+ let str_offset = self.strtab.get_offset(str_id);
+ coff_symbol.name[4..8].copy_from_slice(&u32::to_le_bytes(str_offset as u32));
+ }
+ }
+ self.buffer.write(&coff_symbol);
+ }
+
+ /// Reserve auxiliary symbols for a file name.
+ ///
+ /// Returns the number of auxiliary symbols required.
+ ///
+ /// This must be called before [`Self::reserve_symtab_strtab`].
+ pub fn reserve_aux_file_name(&mut self, name: &[u8]) -> u8 {
+ debug_assert_eq!(self.symtab_offset, 0);
+ let aux_count = (name.len() + pe::IMAGE_SIZEOF_SYMBOL - 1) / pe::IMAGE_SIZEOF_SYMBOL;
+ self.symtab_num += aux_count as u32;
+ aux_count as u8
+ }
+
+ /// Write auxiliary symbols for a file name.
+ pub fn write_aux_file_name(&mut self, name: &[u8], aux_count: u8) {
+ let aux_len = aux_count as usize * pe::IMAGE_SIZEOF_SYMBOL;
+ debug_assert!(aux_len >= name.len());
+ let old_len = self.buffer.len();
+ self.buffer.write_bytes(name);
+ self.buffer.resize(old_len + aux_len);
+ }
+
+ /// Reserve an auxiliary symbol for a section.
+ ///
+ /// Returns the number of auxiliary symbols required.
+ ///
+ /// This must be called before [`Self::reserve_symtab_strtab`].
+ pub fn reserve_aux_section(&mut self) -> u8 {
+ debug_assert_eq!(self.symtab_offset, 0);
+ self.symtab_num += 1;
+ 1
+ }
+
+ /// Write an auxiliary symbol for a section.
+ pub fn write_aux_section(&mut self, section: AuxSymbolSection) {
+ let aux = pe::ImageAuxSymbolSection {
+ length: U32Bytes::new(LE, section.length),
+ number_of_relocations: if section.number_of_relocations > 0xffff {
+ U16Bytes::new(LE, 0xffff)
+ } else {
+ U16Bytes::new(LE, section.number_of_relocations as u16)
+ },
+ number_of_linenumbers: U16Bytes::new(LE, section.number_of_linenumbers),
+ check_sum: U32Bytes::new(LE, section.check_sum),
+ number: U16Bytes::new(LE, section.number as u16),
+ selection: section.selection,
+ reserved: 0,
+ high_number: U16Bytes::new(LE, (section.number >> 16) as u16),
+ };
+ self.buffer.write(&aux);
+ }
+
+ /// Return the number of reserved symbol table entries.
+ pub fn symbol_count(&self) -> u32 {
+ self.symtab_num
+ }
+
+ /// Add a string to the string table.
+ ///
+ /// This must be called before [`Self::reserve_symtab_strtab`].
+ pub fn add_string(&mut self, name: &'a [u8]) -> StringId {
+ debug_assert_eq!(self.strtab_offset, 0);
+ self.strtab.add(name)
+ }
+
+ /// Add a section or symbol name to the string table if required.
+ ///
+ /// This must be called before [`Self::reserve_symtab_strtab`].
+ pub fn add_name(&mut self, name: &'a [u8]) -> Name {
+ if name.len() > 8 {
+ Name::Long(self.add_string(name))
+ } else {
+ let mut short_name = [0; 8];
+ short_name[..name.len()].copy_from_slice(name);
+ Name::Short(short_name)
+ }
+ }
+
+ /// Reserve the range for the symbol table and string table.
+ ///
+ /// This must be called after functions that reserve symbol
+ /// indices or add strings.
+ pub fn reserve_symtab_strtab(&mut self) {
+ debug_assert_eq!(self.symtab_offset, 0);
+ self.symtab_offset = self.reserve(self.symtab_num as usize * pe::IMAGE_SIZEOF_SYMBOL, 1);
+
+ debug_assert_eq!(self.strtab_offset, 0);
+ // First 4 bytes of strtab are the length.
+ self.strtab.write(4, &mut self.strtab_data);
+ self.strtab_len = self.strtab_data.len() + 4;
+ self.strtab_offset = self.reserve(self.strtab_len, 1);
+ }
+
+ /// Write the string table.
+ pub fn write_strtab(&mut self) {
+ debug_assert_eq!(self.strtab_offset, self.buffer.len() as u32);
+ self.buffer
+ .write_bytes(&u32::to_le_bytes(self.strtab_len as u32));
+ self.buffer.write_bytes(&self.strtab_data);
+ }
+}
+
+/// Shortened and native endian version of [`pe::ImageFileHeader`].
+#[allow(missing_docs)]
+#[derive(Debug, Default, Clone)]
+pub struct FileHeader {
+ pub machine: u16,
+ pub time_date_stamp: u32,
+ pub characteristics: u16,
+}
+
+/// A section or symbol name.
+#[derive(Debug, Clone, Copy)]
+pub enum Name {
+ /// An inline name.
+ Short([u8; 8]),
+ /// An id of a string table entry.
+ Long(StringId),
+}
+
+impl Default for Name {
+ fn default() -> Name {
+ Name::Short([0; 8])
+ }
+}
+
+// From isn't useful.
+#[allow(clippy::from_over_into)]
+impl<'a> Into<Name> for &'a [u8; 8] {
+ fn into(self) -> Name {
+ Name::Short(*self)
+ }
+}
+
+/// Native endian version of [`pe::ImageSectionHeader`].
+#[allow(missing_docs)]
+#[derive(Debug, Default, Clone)]
+pub struct SectionHeader {
+ pub name: Name,
+ pub size_of_raw_data: u32,
+ pub pointer_to_raw_data: u32,
+ pub pointer_to_relocations: u32,
+ pub pointer_to_linenumbers: u32,
+ /// This will automatically be clamped if there are more than 0xffff.
+ pub number_of_relocations: u32,
+ pub number_of_linenumbers: u16,
+ pub characteristics: u32,
+}
+
+/// Native endian version of [`pe::ImageSymbol`].
+#[allow(missing_docs)]
+#[derive(Debug, Default, Clone)]
+pub struct Symbol {
+ pub name: Name,
+ pub value: u32,
+ pub section_number: u16,
+ pub typ: u16,
+ pub storage_class: u8,
+ pub number_of_aux_symbols: u8,
+}
+
+/// Native endian version of [`pe::ImageAuxSymbolSection`].
+#[allow(missing_docs)]
+#[derive(Debug, Default, Clone)]
+pub struct AuxSymbolSection {
+ pub length: u32,
+ /// This will automatically be clamped if there are more than 0xffff.
+ pub number_of_relocations: u32,
+ pub number_of_linenumbers: u16,
+ pub check_sum: u32,
+ pub number: u32,
+ pub selection: u8,
+}
+
+/// Native endian version of [`pe::ImageRelocation`].
+#[allow(missing_docs)]
+#[derive(Debug, Default, Clone)]
+pub struct Relocation {
+ pub virtual_address: u32,
+ pub symbol: u32,
+ pub typ: u16,
+}