diff options
Diffstat (limited to 'vendor/object/src/write/coff')
-rw-r--r-- | vendor/object/src/write/coff/mod.rs | 10 | ||||
-rw-r--r-- | vendor/object/src/write/coff/object.rs | 583 | ||||
-rw-r--r-- | vendor/object/src/write/coff/writer.rs | 518 |
3 files changed, 0 insertions, 1111 deletions
diff --git a/vendor/object/src/write/coff/mod.rs b/vendor/object/src/write/coff/mod.rs deleted file mode 100644 index 6e0f5ed..0000000 --- a/vendor/object/src/write/coff/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! 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 deleted file mode 100644 index 5229665..0000000 --- a/vendor/object/src/write/coff/object.rs +++ /dev/null @@ -1,583 +0,0 @@ -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(§ion.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(§ion.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 §ion.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 deleted file mode 100644 index 8c7ada3..0000000 --- a/vendor/object/src/write/coff/writer.rs +++ /dev/null @@ -1,518 +0,0 @@ -//! 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, -} |