diff options
Diffstat (limited to 'vendor/object/src/write')
-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 | ||||
-rw-r--r-- | vendor/object/src/write/elf/mod.rs | 9 | ||||
-rw-r--r-- | vendor/object/src/write/elf/object.rs | 907 | ||||
-rw-r--r-- | vendor/object/src/write/elf/writer.rs | 2143 | ||||
-rw-r--r-- | vendor/object/src/write/macho.rs | 1095 | ||||
-rw-r--r-- | vendor/object/src/write/mod.rs | 961 | ||||
-rw-r--r-- | vendor/object/src/write/pe.rs | 847 | ||||
-rw-r--r-- | vendor/object/src/write/string.rs | 159 | ||||
-rw-r--r-- | vendor/object/src/write/util.rs | 260 | ||||
-rw-r--r-- | vendor/object/src/write/xcoff.rs | 556 |
12 files changed, 0 insertions, 8048 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, -} diff --git a/vendor/object/src/write/elf/mod.rs b/vendor/object/src/write/elf/mod.rs deleted file mode 100644 index 3a4f371..0000000 --- a/vendor/object/src/write/elf/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Support for writing ELF files. -//! -//! Provides [`Writer`] for low level writing of ELF files. -//! This is also used to provide ELF support for [`write::Object`](crate::write::Object). - -mod object; - -mod writer; -pub use writer::*; diff --git a/vendor/object/src/write/elf/object.rs b/vendor/object/src/write/elf/object.rs deleted file mode 100644 index 5d7a93e..0000000 --- a/vendor/object/src/write/elf/object.rs +++ /dev/null @@ -1,907 +0,0 @@ -use alloc::vec::Vec; - -use crate::write::elf::writer::*; -use crate::write::string::StringId; -use crate::write::*; -use crate::AddressSize; -use crate::{elf, pod}; - -#[derive(Clone, Copy)] -struct ComdatOffsets { - offset: usize, - str_id: StringId, -} - -#[derive(Clone, Copy)] -struct SectionOffsets { - index: SectionIndex, - offset: usize, - str_id: StringId, - reloc_offset: usize, - reloc_str_id: Option<StringId>, -} - -#[derive(Default, Clone, Copy)] -struct SymbolOffsets { - index: SymbolIndex, - str_id: Option<StringId>, -} - -// Public methods. -impl<'a> Object<'a> { - /// Add a property with a u32 value to the ELF ".note.gnu.property" section. - /// - /// Requires `feature = "elf"`. - pub fn add_elf_gnu_property_u32(&mut self, property: u32, value: u32) { - if self.format != BinaryFormat::Elf { - return; - } - - let align = if self.elf_is_64() { 8 } else { 4 }; - let mut data = Vec::with_capacity(32); - let n_name = b"GNU\0"; - data.extend_from_slice(pod::bytes_of(&elf::NoteHeader32 { - n_namesz: U32::new(self.endian, n_name.len() as u32), - n_descsz: U32::new(self.endian, util::align(3 * 4, align) as u32), - n_type: U32::new(self.endian, elf::NT_GNU_PROPERTY_TYPE_0), - })); - data.extend_from_slice(n_name); - // This happens to already be aligned correctly. - debug_assert_eq!(util::align(data.len(), align), data.len()); - data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, property))); - // Value size - data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, 4))); - data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, value))); - util::write_align(&mut data, align); - - let section = self.section_id(StandardSection::GnuProperty); - self.append_section_data(section, &data, align as u64); - } -} - -// Private methods. -impl<'a> Object<'a> { - pub(crate) fn elf_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::ReadOnlyString => ( - &[], - &b".rodata"[..], - SectionKind::ReadOnlyData, - SectionFlags::None, - ), - StandardSection::ReadOnlyDataWithRel => ( - &[], - b".data.rel.ro", - SectionKind::ReadOnlyDataWithRel, - SectionFlags::None, - ), - StandardSection::UninitializedData => ( - &[], - &b".bss"[..], - SectionKind::UninitializedData, - SectionFlags::None, - ), - StandardSection::Tls => (&[], &b".tdata"[..], SectionKind::Tls, SectionFlags::None), - StandardSection::UninitializedTls => ( - &[], - &b".tbss"[..], - SectionKind::UninitializedTls, - SectionFlags::None, - ), - StandardSection::TlsVariables => { - // Unsupported section. - (&[], &[], SectionKind::TlsVariables, SectionFlags::None) - } - StandardSection::Common => { - // Unsupported section. - (&[], &[], SectionKind::Common, SectionFlags::None) - } - StandardSection::GnuProperty => ( - &[], - &b".note.gnu.property"[..], - SectionKind::Note, - SectionFlags::Elf { - sh_flags: u64::from(elf::SHF_ALLOC), - }, - ), - } - } - - pub(crate) fn elf_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> { - let mut name = section.to_vec(); - name.push(b'.'); - name.extend_from_slice(value); - name - } - - fn elf_has_relocation_addend(&self) -> Result<bool> { - Ok(match self.architecture { - Architecture::Aarch64 => true, - Architecture::Aarch64_Ilp32 => true, - Architecture::Arm => false, - Architecture::Avr => true, - Architecture::Bpf => false, - Architecture::Csky => true, - Architecture::I386 => false, - Architecture::X86_64 => true, - Architecture::X86_64_X32 => true, - Architecture::Hexagon => true, - Architecture::LoongArch64 => true, - Architecture::Mips => false, - Architecture::Mips64 => true, - Architecture::Msp430 => true, - Architecture::PowerPc => true, - Architecture::PowerPc64 => true, - Architecture::Riscv64 => true, - Architecture::Riscv32 => true, - Architecture::S390x => true, - Architecture::Sbf => false, - Architecture::Sharc => true, - Architecture::Sparc64 => true, - Architecture::Xtensa => true, - _ => { - return Err(Error(format!( - "unimplemented architecture {:?}", - self.architecture - ))); - } - }) - } - - pub(crate) fn elf_fixup_relocation(&mut self, relocation: &mut Relocation) -> Result<i64> { - // Determine whether the addend is stored in the relocation or the data. - if self.elf_has_relocation_addend()? { - Ok(0) - } else { - let constant = relocation.addend; - relocation.addend = 0; - Ok(constant) - } - } - - pub(crate) fn elf_is_64(&self) -> bool { - match self.architecture.address_size().unwrap() { - AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => false, - AddressSize::U64 => true, - } - } - - pub(crate) fn elf_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { - // Create reloc section header names so we can reference them. - let is_rela = self.elf_has_relocation_addend()?; - let reloc_names: Vec<_> = self - .sections - .iter() - .map(|section| { - let mut reloc_name = Vec::with_capacity( - if is_rela { ".rela".len() } else { ".rel".len() } + section.name.len(), - ); - if !section.relocations.is_empty() { - reloc_name.extend_from_slice(if is_rela { - &b".rela"[..] - } else { - &b".rel"[..] - }); - reloc_name.extend_from_slice(§ion.name); - } - reloc_name - }) - .collect(); - - // Start calculating offsets of everything. - let mut writer = Writer::new(self.endian, self.elf_is_64(), buffer); - writer.reserve_file_header(); - - // Calculate size of section data. - let mut comdat_offsets = Vec::with_capacity(self.comdats.len()); - for comdat in &self.comdats { - if comdat.kind != ComdatKind::Any { - return Err(Error(format!( - "unsupported COMDAT symbol `{}` kind {:?}", - self.symbols[comdat.symbol.0].name().unwrap_or(""), - comdat.kind - ))); - } - - writer.reserve_section_index(); - let offset = writer.reserve_comdat(comdat.sections.len()); - let str_id = writer.add_section_name(b".group"); - comdat_offsets.push(ComdatOffsets { offset, str_id }); - } - let mut section_offsets = Vec::with_capacity(self.sections.len()); - for (section, reloc_name) in self.sections.iter().zip(reloc_names.iter()) { - let index = writer.reserve_section_index(); - let offset = writer.reserve(section.data.len(), section.align as usize); - let str_id = writer.add_section_name(§ion.name); - let mut reloc_str_id = None; - if !section.relocations.is_empty() { - writer.reserve_section_index(); - reloc_str_id = Some(writer.add_section_name(reloc_name)); - } - section_offsets.push(SectionOffsets { - index, - offset, - str_id, - // Relocation data is reserved later. - reloc_offset: 0, - reloc_str_id, - }); - } - - // Calculate index of symbols and add symbol strings to strtab. - let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; - writer.reserve_null_symbol_index(); - // Local symbols must come before global. - for (index, symbol) in self.symbols.iter().enumerate() { - if symbol.is_local() { - let section_index = symbol.section.id().map(|s| section_offsets[s.0].index); - symbol_offsets[index].index = writer.reserve_symbol_index(section_index); - } - } - let symtab_num_local = writer.symbol_count(); - for (index, symbol) in self.symbols.iter().enumerate() { - if !symbol.is_local() { - let section_index = symbol.section.id().map(|s| section_offsets[s.0].index); - symbol_offsets[index].index = writer.reserve_symbol_index(section_index); - } - } - for (index, symbol) in self.symbols.iter().enumerate() { - if symbol.kind != SymbolKind::Section && !symbol.name.is_empty() { - symbol_offsets[index].str_id = Some(writer.add_string(&symbol.name)); - } - } - - // Calculate size of symbols. - writer.reserve_symtab_section_index(); - writer.reserve_symtab(); - if writer.symtab_shndx_needed() { - writer.reserve_symtab_shndx_section_index(); - } - writer.reserve_symtab_shndx(); - writer.reserve_strtab_section_index(); - writer.reserve_strtab(); - - // Calculate size of relocations. - for (index, section) in self.sections.iter().enumerate() { - let count = section.relocations.len(); - if count != 0 { - section_offsets[index].reloc_offset = writer.reserve_relocations(count, is_rela); - } - } - - // Calculate size of section headers. - writer.reserve_shstrtab_section_index(); - writer.reserve_shstrtab(); - writer.reserve_section_headers(); - - // Start writing. - let e_type = elf::ET_REL; - let e_machine = match (self.architecture, self.sub_architecture) { - (Architecture::Aarch64, None) => elf::EM_AARCH64, - (Architecture::Aarch64_Ilp32, None) => elf::EM_AARCH64, - (Architecture::Arm, None) => elf::EM_ARM, - (Architecture::Avr, None) => elf::EM_AVR, - (Architecture::Bpf, None) => elf::EM_BPF, - (Architecture::Csky, None) => elf::EM_CSKY, - (Architecture::I386, None) => elf::EM_386, - (Architecture::X86_64, None) => elf::EM_X86_64, - (Architecture::X86_64_X32, None) => elf::EM_X86_64, - (Architecture::Hexagon, None) => elf::EM_HEXAGON, - (Architecture::LoongArch64, None) => elf::EM_LOONGARCH, - (Architecture::Mips, None) => elf::EM_MIPS, - (Architecture::Mips64, None) => elf::EM_MIPS, - (Architecture::Msp430, None) => elf::EM_MSP430, - (Architecture::PowerPc, None) => elf::EM_PPC, - (Architecture::PowerPc64, None) => elf::EM_PPC64, - (Architecture::Riscv32, None) => elf::EM_RISCV, - (Architecture::Riscv64, None) => elf::EM_RISCV, - (Architecture::S390x, None) => elf::EM_S390, - (Architecture::Sbf, None) => elf::EM_SBF, - (Architecture::Sharc, None) => elf::EM_SHARC, - (Architecture::Sparc64, None) => elf::EM_SPARCV9, - (Architecture::Xtensa, None) => elf::EM_XTENSA, - _ => { - return Err(Error(format!( - "unimplemented architecture {:?} with sub-architecture {:?}", - self.architecture, self.sub_architecture - ))); - } - }; - let (os_abi, abi_version, e_flags) = if let FileFlags::Elf { - os_abi, - abi_version, - e_flags, - } = self.flags - { - (os_abi, abi_version, e_flags) - } else { - (elf::ELFOSABI_NONE, 0, 0) - }; - writer.write_file_header(&FileHeader { - os_abi, - abi_version, - e_type, - e_machine, - e_entry: 0, - e_flags, - })?; - - // Write section data. - for comdat in &self.comdats { - writer.write_comdat_header(); - for section in &comdat.sections { - writer.write_comdat_entry(section_offsets[section.0].index); - } - } - for (index, section) in self.sections.iter().enumerate() { - writer.write_align(section.align as usize); - debug_assert_eq!(section_offsets[index].offset, writer.len()); - writer.write(§ion.data); - } - - // Write symbols. - writer.write_null_symbol(); - let mut write_symbol = |index: usize, symbol: &Symbol| -> Result<()> { - let st_info = if let SymbolFlags::Elf { st_info, .. } = symbol.flags { - st_info - } else { - let st_type = match symbol.kind { - SymbolKind::Null => elf::STT_NOTYPE, - SymbolKind::Text => { - if symbol.is_undefined() { - elf::STT_NOTYPE - } else { - elf::STT_FUNC - } - } - SymbolKind::Data => { - if symbol.is_undefined() { - elf::STT_NOTYPE - } else if symbol.is_common() { - elf::STT_COMMON - } else { - elf::STT_OBJECT - } - } - SymbolKind::Section => elf::STT_SECTION, - SymbolKind::File => elf::STT_FILE, - SymbolKind::Tls => elf::STT_TLS, - SymbolKind::Label => elf::STT_NOTYPE, - SymbolKind::Unknown => { - if symbol.is_undefined() { - elf::STT_NOTYPE - } else { - return Err(Error(format!( - "unimplemented symbol `{}` kind {:?}", - symbol.name().unwrap_or(""), - symbol.kind - ))); - } - } - }; - let st_bind = if symbol.weak { - elf::STB_WEAK - } else if symbol.is_undefined() { - elf::STB_GLOBAL - } else if symbol.is_local() { - elf::STB_LOCAL - } else { - elf::STB_GLOBAL - }; - (st_bind << 4) + st_type - }; - let st_other = if let SymbolFlags::Elf { st_other, .. } = symbol.flags { - st_other - } else if symbol.scope == SymbolScope::Linkage { - elf::STV_HIDDEN - } else { - elf::STV_DEFAULT - }; - let (st_shndx, section) = match symbol.section { - SymbolSection::None => { - debug_assert_eq!(symbol.kind, SymbolKind::File); - (elf::SHN_ABS, None) - } - SymbolSection::Undefined => (elf::SHN_UNDEF, None), - SymbolSection::Absolute => (elf::SHN_ABS, None), - SymbolSection::Common => (elf::SHN_COMMON, None), - SymbolSection::Section(id) => (0, Some(section_offsets[id.0].index)), - }; - writer.write_symbol(&Sym { - name: symbol_offsets[index].str_id, - section, - st_info, - st_other, - st_shndx, - st_value: symbol.value, - st_size: symbol.size, - }); - Ok(()) - }; - for (index, symbol) in self.symbols.iter().enumerate() { - if symbol.is_local() { - write_symbol(index, symbol)?; - } - } - for (index, symbol) in self.symbols.iter().enumerate() { - if !symbol.is_local() { - write_symbol(index, symbol)?; - } - } - writer.write_symtab_shndx(); - writer.write_strtab(); - - // Write relocations. - for (index, section) in self.sections.iter().enumerate() { - if !section.relocations.is_empty() { - writer.write_align_relocation(); - debug_assert_eq!(section_offsets[index].reloc_offset, writer.len()); - for reloc in §ion.relocations { - let r_type = match self.architecture { - Architecture::Aarch64 => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => { - elf::R_AARCH64_ABS64 - } - (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => { - elf::R_AARCH64_ABS32 - } - (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => { - elf::R_AARCH64_ABS16 - } - (RelocationKind::Relative, RelocationEncoding::Generic, 64) => { - elf::R_AARCH64_PREL64 - } - (RelocationKind::Relative, RelocationEncoding::Generic, 32) => { - elf::R_AARCH64_PREL32 - } - (RelocationKind::Relative, RelocationEncoding::Generic, 16) => { - elf::R_AARCH64_PREL16 - } - (RelocationKind::Relative, RelocationEncoding::AArch64Call, 26) - | (RelocationKind::PltRelative, RelocationEncoding::AArch64Call, 26) => { - elf::R_AARCH64_CALL26 - } - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::Aarch64_Ilp32 => { - match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => { - elf::R_AARCH64_P32_ABS32 - } - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!( - "unimplemented relocation {:?}", - reloc - ))); - } - } - } - Architecture::Arm => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 32) => elf::R_ARM_ABS32, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::Avr => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 32) => elf::R_AVR_32, - (RelocationKind::Absolute, _, 16) => elf::R_AVR_16, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::Bpf => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 64) => elf::R_BPF_64_64, - (RelocationKind::Absolute, _, 32) => elf::R_BPF_64_32, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::Csky => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 32) => elf::R_CKCORE_ADDR32, - (RelocationKind::Relative, RelocationEncoding::Generic, 32) => { - elf::R_CKCORE_PCREL32 - } - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::I386 => match (reloc.kind, reloc.size) { - (RelocationKind::Absolute, 32) => elf::R_386_32, - (RelocationKind::Relative, 32) => elf::R_386_PC32, - (RelocationKind::Got, 32) => elf::R_386_GOT32, - (RelocationKind::PltRelative, 32) => elf::R_386_PLT32, - (RelocationKind::GotBaseOffset, 32) => elf::R_386_GOTOFF, - (RelocationKind::GotBaseRelative, 32) => elf::R_386_GOTPC, - (RelocationKind::Absolute, 16) => elf::R_386_16, - (RelocationKind::Relative, 16) => elf::R_386_PC16, - (RelocationKind::Absolute, 8) => elf::R_386_8, - (RelocationKind::Relative, 8) => elf::R_386_PC8, - (RelocationKind::Elf(x), _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::X86_64 | Architecture::X86_64_X32 => { - match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => { - elf::R_X86_64_64 - } - (RelocationKind::Relative, RelocationEncoding::X86Branch, 32) => { - elf::R_X86_64_PLT32 - } - (RelocationKind::Relative, _, 32) => elf::R_X86_64_PC32, - (RelocationKind::Got, _, 32) => elf::R_X86_64_GOT32, - (RelocationKind::PltRelative, _, 32) => elf::R_X86_64_PLT32, - (RelocationKind::GotRelative, _, 32) => elf::R_X86_64_GOTPCREL, - (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => { - elf::R_X86_64_32 - } - (RelocationKind::Absolute, RelocationEncoding::X86Signed, 32) => { - elf::R_X86_64_32S - } - (RelocationKind::Absolute, _, 16) => elf::R_X86_64_16, - (RelocationKind::Relative, _, 16) => elf::R_X86_64_PC16, - (RelocationKind::Absolute, _, 8) => elf::R_X86_64_8, - (RelocationKind::Relative, _, 8) => elf::R_X86_64_PC8, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!( - "unimplemented relocation {:?}", - reloc - ))); - } - } - } - Architecture::Hexagon => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 32) => elf::R_HEX_32, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::LoongArch64 => match (reloc.kind, reloc.encoding, reloc.size) - { - (RelocationKind::Absolute, _, 32) => elf::R_LARCH_32, - (RelocationKind::Absolute, _, 64) => elf::R_LARCH_64, - (RelocationKind::Relative, _, 32) => elf::R_LARCH_32_PCREL, - (RelocationKind::Relative, _, 64) => elf::R_LARCH_64_PCREL, - (RelocationKind::Relative, RelocationEncoding::LoongArchBranch, 16) - | ( - RelocationKind::PltRelative, - RelocationEncoding::LoongArchBranch, - 16, - ) => elf::R_LARCH_B16, - (RelocationKind::Relative, RelocationEncoding::LoongArchBranch, 21) - | ( - RelocationKind::PltRelative, - RelocationEncoding::LoongArchBranch, - 21, - ) => elf::R_LARCH_B21, - (RelocationKind::Relative, RelocationEncoding::LoongArchBranch, 26) - | ( - RelocationKind::PltRelative, - RelocationEncoding::LoongArchBranch, - 26, - ) => elf::R_LARCH_B26, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::Mips | Architecture::Mips64 => { - match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 16) => elf::R_MIPS_16, - (RelocationKind::Absolute, _, 32) => elf::R_MIPS_32, - (RelocationKind::Absolute, _, 64) => elf::R_MIPS_64, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!( - "unimplemented relocation {:?}", - reloc - ))); - } - } - } - Architecture::Msp430 => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 32) => elf::R_MSP430_32, - (RelocationKind::Absolute, _, 16) => elf::R_MSP430_16_BYTE, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::PowerPc => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 32) => elf::R_PPC_ADDR32, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::PowerPc64 => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 32) => elf::R_PPC64_ADDR32, - (RelocationKind::Absolute, _, 64) => elf::R_PPC64_ADDR64, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::Riscv32 | Architecture::Riscv64 => { - match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 32) => elf::R_RISCV_32, - (RelocationKind::Absolute, _, 64) => elf::R_RISCV_64, - (RelocationKind::Relative, RelocationEncoding::Generic, 32) => { - elf::R_RISCV_32_PCREL - } - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!( - "unimplemented relocation {:?}", - reloc - ))); - } - } - } - Architecture::S390x => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, RelocationEncoding::Generic, 8) => { - elf::R_390_8 - } - (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => { - elf::R_390_16 - } - (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => { - elf::R_390_32 - } - (RelocationKind::Absolute, RelocationEncoding::Generic, 64) => { - elf::R_390_64 - } - (RelocationKind::Relative, RelocationEncoding::Generic, 16) => { - elf::R_390_PC16 - } - (RelocationKind::Relative, RelocationEncoding::Generic, 32) => { - elf::R_390_PC32 - } - (RelocationKind::Relative, RelocationEncoding::Generic, 64) => { - elf::R_390_PC64 - } - (RelocationKind::Relative, RelocationEncoding::S390xDbl, 16) => { - elf::R_390_PC16DBL - } - (RelocationKind::Relative, RelocationEncoding::S390xDbl, 32) => { - elf::R_390_PC32DBL - } - (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 16) => { - elf::R_390_PLT16DBL - } - (RelocationKind::PltRelative, RelocationEncoding::S390xDbl, 32) => { - elf::R_390_PLT32DBL - } - (RelocationKind::Got, RelocationEncoding::Generic, 16) => { - elf::R_390_GOT16 - } - (RelocationKind::Got, RelocationEncoding::Generic, 32) => { - elf::R_390_GOT32 - } - (RelocationKind::Got, RelocationEncoding::Generic, 64) => { - elf::R_390_GOT64 - } - (RelocationKind::GotRelative, RelocationEncoding::S390xDbl, 32) => { - elf::R_390_GOTENT - } - (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 16) => { - elf::R_390_GOTOFF16 - } - (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 32) => { - elf::R_390_GOTOFF32 - } - (RelocationKind::GotBaseOffset, RelocationEncoding::Generic, 64) => { - elf::R_390_GOTOFF64 - } - (RelocationKind::GotBaseRelative, RelocationEncoding::Generic, 64) => { - elf::R_390_GOTPC - } - (RelocationKind::GotBaseRelative, RelocationEncoding::S390xDbl, 32) => { - elf::R_390_GOTPCDBL - } - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::Sbf => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 64) => elf::R_SBF_64_64, - (RelocationKind::Absolute, _, 32) => elf::R_SBF_64_32, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::Sharc => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, RelocationEncoding::SharcTypeA, 32) => { - elf::R_SHARC_ADDR32_V3 - } - (RelocationKind::Absolute, RelocationEncoding::Generic, 32) => { - elf::R_SHARC_ADDR_VAR_V3 - } - (RelocationKind::Relative, RelocationEncoding::SharcTypeA, 24) => { - elf::R_SHARC_PCRLONG_V3 - } - (RelocationKind::Relative, RelocationEncoding::SharcTypeA, 6) => { - elf::R_SHARC_PCRSHORT_V3 - } - (RelocationKind::Relative, RelocationEncoding::SharcTypeB, 6) => { - elf::R_SHARC_PCRSHORT_V3 - } - (RelocationKind::Absolute, RelocationEncoding::Generic, 16) => { - elf::R_SHARC_ADDR_VAR16_V3 - } - (RelocationKind::Absolute, RelocationEncoding::SharcTypeA, 16) => { - elf::R_SHARC_DATA16_V3 - } - (RelocationKind::Absolute, RelocationEncoding::SharcTypeB, 16) => { - elf::R_SHARC_DATA16_VISA_V3 - } - (RelocationKind::Absolute, RelocationEncoding::SharcTypeA, 24) => { - elf::R_SHARC_ADDR24_V3 - } - (RelocationKind::Absolute, RelocationEncoding::SharcTypeA, 6) => { - elf::R_SHARC_DATA6_V3 - } - (RelocationKind::Absolute, RelocationEncoding::SharcTypeB, 6) => { - elf::R_SHARC_DATA6_VISA_V3 - } - (RelocationKind::Absolute, RelocationEncoding::SharcTypeB, 7) => { - elf::R_SHARC_DATA7_VISA_V3 - } - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::Sparc64 => match (reloc.kind, reloc.encoding, reloc.size) { - // TODO: use R_SPARC_32/R_SPARC_64 if aligned. - (RelocationKind::Absolute, _, 32) => elf::R_SPARC_UA32, - (RelocationKind::Absolute, _, 64) => elf::R_SPARC_UA64, - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::Xtensa => match (reloc.kind, reloc.encoding, reloc.size) { - (RelocationKind::Absolute, _, 32) => elf::R_XTENSA_32, - (RelocationKind::Relative, RelocationEncoding::Generic, 32) => { - elf::R_XTENSA_32_PCREL - } - (RelocationKind::Elf(x), _, _) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - _ => { - if let RelocationKind::Elf(x) = reloc.kind { - x - } else { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - } - }; - let r_sym = symbol_offsets[reloc.symbol.0].index.0; - writer.write_relocation( - is_rela, - &Rel { - r_offset: reloc.offset, - r_sym, - r_type, - r_addend: reloc.addend, - }, - ); - } - } - } - - writer.write_shstrtab(); - - // Write section headers. - writer.write_null_section_header(); - - let symtab_index = writer.symtab_index(); - for (comdat, comdat_offset) in self.comdats.iter().zip(comdat_offsets.iter()) { - writer.write_comdat_section_header( - comdat_offset.str_id, - symtab_index, - symbol_offsets[comdat.symbol.0].index, - comdat_offset.offset, - comdat.sections.len(), - ); - } - for (index, section) in self.sections.iter().enumerate() { - let sh_type = match section.kind { - SectionKind::UninitializedData | SectionKind::UninitializedTls => elf::SHT_NOBITS, - SectionKind::Note => elf::SHT_NOTE, - SectionKind::Elf(sh_type) => sh_type, - _ => elf::SHT_PROGBITS, - }; - let sh_flags = if let SectionFlags::Elf { sh_flags } = section.flags { - sh_flags - } else { - match section.kind { - SectionKind::Text => elf::SHF_ALLOC | elf::SHF_EXECINSTR, - SectionKind::Data | SectionKind::ReadOnlyDataWithRel => { - elf::SHF_ALLOC | elf::SHF_WRITE - } - SectionKind::Tls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS, - SectionKind::UninitializedData => elf::SHF_ALLOC | elf::SHF_WRITE, - SectionKind::UninitializedTls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS, - SectionKind::ReadOnlyData => elf::SHF_ALLOC, - SectionKind::ReadOnlyString => { - elf::SHF_ALLOC | elf::SHF_STRINGS | elf::SHF_MERGE - } - SectionKind::OtherString => elf::SHF_STRINGS | elf::SHF_MERGE, - SectionKind::Other - | SectionKind::Debug - | SectionKind::Metadata - | SectionKind::Linker - | SectionKind::Note - | SectionKind::Elf(_) => 0, - SectionKind::Unknown | SectionKind::Common | SectionKind::TlsVariables => { - return Err(Error(format!( - "unimplemented section `{}` kind {:?}", - section.name().unwrap_or(""), - section.kind - ))); - } - } - .into() - }; - // TODO: not sure if this is correct, maybe user should determine this - let sh_entsize = match section.kind { - SectionKind::ReadOnlyString | SectionKind::OtherString => 1, - _ => 0, - }; - writer.write_section_header(&SectionHeader { - name: Some(section_offsets[index].str_id), - sh_type, - sh_flags, - sh_addr: 0, - sh_offset: section_offsets[index].offset as u64, - sh_size: section.size, - sh_link: 0, - sh_info: 0, - sh_addralign: section.align, - sh_entsize, - }); - - if !section.relocations.is_empty() { - writer.write_relocation_section_header( - section_offsets[index].reloc_str_id.unwrap(), - section_offsets[index].index, - symtab_index, - section_offsets[index].reloc_offset, - section.relocations.len(), - is_rela, - ); - } - } - - writer.write_symtab_section_header(symtab_num_local); - writer.write_symtab_shndx_section_header(); - writer.write_strtab_section_header(); - writer.write_shstrtab_section_header(); - - debug_assert_eq!(writer.reserved_len(), writer.len()); - - Ok(()) - } -} diff --git a/vendor/object/src/write/elf/writer.rs b/vendor/object/src/write/elf/writer.rs deleted file mode 100644 index 9750924..0000000 --- a/vendor/object/src/write/elf/writer.rs +++ /dev/null @@ -1,2143 +0,0 @@ -//! Helper for writing ELF files. -use alloc::string::String; -use alloc::vec::Vec; -use core::mem; - -use crate::elf; -use crate::endian::*; -use crate::pod; -use crate::write::string::{StringId, StringTable}; -use crate::write::util; -use crate::write::{Error, Result, WritableBuffer}; - -/// The index of an ELF section. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SectionIndex(pub u32); - -/// The index of an ELF symbol. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SymbolIndex(pub u32); - -/// A helper for writing ELF 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 tables -/// - 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 string tables before reserving the file range for the string table. Symbol indices -/// must be reserved after reserving the section indices they reference. 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> { - endian: Endianness, - is_64: bool, - is_mips64el: bool, - elf_align: usize, - - buffer: &'a mut dyn WritableBuffer, - len: usize, - - segment_offset: usize, - segment_num: u32, - - section_offset: usize, - section_num: u32, - - shstrtab: StringTable<'a>, - shstrtab_str_id: Option<StringId>, - shstrtab_index: SectionIndex, - shstrtab_offset: usize, - shstrtab_data: Vec<u8>, - - need_strtab: bool, - strtab: StringTable<'a>, - strtab_str_id: Option<StringId>, - strtab_index: SectionIndex, - strtab_offset: usize, - strtab_data: Vec<u8>, - - symtab_str_id: Option<StringId>, - symtab_index: SectionIndex, - symtab_offset: usize, - symtab_num: u32, - - need_symtab_shndx: bool, - symtab_shndx_str_id: Option<StringId>, - symtab_shndx_offset: usize, - symtab_shndx_data: Vec<u8>, - - need_dynstr: bool, - dynstr: StringTable<'a>, - dynstr_str_id: Option<StringId>, - dynstr_index: SectionIndex, - dynstr_offset: usize, - dynstr_data: Vec<u8>, - - dynsym_str_id: Option<StringId>, - dynsym_index: SectionIndex, - dynsym_offset: usize, - dynsym_num: u32, - - dynamic_str_id: Option<StringId>, - dynamic_offset: usize, - dynamic_num: usize, - - hash_str_id: Option<StringId>, - hash_offset: usize, - hash_size: usize, - - gnu_hash_str_id: Option<StringId>, - gnu_hash_offset: usize, - gnu_hash_size: usize, - - gnu_versym_str_id: Option<StringId>, - gnu_versym_offset: usize, - - gnu_verdef_str_id: Option<StringId>, - gnu_verdef_offset: usize, - gnu_verdef_size: usize, - gnu_verdef_count: u16, - gnu_verdef_remaining: u16, - gnu_verdaux_remaining: u16, - - gnu_verneed_str_id: Option<StringId>, - gnu_verneed_offset: usize, - gnu_verneed_size: usize, - gnu_verneed_count: u16, - gnu_verneed_remaining: u16, - gnu_vernaux_remaining: u16, - - gnu_attributes_str_id: Option<StringId>, - gnu_attributes_offset: usize, - gnu_attributes_size: usize, -} - -impl<'a> Writer<'a> { - /// Create a new `Writer` for the given endianness and ELF class. - pub fn new(endian: Endianness, is_64: bool, buffer: &'a mut dyn WritableBuffer) -> Self { - let elf_align = if is_64 { 8 } else { 4 }; - Writer { - endian, - is_64, - // Determined later. - is_mips64el: false, - elf_align, - - buffer, - len: 0, - - segment_offset: 0, - segment_num: 0, - - section_offset: 0, - section_num: 0, - - shstrtab: StringTable::default(), - shstrtab_str_id: None, - shstrtab_index: SectionIndex(0), - shstrtab_offset: 0, - shstrtab_data: Vec::new(), - - need_strtab: false, - strtab: StringTable::default(), - strtab_str_id: None, - strtab_index: SectionIndex(0), - strtab_offset: 0, - strtab_data: Vec::new(), - - symtab_str_id: None, - symtab_index: SectionIndex(0), - symtab_offset: 0, - symtab_num: 0, - - need_symtab_shndx: false, - symtab_shndx_str_id: None, - symtab_shndx_offset: 0, - symtab_shndx_data: Vec::new(), - - need_dynstr: false, - dynstr: StringTable::default(), - dynstr_str_id: None, - dynstr_index: SectionIndex(0), - dynstr_offset: 0, - dynstr_data: Vec::new(), - - dynsym_str_id: None, - dynsym_index: SectionIndex(0), - dynsym_offset: 0, - dynsym_num: 0, - - dynamic_str_id: None, - dynamic_offset: 0, - dynamic_num: 0, - - hash_str_id: None, - hash_offset: 0, - hash_size: 0, - - gnu_hash_str_id: None, - gnu_hash_offset: 0, - gnu_hash_size: 0, - - gnu_versym_str_id: None, - gnu_versym_offset: 0, - - gnu_verdef_str_id: None, - gnu_verdef_offset: 0, - gnu_verdef_size: 0, - gnu_verdef_count: 0, - gnu_verdef_remaining: 0, - gnu_verdaux_remaining: 0, - - gnu_verneed_str_id: None, - gnu_verneed_offset: 0, - gnu_verneed_size: 0, - gnu_verneed_count: 0, - gnu_verneed_remaining: 0, - gnu_vernaux_remaining: 0, - - gnu_attributes_str_id: None, - gnu_attributes_offset: 0, - gnu_attributes_size: 0, - } - } - - /// 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) -> usize { - if align_start > 1 { - self.len = util::align(self.len, align_start); - } - let offset = self.len; - self.len += len; - offset - } - - /// 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. - /// - /// This is typically used to write section 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); - } - - fn file_header_size(&self) -> usize { - if self.is_64 { - mem::size_of::<elf::FileHeader64<Endianness>>() - } else { - mem::size_of::<elf::FileHeader32<Endianness>>() - } - } - - /// 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(self.file_header_size(), 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); - - self.is_mips64el = - self.is_64 && self.endian.is_little_endian() && header.e_machine == elf::EM_MIPS; - - // Start writing. - self.buffer - .reserve(self.len) - .map_err(|_| Error(String::from("Cannot allocate buffer")))?; - - // Write file header. - let e_ident = elf::Ident { - magic: elf::ELFMAG, - class: if self.is_64 { - elf::ELFCLASS64 - } else { - elf::ELFCLASS32 - }, - data: if self.endian.is_little_endian() { - elf::ELFDATA2LSB - } else { - elf::ELFDATA2MSB - }, - version: elf::EV_CURRENT, - os_abi: header.os_abi, - abi_version: header.abi_version, - padding: [0; 7], - }; - - let e_ehsize = self.file_header_size() as u16; - - let e_phoff = self.segment_offset as u64; - let e_phentsize = if self.segment_num == 0 { - 0 - } else { - self.program_header_size() as u16 - }; - // TODO: overflow - let e_phnum = self.segment_num as u16; - - let e_shoff = self.section_offset as u64; - let e_shentsize = if self.section_num == 0 { - 0 - } else { - self.section_header_size() as u16 - }; - let e_shnum = if self.section_num >= elf::SHN_LORESERVE.into() { - 0 - } else { - self.section_num as u16 - }; - let e_shstrndx = if self.shstrtab_index.0 >= elf::SHN_LORESERVE.into() { - elf::SHN_XINDEX - } else { - self.shstrtab_index.0 as u16 - }; - - let endian = self.endian; - if self.is_64 { - let file = elf::FileHeader64 { - e_ident, - e_type: U16::new(endian, header.e_type), - e_machine: U16::new(endian, header.e_machine), - e_version: U32::new(endian, elf::EV_CURRENT.into()), - e_entry: U64::new(endian, header.e_entry), - e_phoff: U64::new(endian, e_phoff), - e_shoff: U64::new(endian, e_shoff), - e_flags: U32::new(endian, header.e_flags), - e_ehsize: U16::new(endian, e_ehsize), - e_phentsize: U16::new(endian, e_phentsize), - e_phnum: U16::new(endian, e_phnum), - e_shentsize: U16::new(endian, e_shentsize), - e_shnum: U16::new(endian, e_shnum), - e_shstrndx: U16::new(endian, e_shstrndx), - }; - self.buffer.write(&file) - } else { - let file = elf::FileHeader32 { - e_ident, - e_type: U16::new(endian, header.e_type), - e_machine: U16::new(endian, header.e_machine), - e_version: U32::new(endian, elf::EV_CURRENT.into()), - e_entry: U32::new(endian, header.e_entry as u32), - e_phoff: U32::new(endian, e_phoff as u32), - e_shoff: U32::new(endian, e_shoff as u32), - e_flags: U32::new(endian, header.e_flags), - e_ehsize: U16::new(endian, e_ehsize), - e_phentsize: U16::new(endian, e_phentsize), - e_phnum: U16::new(endian, e_phnum), - e_shentsize: U16::new(endian, e_shentsize), - e_shnum: U16::new(endian, e_shnum), - e_shstrndx: U16::new(endian, e_shstrndx), - }; - self.buffer.write(&file); - } - - Ok(()) - } - - fn program_header_size(&self) -> usize { - if self.is_64 { - mem::size_of::<elf::ProgramHeader64<Endianness>>() - } else { - mem::size_of::<elf::ProgramHeader32<Endianness>>() - } - } - - /// Reserve the range for the program headers. - pub fn reserve_program_headers(&mut self, num: u32) { - debug_assert_eq!(self.segment_offset, 0); - if num == 0 { - return; - } - self.segment_num = num; - self.segment_offset = - self.reserve(num as usize * self.program_header_size(), self.elf_align); - } - - /// Write alignment padding bytes prior to the program headers. - pub fn write_align_program_headers(&mut self) { - if self.segment_offset == 0 { - return; - } - util::write_align(self.buffer, self.elf_align); - debug_assert_eq!(self.segment_offset, self.buffer.len()); - } - - /// Write a program header. - pub fn write_program_header(&mut self, header: &ProgramHeader) { - let endian = self.endian; - if self.is_64 { - let header = elf::ProgramHeader64 { - p_type: U32::new(endian, header.p_type), - p_flags: U32::new(endian, header.p_flags), - p_offset: U64::new(endian, header.p_offset), - p_vaddr: U64::new(endian, header.p_vaddr), - p_paddr: U64::new(endian, header.p_paddr), - p_filesz: U64::new(endian, header.p_filesz), - p_memsz: U64::new(endian, header.p_memsz), - p_align: U64::new(endian, header.p_align), - }; - self.buffer.write(&header); - } else { - let header = elf::ProgramHeader32 { - p_type: U32::new(endian, header.p_type), - p_offset: U32::new(endian, header.p_offset as u32), - p_vaddr: U32::new(endian, header.p_vaddr as u32), - p_paddr: U32::new(endian, header.p_paddr as u32), - p_filesz: U32::new(endian, header.p_filesz as u32), - p_memsz: U32::new(endian, header.p_memsz as u32), - p_flags: U32::new(endian, header.p_flags), - p_align: U32::new(endian, header.p_align as u32), - }; - self.buffer.write(&header); - } - } - - /// Reserve the section index for the null section header. - /// - /// The null section header is usually automatically reserved, - /// but this can be used to force an empty section table. - /// - /// This must be called before [`Self::reserve_section_headers`]. - pub fn reserve_null_section_index(&mut self) -> SectionIndex { - debug_assert_eq!(self.section_num, 0); - if self.section_num == 0 { - self.section_num = 1; - } - SectionIndex(0) - } - - /// Reserve a section table index. - /// - /// Automatically also reserves the null section header if required. - /// - /// This must be called before [`Self::reserve_section_headers`]. - pub fn reserve_section_index(&mut self) -> SectionIndex { - debug_assert_eq!(self.section_offset, 0); - if self.section_num == 0 { - self.section_num = 1; - } - let index = self.section_num; - self.section_num += 1; - SectionIndex(index) - } - - fn section_header_size(&self) -> usize { - if self.is_64 { - mem::size_of::<elf::SectionHeader64<Endianness>>() - } else { - mem::size_of::<elf::SectionHeader32<Endianness>>() - } - } - - /// Reserve the range for the section headers. - /// - /// This function does nothing if no sections were reserved. - /// This must be called after [`Self::reserve_section_index`] - /// and other functions that reserve section indices. - pub fn reserve_section_headers(&mut self) { - debug_assert_eq!(self.section_offset, 0); - if self.section_num == 0 { - return; - } - self.section_offset = self.reserve( - self.section_num as usize * self.section_header_size(), - self.elf_align, - ); - } - - /// Write the null section header. - /// - /// This must be the first section header that is written. - /// This function does nothing if no sections were reserved. - pub fn write_null_section_header(&mut self) { - if self.section_num == 0 { - return; - } - util::write_align(self.buffer, self.elf_align); - debug_assert_eq!(self.section_offset, self.buffer.len()); - self.write_section_header(&SectionHeader { - name: None, - sh_type: 0, - sh_flags: 0, - sh_addr: 0, - sh_offset: 0, - sh_size: if self.section_num >= elf::SHN_LORESERVE.into() { - self.section_num.into() - } else { - 0 - }, - sh_link: if self.shstrtab_index.0 >= elf::SHN_LORESERVE.into() { - self.shstrtab_index.0 - } else { - 0 - }, - // TODO: e_phnum overflow - sh_info: 0, - sh_addralign: 0, - sh_entsize: 0, - }); - } - - /// Write a section header. - pub fn write_section_header(&mut self, section: &SectionHeader) { - let sh_name = if let Some(name) = section.name { - self.shstrtab.get_offset(name) as u32 - } else { - 0 - }; - let endian = self.endian; - if self.is_64 { - let section = elf::SectionHeader64 { - sh_name: U32::new(endian, sh_name), - sh_type: U32::new(endian, section.sh_type), - sh_flags: U64::new(endian, section.sh_flags), - sh_addr: U64::new(endian, section.sh_addr), - sh_offset: U64::new(endian, section.sh_offset), - sh_size: U64::new(endian, section.sh_size), - sh_link: U32::new(endian, section.sh_link), - sh_info: U32::new(endian, section.sh_info), - sh_addralign: U64::new(endian, section.sh_addralign), - sh_entsize: U64::new(endian, section.sh_entsize), - }; - self.buffer.write(§ion); - } else { - let section = elf::SectionHeader32 { - sh_name: U32::new(endian, sh_name), - sh_type: U32::new(endian, section.sh_type), - sh_flags: U32::new(endian, section.sh_flags as u32), - sh_addr: U32::new(endian, section.sh_addr as u32), - sh_offset: U32::new(endian, section.sh_offset as u32), - sh_size: U32::new(endian, section.sh_size as u32), - sh_link: U32::new(endian, section.sh_link), - sh_info: U32::new(endian, section.sh_info), - sh_addralign: U32::new(endian, section.sh_addralign as u32), - sh_entsize: U32::new(endian, section.sh_entsize as u32), - }; - self.buffer.write(§ion); - } - } - - /// Add a section name to the section header string table. - /// - /// This will be stored in the `.shstrtab` section. - /// - /// This must be called before [`Self::reserve_shstrtab`]. - pub fn add_section_name(&mut self, name: &'a [u8]) -> StringId { - debug_assert_eq!(self.shstrtab_offset, 0); - self.shstrtab.add(name) - } - - /// Reserve the range for the section header string table. - /// - /// This range is used for a section named `.shstrtab`. - /// - /// This function does nothing if no sections were reserved. - /// This must be called after [`Self::add_section_name`]. - /// and other functions that reserve section names and indices. - pub fn reserve_shstrtab(&mut self) { - debug_assert_eq!(self.shstrtab_offset, 0); - if self.section_num == 0 { - return; - } - // Start with null section name. - self.shstrtab_data = vec![0]; - self.shstrtab.write(1, &mut self.shstrtab_data); - self.shstrtab_offset = self.reserve(self.shstrtab_data.len(), 1); - } - - /// Write the section header string table. - /// - /// This function does nothing if the section was not reserved. - pub fn write_shstrtab(&mut self) { - if self.shstrtab_offset == 0 { - return; - } - debug_assert_eq!(self.shstrtab_offset, self.buffer.len()); - self.buffer.write_bytes(&self.shstrtab_data); - } - - /// Reserve the section index for the section header string table. - /// - /// This must be called before [`Self::reserve_shstrtab`] - /// and [`Self::reserve_section_headers`]. - pub fn reserve_shstrtab_section_index(&mut self) -> SectionIndex { - debug_assert_eq!(self.shstrtab_index, SectionIndex(0)); - self.shstrtab_str_id = Some(self.add_section_name(&b".shstrtab"[..])); - self.shstrtab_index = self.reserve_section_index(); - self.shstrtab_index - } - - /// Write the section header for the section header string table. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_shstrtab_section_header(&mut self) { - if self.shstrtab_index == SectionIndex(0) { - return; - } - self.write_section_header(&SectionHeader { - name: self.shstrtab_str_id, - sh_type: elf::SHT_STRTAB, - sh_flags: 0, - sh_addr: 0, - sh_offset: self.shstrtab_offset as u64, - sh_size: self.shstrtab_data.len() as u64, - sh_link: 0, - sh_info: 0, - sh_addralign: 1, - sh_entsize: 0, - }); - } - - /// Add a string to the string table. - /// - /// This will be stored in the `.strtab` section. - /// - /// This must be called before [`Self::reserve_strtab`]. - pub fn add_string(&mut self, name: &'a [u8]) -> StringId { - debug_assert_eq!(self.strtab_offset, 0); - self.need_strtab = true; - self.strtab.add(name) - } - - /// Return true if `.strtab` is needed. - pub fn strtab_needed(&self) -> bool { - self.need_strtab - } - - /// Reserve the range for the string table. - /// - /// This range is used for a section named `.strtab`. - /// - /// This function does nothing if no strings or symbols were defined. - /// This must be called after [`Self::add_string`]. - pub fn reserve_strtab(&mut self) { - debug_assert_eq!(self.strtab_offset, 0); - if !self.need_strtab { - return; - } - // Start with null string. - self.strtab_data = vec![0]; - self.strtab.write(1, &mut self.strtab_data); - self.strtab_offset = self.reserve(self.strtab_data.len(), 1); - } - - /// Write the string table. - /// - /// This function does nothing if the section was not reserved. - pub fn write_strtab(&mut self) { - if self.strtab_offset == 0 { - return; - } - debug_assert_eq!(self.strtab_offset, self.buffer.len()); - self.buffer.write_bytes(&self.strtab_data); - } - - /// Reserve the section index for the string table. - /// - /// This must be called before [`Self::reserve_section_headers`]. - pub fn reserve_strtab_section_index(&mut self) -> SectionIndex { - debug_assert_eq!(self.strtab_index, SectionIndex(0)); - self.strtab_str_id = Some(self.add_section_name(&b".strtab"[..])); - self.strtab_index = self.reserve_section_index(); - self.strtab_index - } - - /// Write the section header for the string table. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_strtab_section_header(&mut self) { - if self.strtab_index == SectionIndex(0) { - return; - } - self.write_section_header(&SectionHeader { - name: self.strtab_str_id, - sh_type: elf::SHT_STRTAB, - sh_flags: 0, - sh_addr: 0, - sh_offset: self.strtab_offset as u64, - sh_size: self.strtab_data.len() as u64, - sh_link: 0, - sh_info: 0, - sh_addralign: 1, - sh_entsize: 0, - }); - } - - /// Reserve the null symbol table entry. - /// - /// This will be stored in the `.symtab` section. - /// - /// The null symbol table entry is usually automatically reserved, - /// but this can be used to force an empty symbol table. - /// - /// This must be called before [`Self::reserve_symtab`]. - pub fn reserve_null_symbol_index(&mut self) -> SymbolIndex { - debug_assert_eq!(self.symtab_offset, 0); - debug_assert_eq!(self.symtab_num, 0); - self.symtab_num = 1; - // The symtab must link to a strtab. - self.need_strtab = true; - SymbolIndex(0) - } - - /// Reserve a symbol table entry. - /// - /// This will be stored in the `.symtab` section. - /// - /// `section_index` is used to determine whether `.symtab_shndx` is required. - /// - /// Automatically also reserves the null symbol if required. - /// Callers may assume that the returned indices will be sequential - /// starting at 1. - /// - /// This must be called before [`Self::reserve_symtab`] and - /// [`Self::reserve_symtab_shndx`]. - pub fn reserve_symbol_index(&mut self, section_index: Option<SectionIndex>) -> SymbolIndex { - debug_assert_eq!(self.symtab_offset, 0); - debug_assert_eq!(self.symtab_shndx_offset, 0); - if self.symtab_num == 0 { - self.symtab_num = 1; - // The symtab must link to a strtab. - self.need_strtab = true; - } - let index = self.symtab_num; - self.symtab_num += 1; - if let Some(section_index) = section_index { - if section_index.0 >= elf::SHN_LORESERVE.into() { - self.need_symtab_shndx = true; - } - } - SymbolIndex(index) - } - - /// Return the number of reserved symbol table entries. - /// - /// Includes the null symbol. - pub fn symbol_count(&self) -> u32 { - self.symtab_num - } - - fn symbol_size(&self) -> usize { - if self.is_64 { - mem::size_of::<elf::Sym64<Endianness>>() - } else { - mem::size_of::<elf::Sym32<Endianness>>() - } - } - - /// Reserve the range for the symbol table. - /// - /// This range is used for a section named `.symtab`. - /// This function does nothing if no symbols were reserved. - /// This must be called after [`Self::reserve_symbol_index`]. - pub fn reserve_symtab(&mut self) { - debug_assert_eq!(self.symtab_offset, 0); - if self.symtab_num == 0 { - return; - } - self.symtab_offset = self.reserve( - self.symtab_num as usize * self.symbol_size(), - self.elf_align, - ); - } - - /// Write the null symbol. - /// - /// This must be the first symbol that is written. - /// This function does nothing if no symbols were reserved. - pub fn write_null_symbol(&mut self) { - if self.symtab_num == 0 { - return; - } - util::write_align(self.buffer, self.elf_align); - debug_assert_eq!(self.symtab_offset, self.buffer.len()); - if self.is_64 { - self.buffer.write(&elf::Sym64::<Endianness>::default()); - } else { - self.buffer.write(&elf::Sym32::<Endianness>::default()); - } - - if self.need_symtab_shndx { - self.symtab_shndx_data.write_pod(&U32::new(self.endian, 0)); - } - } - - /// Write a symbol. - pub fn write_symbol(&mut self, sym: &Sym) { - let st_name = if let Some(name) = sym.name { - self.strtab.get_offset(name) as u32 - } else { - 0 - }; - let st_shndx = if let Some(section) = sym.section { - if section.0 >= elf::SHN_LORESERVE as u32 { - elf::SHN_XINDEX - } else { - section.0 as u16 - } - } else { - sym.st_shndx - }; - - let endian = self.endian; - if self.is_64 { - let sym = elf::Sym64 { - st_name: U32::new(endian, st_name), - st_info: sym.st_info, - st_other: sym.st_other, - st_shndx: U16::new(endian, st_shndx), - st_value: U64::new(endian, sym.st_value), - st_size: U64::new(endian, sym.st_size), - }; - self.buffer.write(&sym); - } else { - let sym = elf::Sym32 { - st_name: U32::new(endian, st_name), - st_info: sym.st_info, - st_other: sym.st_other, - st_shndx: U16::new(endian, st_shndx), - st_value: U32::new(endian, sym.st_value as u32), - st_size: U32::new(endian, sym.st_size as u32), - }; - self.buffer.write(&sym); - } - - if self.need_symtab_shndx { - let section_index = sym.section.unwrap_or(SectionIndex(0)); - self.symtab_shndx_data - .write_pod(&U32::new(self.endian, section_index.0)); - } - } - - /// Reserve the section index for the symbol table. - /// - /// This must be called before [`Self::reserve_section_headers`]. - pub fn reserve_symtab_section_index(&mut self) -> SectionIndex { - debug_assert_eq!(self.symtab_index, SectionIndex(0)); - self.symtab_str_id = Some(self.add_section_name(&b".symtab"[..])); - self.symtab_index = self.reserve_section_index(); - self.symtab_index - } - - /// Return the section index of the symbol table. - pub fn symtab_index(&mut self) -> SectionIndex { - self.symtab_index - } - - /// Write the section header for the symbol table. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_symtab_section_header(&mut self, num_local: u32) { - if self.symtab_index == SectionIndex(0) { - return; - } - self.write_section_header(&SectionHeader { - name: self.symtab_str_id, - sh_type: elf::SHT_SYMTAB, - sh_flags: 0, - sh_addr: 0, - sh_offset: self.symtab_offset as u64, - sh_size: self.symtab_num as u64 * self.symbol_size() as u64, - sh_link: self.strtab_index.0, - sh_info: num_local, - sh_addralign: self.elf_align as u64, - sh_entsize: self.symbol_size() as u64, - }); - } - - /// Return true if `.symtab_shndx` is needed. - pub fn symtab_shndx_needed(&self) -> bool { - self.need_symtab_shndx - } - - /// Reserve the range for the extended section indices for the symbol table. - /// - /// This range is used for a section named `.symtab_shndx`. - /// This also reserves a section index. - /// - /// This function does nothing if extended section indices are not needed. - /// This must be called after [`Self::reserve_symbol_index`]. - pub fn reserve_symtab_shndx(&mut self) { - debug_assert_eq!(self.symtab_shndx_offset, 0); - if !self.need_symtab_shndx { - return; - } - self.symtab_shndx_offset = self.reserve(self.symtab_num as usize * 4, 4); - self.symtab_shndx_data.reserve(self.symtab_num as usize * 4); - } - - /// Write the extended section indices for the symbol table. - /// - /// This function does nothing if the section was not reserved. - pub fn write_symtab_shndx(&mut self) { - if self.symtab_shndx_offset == 0 { - return; - } - debug_assert_eq!(self.symtab_shndx_offset, self.buffer.len()); - debug_assert_eq!(self.symtab_num as usize * 4, self.symtab_shndx_data.len()); - self.buffer.write_bytes(&self.symtab_shndx_data); - } - - /// Reserve the section index for the extended section indices symbol table. - /// - /// You should check [`Self::symtab_shndx_needed`] before calling this - /// unless you have other means of knowing if this section is needed. - /// - /// This must be called before [`Self::reserve_section_headers`]. - pub fn reserve_symtab_shndx_section_index(&mut self) -> SectionIndex { - debug_assert!(self.symtab_shndx_str_id.is_none()); - self.symtab_shndx_str_id = Some(self.add_section_name(&b".symtab_shndx"[..])); - self.reserve_section_index() - } - - /// Write the section header for the extended section indices for the symbol table. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_symtab_shndx_section_header(&mut self) { - if self.symtab_shndx_str_id.is_none() { - return; - } - let sh_size = if self.symtab_shndx_offset == 0 { - 0 - } else { - (self.symtab_num * 4) as u64 - }; - self.write_section_header(&SectionHeader { - name: self.symtab_shndx_str_id, - sh_type: elf::SHT_SYMTAB_SHNDX, - sh_flags: 0, - sh_addr: 0, - sh_offset: self.symtab_shndx_offset as u64, - sh_size, - sh_link: self.symtab_index.0, - sh_info: 0, - sh_addralign: 4, - sh_entsize: 4, - }); - } - - /// Add a string to the dynamic string table. - /// - /// This will be stored in the `.dynstr` section. - /// - /// This must be called before [`Self::reserve_dynstr`]. - pub fn add_dynamic_string(&mut self, name: &'a [u8]) -> StringId { - debug_assert_eq!(self.dynstr_offset, 0); - self.need_dynstr = true; - self.dynstr.add(name) - } - - /// Get a string that was previously added to the dynamic string table. - /// - /// Panics if the string was not added. - pub fn get_dynamic_string(&self, name: &'a [u8]) -> StringId { - self.dynstr.get_id(name) - } - - /// Return true if `.dynstr` is needed. - pub fn dynstr_needed(&self) -> bool { - self.need_dynstr - } - - /// Reserve the range for the dynamic string table. - /// - /// This range is used for a section named `.dynstr`. - /// - /// This function does nothing if no dynamic strings or symbols were defined. - /// This must be called after [`Self::add_dynamic_string`]. - pub fn reserve_dynstr(&mut self) { - debug_assert_eq!(self.dynstr_offset, 0); - if !self.need_dynstr { - return; - } - // Start with null string. - self.dynstr_data = vec![0]; - self.dynstr.write(1, &mut self.dynstr_data); - self.dynstr_offset = self.reserve(self.dynstr_data.len(), 1); - } - - /// Write the dynamic string table. - /// - /// This function does nothing if the section was not reserved. - pub fn write_dynstr(&mut self) { - if self.dynstr_offset == 0 { - return; - } - debug_assert_eq!(self.dynstr_offset, self.buffer.len()); - self.buffer.write_bytes(&self.dynstr_data); - } - - /// Reserve the section index for the dynamic string table. - /// - /// This must be called before [`Self::reserve_section_headers`]. - pub fn reserve_dynstr_section_index(&mut self) -> SectionIndex { - debug_assert_eq!(self.dynstr_index, SectionIndex(0)); - self.dynstr_str_id = Some(self.add_section_name(&b".dynstr"[..])); - self.dynstr_index = self.reserve_section_index(); - self.dynstr_index - } - - /// Return the section index of the dynamic string table. - pub fn dynstr_index(&mut self) -> SectionIndex { - self.dynstr_index - } - - /// Write the section header for the dynamic string table. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_dynstr_section_header(&mut self, sh_addr: u64) { - if self.dynstr_index == SectionIndex(0) { - return; - } - self.write_section_header(&SectionHeader { - name: self.dynstr_str_id, - sh_type: elf::SHT_STRTAB, - sh_flags: elf::SHF_ALLOC.into(), - sh_addr, - sh_offset: self.dynstr_offset as u64, - sh_size: self.dynstr_data.len() as u64, - sh_link: 0, - sh_info: 0, - sh_addralign: 1, - sh_entsize: 0, - }); - } - - /// Reserve the null dynamic symbol table entry. - /// - /// This will be stored in the `.dynsym` section. - /// - /// The null dynamic symbol table entry is usually automatically reserved, - /// but this can be used to force an empty dynamic symbol table. - /// - /// This must be called before [`Self::reserve_dynsym`]. - pub fn reserve_null_dynamic_symbol_index(&mut self) -> SymbolIndex { - debug_assert_eq!(self.dynsym_offset, 0); - debug_assert_eq!(self.dynsym_num, 0); - self.dynsym_num = 1; - // The symtab must link to a strtab. - self.need_dynstr = true; - SymbolIndex(0) - } - - /// Reserve a dynamic symbol table entry. - /// - /// This will be stored in the `.dynsym` section. - /// - /// Automatically also reserves the null symbol if required. - /// Callers may assume that the returned indices will be sequential - /// starting at 1. - /// - /// This must be called before [`Self::reserve_dynsym`]. - pub fn reserve_dynamic_symbol_index(&mut self) -> SymbolIndex { - debug_assert_eq!(self.dynsym_offset, 0); - if self.dynsym_num == 0 { - self.dynsym_num = 1; - // The symtab must link to a strtab. - self.need_dynstr = true; - } - let index = self.dynsym_num; - self.dynsym_num += 1; - SymbolIndex(index) - } - - /// Return the number of reserved dynamic symbols. - /// - /// Includes the null symbol. - pub fn dynamic_symbol_count(&mut self) -> u32 { - self.dynsym_num - } - - /// Reserve the range for the dynamic symbol table. - /// - /// This range is used for a section named `.dynsym`. - /// - /// This function does nothing if no dynamic symbols were reserved. - /// This must be called after [`Self::reserve_dynamic_symbol_index`]. - pub fn reserve_dynsym(&mut self) { - debug_assert_eq!(self.dynsym_offset, 0); - if self.dynsym_num == 0 { - return; - } - self.dynsym_offset = self.reserve( - self.dynsym_num as usize * self.symbol_size(), - self.elf_align, - ); - } - - /// Write the null dynamic symbol. - /// - /// This must be the first dynamic symbol that is written. - /// This function does nothing if no dynamic symbols were reserved. - pub fn write_null_dynamic_symbol(&mut self) { - if self.dynsym_num == 0 { - return; - } - util::write_align(self.buffer, self.elf_align); - debug_assert_eq!(self.dynsym_offset, self.buffer.len()); - if self.is_64 { - self.buffer.write(&elf::Sym64::<Endianness>::default()); - } else { - self.buffer.write(&elf::Sym32::<Endianness>::default()); - } - } - - /// Write a dynamic symbol. - pub fn write_dynamic_symbol(&mut self, sym: &Sym) { - let st_name = if let Some(name) = sym.name { - self.dynstr.get_offset(name) as u32 - } else { - 0 - }; - - let st_shndx = if let Some(section) = sym.section { - if section.0 >= elf::SHN_LORESERVE as u32 { - // TODO: we don't actually write out .dynsym_shndx yet. - // This is unlikely to be needed though. - elf::SHN_XINDEX - } else { - section.0 as u16 - } - } else { - sym.st_shndx - }; - - let endian = self.endian; - if self.is_64 { - let sym = elf::Sym64 { - st_name: U32::new(endian, st_name), - st_info: sym.st_info, - st_other: sym.st_other, - st_shndx: U16::new(endian, st_shndx), - st_value: U64::new(endian, sym.st_value), - st_size: U64::new(endian, sym.st_size), - }; - self.buffer.write(&sym); - } else { - let sym = elf::Sym32 { - st_name: U32::new(endian, st_name), - st_info: sym.st_info, - st_other: sym.st_other, - st_shndx: U16::new(endian, st_shndx), - st_value: U32::new(endian, sym.st_value as u32), - st_size: U32::new(endian, sym.st_size as u32), - }; - self.buffer.write(&sym); - } - } - - /// Reserve the section index for the dynamic symbol table. - /// - /// This must be called before [`Self::reserve_section_headers`]. - pub fn reserve_dynsym_section_index(&mut self) -> SectionIndex { - debug_assert_eq!(self.dynsym_index, SectionIndex(0)); - self.dynsym_str_id = Some(self.add_section_name(&b".dynsym"[..])); - self.dynsym_index = self.reserve_section_index(); - self.dynsym_index - } - - /// Return the section index of the dynamic symbol table. - pub fn dynsym_index(&mut self) -> SectionIndex { - self.dynsym_index - } - - /// Write the section header for the dynamic symbol table. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_dynsym_section_header(&mut self, sh_addr: u64, num_local: u32) { - if self.dynsym_index == SectionIndex(0) { - return; - } - self.write_section_header(&SectionHeader { - name: self.dynsym_str_id, - sh_type: elf::SHT_DYNSYM, - sh_flags: elf::SHF_ALLOC.into(), - sh_addr, - sh_offset: self.dynsym_offset as u64, - sh_size: self.dynsym_num as u64 * self.symbol_size() as u64, - sh_link: self.dynstr_index.0, - sh_info: num_local, - sh_addralign: self.elf_align as u64, - sh_entsize: self.symbol_size() as u64, - }); - } - - fn dyn_size(&self) -> usize { - if self.is_64 { - mem::size_of::<elf::Dyn64<Endianness>>() - } else { - mem::size_of::<elf::Dyn32<Endianness>>() - } - } - - /// Reserve the range for the `.dynamic` section. - /// - /// This function does nothing if `dynamic_num` is zero. - pub fn reserve_dynamic(&mut self, dynamic_num: usize) { - debug_assert_eq!(self.dynamic_offset, 0); - if dynamic_num == 0 { - return; - } - self.dynamic_num = dynamic_num; - self.dynamic_offset = self.reserve(dynamic_num * self.dyn_size(), self.elf_align); - } - - /// Write alignment padding bytes prior to the `.dynamic` section. - /// - /// This function does nothing if the section was not reserved. - pub fn write_align_dynamic(&mut self) { - if self.dynamic_offset == 0 { - return; - } - util::write_align(self.buffer, self.elf_align); - debug_assert_eq!(self.dynamic_offset, self.buffer.len()); - } - - /// Write a dynamic string entry. - pub fn write_dynamic_string(&mut self, tag: u32, id: StringId) { - self.write_dynamic(tag, self.dynstr.get_offset(id) as u64); - } - - /// Write a dynamic value entry. - pub fn write_dynamic(&mut self, d_tag: u32, d_val: u64) { - debug_assert!(self.dynamic_offset <= self.buffer.len()); - let endian = self.endian; - if self.is_64 { - let d = elf::Dyn64 { - d_tag: U64::new(endian, d_tag.into()), - d_val: U64::new(endian, d_val), - }; - self.buffer.write(&d); - } else { - let d = elf::Dyn32 { - d_tag: U32::new(endian, d_tag), - d_val: U32::new(endian, d_val as u32), - }; - self.buffer.write(&d); - } - debug_assert!( - self.dynamic_offset + self.dynamic_num * self.dyn_size() >= self.buffer.len() - ); - } - - /// Reserve the section index for the dynamic table. - pub fn reserve_dynamic_section_index(&mut self) -> SectionIndex { - debug_assert!(self.dynamic_str_id.is_none()); - self.dynamic_str_id = Some(self.add_section_name(&b".dynamic"[..])); - self.reserve_section_index() - } - - /// Write the section header for the dynamic table. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_dynamic_section_header(&mut self, sh_addr: u64) { - if self.dynamic_str_id.is_none() { - return; - } - self.write_section_header(&SectionHeader { - name: self.dynamic_str_id, - sh_type: elf::SHT_DYNAMIC, - sh_flags: (elf::SHF_WRITE | elf::SHF_ALLOC).into(), - sh_addr, - sh_offset: self.dynamic_offset as u64, - sh_size: (self.dynamic_num * self.dyn_size()) as u64, - sh_link: self.dynstr_index.0, - sh_info: 0, - sh_addralign: self.elf_align as u64, - sh_entsize: self.dyn_size() as u64, - }); - } - - fn rel_size(&self, is_rela: bool) -> usize { - if self.is_64 { - if is_rela { - mem::size_of::<elf::Rela64<Endianness>>() - } else { - mem::size_of::<elf::Rel64<Endianness>>() - } - } else { - if is_rela { - mem::size_of::<elf::Rela32<Endianness>>() - } else { - mem::size_of::<elf::Rel32<Endianness>>() - } - } - } - - /// Reserve a file range for a SysV hash section. - /// - /// `symbol_count` is the number of symbols in the hash, - /// not the total number of symbols. - pub fn reserve_hash(&mut self, bucket_count: u32, chain_count: u32) { - self.hash_size = mem::size_of::<elf::HashHeader<Endianness>>() - + bucket_count as usize * 4 - + chain_count as usize * 4; - self.hash_offset = self.reserve(self.hash_size, self.elf_align); - } - - /// Write a SysV hash section. - /// - /// `chain_count` is the number of symbols in the hash. - /// The argument to `hash` will be in the range `0..chain_count`. - pub fn write_hash<F>(&mut self, bucket_count: u32, chain_count: u32, hash: F) - where - F: Fn(u32) -> Option<u32>, - { - let mut buckets = vec![U32::new(self.endian, 0); bucket_count as usize]; - let mut chains = vec![U32::new(self.endian, 0); chain_count as usize]; - for i in 0..chain_count { - if let Some(hash) = hash(i) { - let bucket = hash % bucket_count; - chains[i as usize] = buckets[bucket as usize]; - buckets[bucket as usize] = U32::new(self.endian, i); - } - } - - util::write_align(self.buffer, self.elf_align); - debug_assert_eq!(self.hash_offset, self.buffer.len()); - self.buffer.write(&elf::HashHeader { - bucket_count: U32::new(self.endian, bucket_count), - chain_count: U32::new(self.endian, chain_count), - }); - self.buffer.write_slice(&buckets); - self.buffer.write_slice(&chains); - } - - /// Reserve the section index for the SysV hash table. - pub fn reserve_hash_section_index(&mut self) -> SectionIndex { - debug_assert!(self.hash_str_id.is_none()); - self.hash_str_id = Some(self.add_section_name(&b".hash"[..])); - self.reserve_section_index() - } - - /// Write the section header for the SysV hash table. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_hash_section_header(&mut self, sh_addr: u64) { - if self.hash_str_id.is_none() { - return; - } - self.write_section_header(&SectionHeader { - name: self.hash_str_id, - sh_type: elf::SHT_HASH, - sh_flags: elf::SHF_ALLOC.into(), - sh_addr, - sh_offset: self.hash_offset as u64, - sh_size: self.hash_size as u64, - sh_link: self.dynsym_index.0, - sh_info: 0, - sh_addralign: self.elf_align as u64, - sh_entsize: 4, - }); - } - - /// Reserve a file range for a GNU hash section. - /// - /// `symbol_count` is the number of symbols in the hash, - /// not the total number of symbols. - pub fn reserve_gnu_hash(&mut self, bloom_count: u32, bucket_count: u32, symbol_count: u32) { - self.gnu_hash_size = mem::size_of::<elf::GnuHashHeader<Endianness>>() - + bloom_count as usize * self.elf_align - + bucket_count as usize * 4 - + symbol_count as usize * 4; - self.gnu_hash_offset = self.reserve(self.gnu_hash_size, self.elf_align); - } - - /// Write a GNU hash section. - /// - /// `symbol_count` is the number of symbols in the hash. - /// The argument to `hash` will be in the range `0..symbol_count`. - /// - /// This requires that symbols are already sorted by bucket. - pub fn write_gnu_hash<F>( - &mut self, - symbol_base: u32, - bloom_shift: u32, - bloom_count: u32, - bucket_count: u32, - symbol_count: u32, - hash: F, - ) where - F: Fn(u32) -> u32, - { - util::write_align(self.buffer, self.elf_align); - debug_assert_eq!(self.gnu_hash_offset, self.buffer.len()); - self.buffer.write(&elf::GnuHashHeader { - bucket_count: U32::new(self.endian, bucket_count), - symbol_base: U32::new(self.endian, symbol_base), - bloom_count: U32::new(self.endian, bloom_count), - bloom_shift: U32::new(self.endian, bloom_shift), - }); - - // Calculate and write bloom filter. - if self.is_64 { - let mut bloom_filters = vec![0; bloom_count as usize]; - for i in 0..symbol_count { - let h = hash(i); - bloom_filters[((h / 64) & (bloom_count - 1)) as usize] |= - 1 << (h % 64) | 1 << ((h >> bloom_shift) % 64); - } - for bloom_filter in bloom_filters { - self.buffer.write(&U64::new(self.endian, bloom_filter)); - } - } else { - let mut bloom_filters = vec![0; bloom_count as usize]; - for i in 0..symbol_count { - let h = hash(i); - bloom_filters[((h / 32) & (bloom_count - 1)) as usize] |= - 1 << (h % 32) | 1 << ((h >> bloom_shift) % 32); - } - for bloom_filter in bloom_filters { - self.buffer.write(&U32::new(self.endian, bloom_filter)); - } - } - - // Write buckets. - // - // This requires that symbols are already sorted by bucket. - let mut bucket = 0; - for i in 0..symbol_count { - let symbol_bucket = hash(i) % bucket_count; - while bucket < symbol_bucket { - self.buffer.write(&U32::new(self.endian, 0)); - bucket += 1; - } - if bucket == symbol_bucket { - self.buffer.write(&U32::new(self.endian, symbol_base + i)); - bucket += 1; - } - } - while bucket < bucket_count { - self.buffer.write(&U32::new(self.endian, 0)); - bucket += 1; - } - - // Write hash values. - for i in 0..symbol_count { - let mut h = hash(i); - if i == symbol_count - 1 || h % bucket_count != hash(i + 1) % bucket_count { - h |= 1; - } else { - h &= !1; - } - self.buffer.write(&U32::new(self.endian, h)); - } - } - - /// Reserve the section index for the GNU hash table. - pub fn reserve_gnu_hash_section_index(&mut self) -> SectionIndex { - debug_assert!(self.gnu_hash_str_id.is_none()); - self.gnu_hash_str_id = Some(self.add_section_name(&b".gnu.hash"[..])); - self.reserve_section_index() - } - - /// Write the section header for the GNU hash table. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_gnu_hash_section_header(&mut self, sh_addr: u64) { - if self.gnu_hash_str_id.is_none() { - return; - } - self.write_section_header(&SectionHeader { - name: self.gnu_hash_str_id, - sh_type: elf::SHT_GNU_HASH, - sh_flags: elf::SHF_ALLOC.into(), - sh_addr, - sh_offset: self.gnu_hash_offset as u64, - sh_size: self.gnu_hash_size as u64, - sh_link: self.dynsym_index.0, - sh_info: 0, - sh_addralign: self.elf_align as u64, - sh_entsize: 0, - }); - } - - /// Reserve the range for the `.gnu.version` section. - /// - /// This function does nothing if no dynamic symbols were reserved. - pub fn reserve_gnu_versym(&mut self) { - debug_assert_eq!(self.gnu_versym_offset, 0); - if self.dynsym_num == 0 { - return; - } - self.gnu_versym_offset = self.reserve(self.dynsym_num as usize * 2, 2); - } - - /// Write the null symbol version entry. - /// - /// This must be the first symbol version that is written. - /// This function does nothing if no dynamic symbols were reserved. - pub fn write_null_gnu_versym(&mut self) { - if self.dynsym_num == 0 { - return; - } - util::write_align(self.buffer, 2); - debug_assert_eq!(self.gnu_versym_offset, self.buffer.len()); - self.write_gnu_versym(0); - } - - /// Write a symbol version entry. - pub fn write_gnu_versym(&mut self, versym: u16) { - self.buffer.write(&U16::new(self.endian, versym)); - } - - /// Reserve the section index for the `.gnu.version` section. - pub fn reserve_gnu_versym_section_index(&mut self) -> SectionIndex { - debug_assert!(self.gnu_versym_str_id.is_none()); - self.gnu_versym_str_id = Some(self.add_section_name(&b".gnu.version"[..])); - self.reserve_section_index() - } - - /// Write the section header for the `.gnu.version` section. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_gnu_versym_section_header(&mut self, sh_addr: u64) { - if self.gnu_versym_str_id.is_none() { - return; - } - self.write_section_header(&SectionHeader { - name: self.gnu_versym_str_id, - sh_type: elf::SHT_GNU_VERSYM, - sh_flags: elf::SHF_ALLOC.into(), - sh_addr, - sh_offset: self.gnu_versym_offset as u64, - sh_size: self.dynsym_num as u64 * 2, - sh_link: self.dynsym_index.0, - sh_info: 0, - sh_addralign: 2, - sh_entsize: 2, - }); - } - - /// Reserve the range for the `.gnu.version_d` section. - pub fn reserve_gnu_verdef(&mut self, verdef_count: usize, verdaux_count: usize) { - debug_assert_eq!(self.gnu_verdef_offset, 0); - if verdef_count == 0 { - return; - } - self.gnu_verdef_size = verdef_count * mem::size_of::<elf::Verdef<Endianness>>() - + verdaux_count * mem::size_of::<elf::Verdaux<Endianness>>(); - self.gnu_verdef_offset = self.reserve(self.gnu_verdef_size, self.elf_align); - self.gnu_verdef_count = verdef_count as u16; - self.gnu_verdef_remaining = self.gnu_verdef_count; - } - - /// Write alignment padding bytes prior to a `.gnu.version_d` section. - pub fn write_align_gnu_verdef(&mut self) { - if self.gnu_verdef_offset == 0 { - return; - } - util::write_align(self.buffer, self.elf_align); - debug_assert_eq!(self.gnu_verdef_offset, self.buffer.len()); - } - - /// Write a version definition entry. - pub fn write_gnu_verdef(&mut self, verdef: &Verdef) { - debug_assert_ne!(self.gnu_verdef_remaining, 0); - self.gnu_verdef_remaining -= 1; - let vd_next = if self.gnu_verdef_remaining == 0 { - 0 - } else { - mem::size_of::<elf::Verdef<Endianness>>() as u32 - + verdef.aux_count as u32 * mem::size_of::<elf::Verdaux<Endianness>>() as u32 - }; - - self.gnu_verdaux_remaining = verdef.aux_count; - let vd_aux = if verdef.aux_count == 0 { - 0 - } else { - mem::size_of::<elf::Verdef<Endianness>>() as u32 - }; - - self.buffer.write(&elf::Verdef { - vd_version: U16::new(self.endian, verdef.version), - vd_flags: U16::new(self.endian, verdef.flags), - vd_ndx: U16::new(self.endian, verdef.index), - vd_cnt: U16::new(self.endian, verdef.aux_count), - vd_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(verdef.name))), - vd_aux: U32::new(self.endian, vd_aux), - vd_next: U32::new(self.endian, vd_next), - }); - self.write_gnu_verdaux(verdef.name); - } - - /// Write a version definition auxiliary entry. - pub fn write_gnu_verdaux(&mut self, name: StringId) { - debug_assert_ne!(self.gnu_verdaux_remaining, 0); - self.gnu_verdaux_remaining -= 1; - let vda_next = if self.gnu_verdaux_remaining == 0 { - 0 - } else { - mem::size_of::<elf::Verdaux<Endianness>>() as u32 - }; - self.buffer.write(&elf::Verdaux { - vda_name: U32::new(self.endian, self.dynstr.get_offset(name) as u32), - vda_next: U32::new(self.endian, vda_next), - }); - } - - /// Reserve the section index for the `.gnu.version_d` section. - pub fn reserve_gnu_verdef_section_index(&mut self) -> SectionIndex { - debug_assert!(self.gnu_verdef_str_id.is_none()); - self.gnu_verdef_str_id = Some(self.add_section_name(&b".gnu.version_d"[..])); - self.reserve_section_index() - } - - /// Write the section header for the `.gnu.version_d` section. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_gnu_verdef_section_header(&mut self, sh_addr: u64) { - if self.gnu_verdef_str_id.is_none() { - return; - } - self.write_section_header(&SectionHeader { - name: self.gnu_verdef_str_id, - sh_type: elf::SHT_GNU_VERDEF, - sh_flags: elf::SHF_ALLOC.into(), - sh_addr, - sh_offset: self.gnu_verdef_offset as u64, - sh_size: self.gnu_verdef_size as u64, - sh_link: self.dynstr_index.0, - sh_info: self.gnu_verdef_count.into(), - sh_addralign: self.elf_align as u64, - sh_entsize: 0, - }); - } - - /// Reserve the range for the `.gnu.version_r` section. - pub fn reserve_gnu_verneed(&mut self, verneed_count: usize, vernaux_count: usize) { - debug_assert_eq!(self.gnu_verneed_offset, 0); - if verneed_count == 0 { - return; - } - self.gnu_verneed_size = verneed_count * mem::size_of::<elf::Verneed<Endianness>>() - + vernaux_count * mem::size_of::<elf::Vernaux<Endianness>>(); - self.gnu_verneed_offset = self.reserve(self.gnu_verneed_size, self.elf_align); - self.gnu_verneed_count = verneed_count as u16; - self.gnu_verneed_remaining = self.gnu_verneed_count; - } - - /// Write alignment padding bytes prior to a `.gnu.version_r` section. - pub fn write_align_gnu_verneed(&mut self) { - if self.gnu_verneed_offset == 0 { - return; - } - util::write_align(self.buffer, self.elf_align); - debug_assert_eq!(self.gnu_verneed_offset, self.buffer.len()); - } - - /// Write a version need entry. - pub fn write_gnu_verneed(&mut self, verneed: &Verneed) { - debug_assert_ne!(self.gnu_verneed_remaining, 0); - self.gnu_verneed_remaining -= 1; - let vn_next = if self.gnu_verneed_remaining == 0 { - 0 - } else { - mem::size_of::<elf::Verneed<Endianness>>() as u32 - + verneed.aux_count as u32 * mem::size_of::<elf::Vernaux<Endianness>>() as u32 - }; - - self.gnu_vernaux_remaining = verneed.aux_count; - let vn_aux = if verneed.aux_count == 0 { - 0 - } else { - mem::size_of::<elf::Verneed<Endianness>>() as u32 - }; - - self.buffer.write(&elf::Verneed { - vn_version: U16::new(self.endian, verneed.version), - vn_cnt: U16::new(self.endian, verneed.aux_count), - vn_file: U32::new(self.endian, self.dynstr.get_offset(verneed.file) as u32), - vn_aux: U32::new(self.endian, vn_aux), - vn_next: U32::new(self.endian, vn_next), - }); - } - - /// Write a version need auxiliary entry. - pub fn write_gnu_vernaux(&mut self, vernaux: &Vernaux) { - debug_assert_ne!(self.gnu_vernaux_remaining, 0); - self.gnu_vernaux_remaining -= 1; - let vna_next = if self.gnu_vernaux_remaining == 0 { - 0 - } else { - mem::size_of::<elf::Vernaux<Endianness>>() as u32 - }; - self.buffer.write(&elf::Vernaux { - vna_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(vernaux.name))), - vna_flags: U16::new(self.endian, vernaux.flags), - vna_other: U16::new(self.endian, vernaux.index), - vna_name: U32::new(self.endian, self.dynstr.get_offset(vernaux.name) as u32), - vna_next: U32::new(self.endian, vna_next), - }); - } - - /// Reserve the section index for the `.gnu.version_r` section. - pub fn reserve_gnu_verneed_section_index(&mut self) -> SectionIndex { - debug_assert!(self.gnu_verneed_str_id.is_none()); - self.gnu_verneed_str_id = Some(self.add_section_name(&b".gnu.version_r"[..])); - self.reserve_section_index() - } - - /// Write the section header for the `.gnu.version_r` section. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_gnu_verneed_section_header(&mut self, sh_addr: u64) { - if self.gnu_verneed_str_id.is_none() { - return; - } - self.write_section_header(&SectionHeader { - name: self.gnu_verneed_str_id, - sh_type: elf::SHT_GNU_VERNEED, - sh_flags: elf::SHF_ALLOC.into(), - sh_addr, - sh_offset: self.gnu_verneed_offset as u64, - sh_size: self.gnu_verneed_size as u64, - sh_link: self.dynstr_index.0, - sh_info: self.gnu_verneed_count.into(), - sh_addralign: self.elf_align as u64, - sh_entsize: 0, - }); - } - - /// Reserve the section index for the `.gnu.attributes` section. - pub fn reserve_gnu_attributes_section_index(&mut self) -> SectionIndex { - debug_assert!(self.gnu_attributes_str_id.is_none()); - self.gnu_attributes_str_id = Some(self.add_section_name(&b".gnu.attributes"[..])); - self.reserve_section_index() - } - - /// Reserve the range for the `.gnu.attributes` section. - pub fn reserve_gnu_attributes(&mut self, gnu_attributes_size: usize) { - debug_assert_eq!(self.gnu_attributes_offset, 0); - if gnu_attributes_size == 0 { - return; - } - self.gnu_attributes_size = gnu_attributes_size; - self.gnu_attributes_offset = self.reserve(self.gnu_attributes_size, self.elf_align); - } - - /// Write the section header for the `.gnu.attributes` section. - /// - /// This function does nothing if the section index was not reserved. - pub fn write_gnu_attributes_section_header(&mut self) { - if self.gnu_attributes_str_id.is_none() { - return; - } - self.write_section_header(&SectionHeader { - name: self.gnu_attributes_str_id, - sh_type: elf::SHT_GNU_ATTRIBUTES, - sh_flags: 0, - sh_addr: 0, - sh_offset: self.gnu_attributes_offset as u64, - sh_size: self.gnu_attributes_size as u64, - sh_link: self.dynstr_index.0, - sh_info: 0, // TODO - sh_addralign: self.elf_align as u64, - sh_entsize: 0, - }); - } - - /// Write the data for the `.gnu.attributes` section. - pub fn write_gnu_attributes(&mut self, data: &[u8]) { - if self.gnu_attributes_offset == 0 { - return; - } - util::write_align(self.buffer, self.elf_align); - debug_assert_eq!(self.gnu_attributes_offset, self.buffer.len()); - self.buffer.write_bytes(data); - } - - /// Reserve a file range for the given number of relocations. - /// - /// Returns the offset of the range. - pub fn reserve_relocations(&mut self, count: usize, is_rela: bool) -> usize { - self.reserve(count * self.rel_size(is_rela), self.elf_align) - } - - /// Write alignment padding bytes prior to a relocation section. - pub fn write_align_relocation(&mut self) { - util::write_align(self.buffer, self.elf_align); - } - - /// Write a relocation. - pub fn write_relocation(&mut self, is_rela: bool, rel: &Rel) { - let endian = self.endian; - if self.is_64 { - if is_rela { - let rel = elf::Rela64 { - r_offset: U64::new(endian, rel.r_offset), - r_info: elf::Rela64::r_info(endian, self.is_mips64el, rel.r_sym, rel.r_type), - r_addend: I64::new(endian, rel.r_addend), - }; - self.buffer.write(&rel); - } else { - let rel = elf::Rel64 { - r_offset: U64::new(endian, rel.r_offset), - r_info: elf::Rel64::r_info(endian, rel.r_sym, rel.r_type), - }; - self.buffer.write(&rel); - } - } else { - if is_rela { - let rel = elf::Rela32 { - r_offset: U32::new(endian, rel.r_offset as u32), - r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8), - r_addend: I32::new(endian, rel.r_addend as i32), - }; - self.buffer.write(&rel); - } else { - let rel = elf::Rel32 { - r_offset: U32::new(endian, rel.r_offset as u32), - r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8), - }; - self.buffer.write(&rel); - } - } - } - - /// Write the section header for a relocation section. - /// - /// `section` is the index of the section the relocations apply to, - /// or 0 if none. - /// - /// `symtab` is the index of the symbol table the relocations refer to, - /// or 0 if none. - /// - /// `offset` is the file offset of the relocations. - pub fn write_relocation_section_header( - &mut self, - name: StringId, - section: SectionIndex, - symtab: SectionIndex, - offset: usize, - count: usize, - is_rela: bool, - ) { - self.write_section_header(&SectionHeader { - name: Some(name), - sh_type: if is_rela { elf::SHT_RELA } else { elf::SHT_REL }, - sh_flags: elf::SHF_INFO_LINK.into(), - sh_addr: 0, - sh_offset: offset as u64, - sh_size: (count * self.rel_size(is_rela)) as u64, - sh_link: symtab.0, - sh_info: section.0, - sh_addralign: self.elf_align as u64, - sh_entsize: self.rel_size(is_rela) as u64, - }); - } - - /// Reserve a file range for a COMDAT section. - /// - /// `count` is the number of sections in the COMDAT group. - /// - /// Returns the offset of the range. - pub fn reserve_comdat(&mut self, count: usize) -> usize { - self.reserve((count + 1) * 4, 4) - } - - /// Write `GRP_COMDAT` at the start of the COMDAT section. - pub fn write_comdat_header(&mut self) { - util::write_align(self.buffer, 4); - self.buffer.write(&U32::new(self.endian, elf::GRP_COMDAT)); - } - - /// Write an entry in a COMDAT section. - pub fn write_comdat_entry(&mut self, entry: SectionIndex) { - self.buffer.write(&U32::new(self.endian, entry.0)); - } - - /// Write the section header for a COMDAT section. - pub fn write_comdat_section_header( - &mut self, - name: StringId, - symtab: SectionIndex, - symbol: SymbolIndex, - offset: usize, - count: usize, - ) { - self.write_section_header(&SectionHeader { - name: Some(name), - sh_type: elf::SHT_GROUP, - sh_flags: 0, - sh_addr: 0, - sh_offset: offset as u64, - sh_size: ((count + 1) * 4) as u64, - sh_link: symtab.0, - sh_info: symbol.0, - sh_addralign: 4, - sh_entsize: 4, - }); - } - - /// Return a helper for writing an attributes section. - pub fn attributes_writer(&self) -> AttributesWriter { - AttributesWriter::new(self.endian) - } -} - -/// A helper for writing an attributes section. -/// -/// Attributes have a variable length encoding, so it is awkward to write them in a -/// single pass. Instead, we build the entire attributes section data in memory, using -/// placeholders for unknown lengths that are filled in later. -#[allow(missing_debug_implementations)] -pub struct AttributesWriter { - endian: Endianness, - data: Vec<u8>, - subsection_offset: usize, - subsubsection_offset: usize, -} - -impl AttributesWriter { - /// Create a new `AttributesWriter` for the given endianness. - pub fn new(endian: Endianness) -> Self { - AttributesWriter { - endian, - data: vec![0x41], - subsection_offset: 0, - subsubsection_offset: 0, - } - } - - /// Start a new subsection with the given vendor name. - pub fn start_subsection(&mut self, vendor: &[u8]) { - debug_assert_eq!(self.subsection_offset, 0); - debug_assert_eq!(self.subsubsection_offset, 0); - self.subsection_offset = self.data.len(); - self.data.extend_from_slice(&[0; 4]); - self.data.extend_from_slice(vendor); - self.data.push(0); - } - - /// End the subsection. - /// - /// The subsection length is automatically calculated and written. - pub fn end_subsection(&mut self) { - debug_assert_ne!(self.subsection_offset, 0); - debug_assert_eq!(self.subsubsection_offset, 0); - let length = self.data.len() - self.subsection_offset; - self.data[self.subsection_offset..][..4] - .copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32))); - self.subsection_offset = 0; - } - - /// Start a new sub-subsection with the given tag. - pub fn start_subsubsection(&mut self, tag: u8) { - debug_assert_ne!(self.subsection_offset, 0); - debug_assert_eq!(self.subsubsection_offset, 0); - self.subsubsection_offset = self.data.len(); - self.data.push(tag); - self.data.extend_from_slice(&[0; 4]); - } - - /// Write a section or symbol index to the sub-subsection. - /// - /// The user must also call this function to write the terminating 0 index. - pub fn write_subsubsection_index(&mut self, index: u32) { - debug_assert_ne!(self.subsection_offset, 0); - debug_assert_ne!(self.subsubsection_offset, 0); - util::write_uleb128(&mut self.data, u64::from(index)); - } - - /// Write raw index data to the sub-subsection. - /// - /// The terminating 0 index is automatically written. - pub fn write_subsubsection_indices(&mut self, indices: &[u8]) { - debug_assert_ne!(self.subsection_offset, 0); - debug_assert_ne!(self.subsubsection_offset, 0); - self.data.extend_from_slice(indices); - self.data.push(0); - } - - /// Write an attribute tag to the sub-subsection. - pub fn write_attribute_tag(&mut self, tag: u64) { - debug_assert_ne!(self.subsection_offset, 0); - debug_assert_ne!(self.subsubsection_offset, 0); - util::write_uleb128(&mut self.data, tag); - } - - /// Write an attribute integer value to the sub-subsection. - pub fn write_attribute_integer(&mut self, value: u64) { - debug_assert_ne!(self.subsection_offset, 0); - debug_assert_ne!(self.subsubsection_offset, 0); - util::write_uleb128(&mut self.data, value); - } - - /// Write an attribute string value to the sub-subsection. - /// - /// The value must not include the null terminator. - pub fn write_attribute_string(&mut self, value: &[u8]) { - debug_assert_ne!(self.subsection_offset, 0); - debug_assert_ne!(self.subsubsection_offset, 0); - self.data.extend_from_slice(value); - self.data.push(0); - } - - /// Write raw attribute data to the sub-subsection. - pub fn write_subsubsection_attributes(&mut self, attributes: &[u8]) { - debug_assert_ne!(self.subsection_offset, 0); - debug_assert_ne!(self.subsubsection_offset, 0); - self.data.extend_from_slice(attributes); - } - - /// End the sub-subsection. - /// - /// The sub-subsection length is automatically calculated and written. - pub fn end_subsubsection(&mut self) { - debug_assert_ne!(self.subsection_offset, 0); - debug_assert_ne!(self.subsubsection_offset, 0); - let length = self.data.len() - self.subsubsection_offset; - self.data[self.subsubsection_offset + 1..][..4] - .copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32))); - self.subsubsection_offset = 0; - } - - /// Return the completed section data. - pub fn data(self) -> Vec<u8> { - debug_assert_eq!(self.subsection_offset, 0); - debug_assert_eq!(self.subsubsection_offset, 0); - self.data - } -} - -/// Native endian version of [`elf::FileHeader64`]. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub struct FileHeader { - pub os_abi: u8, - pub abi_version: u8, - pub e_type: u16, - pub e_machine: u16, - pub e_entry: u64, - pub e_flags: u32, -} - -/// Native endian version of [`elf::ProgramHeader64`]. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub struct ProgramHeader { - pub p_type: u32, - pub p_flags: u32, - pub p_offset: u64, - pub p_vaddr: u64, - pub p_paddr: u64, - pub p_filesz: u64, - pub p_memsz: u64, - pub p_align: u64, -} - -/// Native endian version of [`elf::SectionHeader64`]. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub struct SectionHeader { - pub name: Option<StringId>, - pub sh_type: u32, - pub sh_flags: u64, - pub sh_addr: u64, - pub sh_offset: u64, - pub sh_size: u64, - pub sh_link: u32, - pub sh_info: u32, - pub sh_addralign: u64, - pub sh_entsize: u64, -} - -/// Native endian version of [`elf::Sym64`]. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub struct Sym { - pub name: Option<StringId>, - pub section: Option<SectionIndex>, - pub st_info: u8, - pub st_other: u8, - pub st_shndx: u16, - pub st_value: u64, - pub st_size: u64, -} - -/// Unified native endian version of [`elf::Rel64`] and [`elf::Rela64`]. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub struct Rel { - pub r_offset: u64, - pub r_sym: u32, - pub r_type: u32, - pub r_addend: i64, -} - -/// Information required for writing [`elf::Verdef`]. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub struct Verdef { - pub version: u16, - pub flags: u16, - pub index: u16, - pub aux_count: u16, - /// The name for the first [`elf::Verdaux`] entry. - pub name: StringId, -} - -/// Information required for writing [`elf::Verneed`]. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub struct Verneed { - pub version: u16, - pub aux_count: u16, - pub file: StringId, -} - -/// Information required for writing [`elf::Vernaux`]. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub struct Vernaux { - pub flags: u16, - pub index: u16, - pub name: StringId, -} diff --git a/vendor/object/src/write/macho.rs b/vendor/object/src/write/macho.rs deleted file mode 100644 index 1c61523..0000000 --- a/vendor/object/src/write/macho.rs +++ /dev/null @@ -1,1095 +0,0 @@ -use core::mem; - -use crate::endian::*; -use crate::macho; -use crate::write::string::*; -use crate::write::util::*; -use crate::write::*; -use crate::AddressSize; - -#[derive(Default, Clone, Copy)] -struct SectionOffsets { - index: usize, - offset: usize, - address: u64, - reloc_offset: usize, - reloc_count: usize, -} - -#[derive(Default, Clone, Copy)] -struct SymbolOffsets { - index: usize, - str_id: Option<StringId>, -} - -/// The customizable portion of a [`macho::BuildVersionCommand`]. -#[derive(Debug, Default, Clone, Copy)] -#[non_exhaustive] // May want to add the tool list? -pub struct MachOBuildVersion { - /// One of the `PLATFORM_` constants (for example, - /// [`object::macho::PLATFORM_MACOS`](macho::PLATFORM_MACOS)). - pub platform: u32, - /// The minimum OS version, where `X.Y.Z` is encoded in nibbles as - /// `xxxx.yy.zz`. - pub minos: u32, - /// The SDK version as `X.Y.Z`, where `X.Y.Z` is encoded in nibbles as - /// `xxxx.yy.zz`. - pub sdk: u32, -} - -impl MachOBuildVersion { - fn cmdsize(&self) -> u32 { - // Same size for both endianness, and we don't have `ntools`. - let sz = mem::size_of::<macho::BuildVersionCommand<Endianness>>(); - debug_assert!(sz <= u32::MAX as usize); - sz as u32 - } -} - -// Public methods. -impl<'a> Object<'a> { - /// Specify the Mach-O CPU subtype. - /// - /// Requires `feature = "macho"`. - #[inline] - pub fn set_macho_cpu_subtype(&mut self, cpu_subtype: u32) { - self.macho_cpu_subtype = Some(cpu_subtype); - } - - /// Specify information for a Mach-O `LC_BUILD_VERSION` command. - /// - /// Requires `feature = "macho"`. - #[inline] - pub fn set_macho_build_version(&mut self, info: MachOBuildVersion) { - self.macho_build_version = Some(info); - } -} - -// Private methods. -impl<'a> Object<'a> { - pub(crate) fn macho_set_subsections_via_symbols(&mut self) { - let flags = match self.flags { - FileFlags::MachO { flags } => flags, - _ => 0, - }; - self.flags = FileFlags::MachO { - flags: flags | macho::MH_SUBSECTIONS_VIA_SYMBOLS, - }; - } - - pub(crate) fn macho_segment_name(&self, segment: StandardSegment) -> &'static [u8] { - match segment { - StandardSegment::Text => &b"__TEXT"[..], - StandardSegment::Data => &b"__DATA"[..], - StandardSegment::Debug => &b"__DWARF"[..], - } - } - - pub(crate) fn macho_section_info( - &self, - section: StandardSection, - ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { - match section { - StandardSection::Text => ( - &b"__TEXT"[..], - &b"__text"[..], - SectionKind::Text, - SectionFlags::None, - ), - StandardSection::Data => ( - &b"__DATA"[..], - &b"__data"[..], - SectionKind::Data, - SectionFlags::None, - ), - StandardSection::ReadOnlyData => ( - &b"__TEXT"[..], - &b"__const"[..], - SectionKind::ReadOnlyData, - SectionFlags::None, - ), - StandardSection::ReadOnlyDataWithRel => ( - &b"__DATA"[..], - &b"__const"[..], - SectionKind::ReadOnlyDataWithRel, - SectionFlags::None, - ), - StandardSection::ReadOnlyString => ( - &b"__TEXT"[..], - &b"__cstring"[..], - SectionKind::ReadOnlyString, - SectionFlags::None, - ), - StandardSection::UninitializedData => ( - &b"__DATA"[..], - &b"__bss"[..], - SectionKind::UninitializedData, - SectionFlags::None, - ), - StandardSection::Tls => ( - &b"__DATA"[..], - &b"__thread_data"[..], - SectionKind::Tls, - SectionFlags::None, - ), - StandardSection::UninitializedTls => ( - &b"__DATA"[..], - &b"__thread_bss"[..], - SectionKind::UninitializedTls, - SectionFlags::None, - ), - StandardSection::TlsVariables => ( - &b"__DATA"[..], - &b"__thread_vars"[..], - SectionKind::TlsVariables, - SectionFlags::None, - ), - StandardSection::Common => ( - &b"__DATA"[..], - &b"__common"[..], - SectionKind::Common, - SectionFlags::None, - ), - StandardSection::GnuProperty => { - // Unsupported section. - (&[], &[], SectionKind::Note, SectionFlags::None) - } - } - } - - fn macho_tlv_bootstrap(&mut self) -> SymbolId { - match self.tlv_bootstrap { - Some(id) => id, - None => { - let id = self.add_symbol(Symbol { - name: b"_tlv_bootstrap".to_vec(), - value: 0, - size: 0, - kind: SymbolKind::Text, - scope: SymbolScope::Dynamic, - weak: false, - section: SymbolSection::Undefined, - flags: SymbolFlags::None, - }); - self.tlv_bootstrap = Some(id); - id - } - } - } - - /// Create the `__thread_vars` entry for a TLS variable. - /// - /// The symbol given by `symbol_id` will be updated to point to this entry. - /// - /// A new `SymbolId` will be returned. The caller must update this symbol - /// to point to the initializer. - /// - /// If `symbol_id` is not for a TLS variable, then it is returned unchanged. - pub(crate) fn macho_add_thread_var(&mut self, symbol_id: SymbolId) -> SymbolId { - let symbol = self.symbol_mut(symbol_id); - if symbol.kind != SymbolKind::Tls { - return symbol_id; - } - - // Create the initializer symbol. - let mut name = symbol.name.clone(); - name.extend_from_slice(b"$tlv$init"); - let init_symbol_id = self.add_raw_symbol(Symbol { - name, - value: 0, - size: 0, - kind: SymbolKind::Tls, - scope: SymbolScope::Compilation, - weak: false, - section: SymbolSection::Undefined, - flags: SymbolFlags::None, - }); - - // Add the tlv entry. - // Three pointers in size: - // - __tlv_bootstrap - used to make sure support exists - // - spare pointer - used when mapped by the runtime - // - pointer to symbol initializer - let section = self.section_id(StandardSection::TlsVariables); - let address_size = self.architecture.address_size().unwrap().bytes(); - let size = u64::from(address_size) * 3; - let data = vec![0; size as usize]; - let offset = self.append_section_data(section, &data, u64::from(address_size)); - - let tlv_bootstrap = self.macho_tlv_bootstrap(); - self.add_relocation( - section, - Relocation { - offset, - size: address_size * 8, - kind: RelocationKind::Absolute, - encoding: RelocationEncoding::Generic, - symbol: tlv_bootstrap, - addend: 0, - }, - ) - .unwrap(); - self.add_relocation( - section, - Relocation { - offset: offset + u64::from(address_size) * 2, - size: address_size * 8, - kind: RelocationKind::Absolute, - encoding: RelocationEncoding::Generic, - symbol: init_symbol_id, - addend: 0, - }, - ) - .unwrap(); - - // Update the symbol to point to the tlv. - let symbol = self.symbol_mut(symbol_id); - symbol.value = offset; - symbol.size = size; - symbol.section = SymbolSection::Section(section); - - init_symbol_id - } - - pub(crate) fn macho_fixup_relocation(&mut self, relocation: &mut Relocation) -> i64 { - let relative = match relocation.kind { - RelocationKind::Relative - | RelocationKind::GotRelative - | RelocationKind::PltRelative - | RelocationKind::MachO { relative: true, .. } => true, - _ => false, - }; - if relative { - // For PC relative relocations on some architectures, the - // addend does not include the offset required due to the - // PC being different from the place of the relocation. - // This differs from other file formats, so adjust the - // addend here to account for this. - let pcrel_offset = match self.architecture { - Architecture::I386 => 4, - Architecture::X86_64 => match relocation.kind { - RelocationKind::MachO { - value: macho::X86_64_RELOC_SIGNED_1, - .. - } => 5, - RelocationKind::MachO { - value: macho::X86_64_RELOC_SIGNED_2, - .. - } => 6, - RelocationKind::MachO { - value: macho::X86_64_RELOC_SIGNED_4, - .. - } => 8, - _ => 4, - }, - // TODO: maybe missing support for some architectures and relocations - _ => 0, - }; - relocation.addend += pcrel_offset; - } - // Aarch64 relocs of these sizes act as if they are double-word length - if self.architecture == Architecture::Aarch64 && matches!(relocation.size, 12 | 21 | 26) { - relocation.size = 32; - } - // Check for relocations that use an explicit addend. - if self.architecture == Architecture::Aarch64 { - if relocation.encoding == RelocationEncoding::AArch64Call { - return 0; - } - if let RelocationKind::MachO { value, .. } = relocation.kind { - match value { - macho::ARM64_RELOC_BRANCH26 - | macho::ARM64_RELOC_PAGE21 - | macho::ARM64_RELOC_PAGEOFF12 => return 0, - _ => {} - } - } - } - // Signify implicit addend. - let constant = relocation.addend; - relocation.addend = 0; - constant - } - - pub(crate) fn macho_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { - let address_size = self.architecture.address_size().unwrap(); - let endian = self.endian; - let macho32 = MachO32 { endian }; - let macho64 = MachO64 { endian }; - let macho: &dyn MachO = match address_size { - AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => &macho32, - AddressSize::U64 => &macho64, - }; - let pointer_align = address_size.bytes() as usize; - - // Calculate offsets of everything, and build strtab. - let mut offset = 0; - - // Calculate size of Mach-O header. - offset += macho.mach_header_size(); - - // Calculate size of commands. - let mut ncmds = 0; - let command_offset = offset; - - // Calculate size of segment command and section headers. - let segment_command_offset = offset; - let segment_command_len = - macho.segment_command_size() + self.sections.len() * macho.section_header_size(); - offset += segment_command_len; - ncmds += 1; - - // Calculate size of build version. - let build_version_offset = offset; - if let Some(version) = &self.macho_build_version { - offset += version.cmdsize() as usize; - ncmds += 1; - } - - // Calculate size of symtab command. - let symtab_command_offset = offset; - let symtab_command_len = mem::size_of::<macho::SymtabCommand<Endianness>>(); - offset += symtab_command_len; - ncmds += 1; - - // Calculate size of dysymtab command. - let dysymtab_command_offset = offset; - let dysymtab_command_len = mem::size_of::<macho::DysymtabCommand<Endianness>>(); - offset += dysymtab_command_len; - ncmds += 1; - - let sizeofcmds = offset - command_offset; - - // Calculate size of section data. - // Section data can immediately follow the load commands without any alignment padding. - let segment_file_offset = offset; - let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()]; - let mut address = 0; - for (index, section) in self.sections.iter().enumerate() { - section_offsets[index].index = 1 + index; - if !section.is_bss() { - address = align_u64(address, section.align); - section_offsets[index].address = address; - section_offsets[index].offset = segment_file_offset + address as usize; - address += section.size; - } - } - let segment_file_size = address as usize; - offset += address as usize; - for (index, section) in self.sections.iter().enumerate() { - if section.is_bss() { - debug_assert!(section.data.is_empty()); - address = align_u64(address, section.align); - section_offsets[index].address = address; - address += section.size; - } - } - - // Partition symbols and add symbol strings to strtab. - let mut strtab = StringTable::default(); - let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; - let mut local_symbols = vec![]; - let mut external_symbols = vec![]; - let mut undefined_symbols = vec![]; - for (index, symbol) in self.symbols.iter().enumerate() { - // The unified API allows creating symbols that we don't emit, so filter - // them out here. - // - // Since we don't actually emit the symbol kind, we validate it here too. - match symbol.kind { - SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls | SymbolKind::Unknown => {} - SymbolKind::File | SymbolKind::Section => continue, - SymbolKind::Null | SymbolKind::Label => { - return Err(Error(format!( - "unimplemented symbol `{}` kind {:?}", - symbol.name().unwrap_or(""), - symbol.kind - ))); - } - } - if !symbol.name.is_empty() { - symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); - } - if symbol.is_undefined() { - undefined_symbols.push(index); - } else if symbol.is_local() { - local_symbols.push(index); - } else { - external_symbols.push(index); - } - } - - external_symbols.sort_by_key(|index| &*self.symbols[*index].name); - undefined_symbols.sort_by_key(|index| &*self.symbols[*index].name); - - // Count symbols. - let mut nsyms = 0; - for index in local_symbols - .iter() - .copied() - .chain(external_symbols.iter().copied()) - .chain(undefined_symbols.iter().copied()) - { - symbol_offsets[index].index = nsyms; - nsyms += 1; - } - - // Calculate size of relocations. - for (index, section) in self.sections.iter().enumerate() { - let count: usize = section - .relocations - .iter() - .map(|reloc| 1 + usize::from(reloc.addend != 0)) - .sum(); - if count != 0 { - offset = align(offset, pointer_align); - section_offsets[index].reloc_offset = offset; - section_offsets[index].reloc_count = count; - let len = count * mem::size_of::<macho::Relocation<Endianness>>(); - offset += len; - } - } - - // Calculate size of symtab. - offset = align(offset, pointer_align); - let symtab_offset = offset; - let symtab_len = nsyms * macho.nlist_size(); - offset += symtab_len; - - // Calculate size of strtab. - let strtab_offset = offset; - // Start with null name. - let mut strtab_data = vec![0]; - strtab.write(1, &mut strtab_data); - write_align(&mut strtab_data, pointer_align); - offset += strtab_data.len(); - - // Start writing. - buffer - .reserve(offset) - .map_err(|_| Error(String::from("Cannot allocate buffer")))?; - - // Write file header. - let (cputype, mut cpusubtype) = match (self.architecture, self.sub_architecture) { - (Architecture::Arm, None) => (macho::CPU_TYPE_ARM, macho::CPU_SUBTYPE_ARM_ALL), - (Architecture::Aarch64, None) => (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64_ALL), - (Architecture::Aarch64, Some(SubArchitecture::Arm64E)) => { - (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64E) - } - (Architecture::Aarch64_Ilp32, None) => { - (macho::CPU_TYPE_ARM64_32, macho::CPU_SUBTYPE_ARM64_32_V8) - } - (Architecture::I386, None) => (macho::CPU_TYPE_X86, macho::CPU_SUBTYPE_I386_ALL), - (Architecture::X86_64, None) => (macho::CPU_TYPE_X86_64, macho::CPU_SUBTYPE_X86_64_ALL), - (Architecture::PowerPc, None) => { - (macho::CPU_TYPE_POWERPC, macho::CPU_SUBTYPE_POWERPC_ALL) - } - (Architecture::PowerPc64, None) => { - (macho::CPU_TYPE_POWERPC64, macho::CPU_SUBTYPE_POWERPC_ALL) - } - _ => { - return Err(Error(format!( - "unimplemented architecture {:?} with sub-architecture {:?}", - self.architecture, self.sub_architecture - ))); - } - }; - - if let Some(cpu_subtype) = self.macho_cpu_subtype { - cpusubtype = cpu_subtype; - } - - let flags = match self.flags { - FileFlags::MachO { flags } => flags, - _ => 0, - }; - macho.write_mach_header( - buffer, - MachHeader { - cputype, - cpusubtype, - filetype: macho::MH_OBJECT, - ncmds, - sizeofcmds: sizeofcmds as u32, - flags, - }, - ); - - // Write segment command. - debug_assert_eq!(segment_command_offset, buffer.len()); - macho.write_segment_command( - buffer, - SegmentCommand { - cmdsize: segment_command_len as u32, - segname: [0; 16], - vmaddr: 0, - vmsize: address, - fileoff: segment_file_offset as u64, - filesize: segment_file_size as u64, - maxprot: macho::VM_PROT_READ | macho::VM_PROT_WRITE | macho::VM_PROT_EXECUTE, - initprot: macho::VM_PROT_READ | macho::VM_PROT_WRITE | macho::VM_PROT_EXECUTE, - nsects: self.sections.len() as u32, - flags: 0, - }, - ); - - // Write section headers. - for (index, section) in self.sections.iter().enumerate() { - let mut sectname = [0; 16]; - sectname - .get_mut(..section.name.len()) - .ok_or_else(|| { - Error(format!( - "section name `{}` is too long", - section.name().unwrap_or(""), - )) - })? - .copy_from_slice(§ion.name); - let mut segname = [0; 16]; - segname - .get_mut(..section.segment.len()) - .ok_or_else(|| { - Error(format!( - "segment name `{}` is too long", - section.segment().unwrap_or(""), - )) - })? - .copy_from_slice(§ion.segment); - let flags = if let SectionFlags::MachO { flags } = section.flags { - flags - } else { - match section.kind { - SectionKind::Text => { - macho::S_ATTR_PURE_INSTRUCTIONS | macho::S_ATTR_SOME_INSTRUCTIONS - } - SectionKind::Data => 0, - SectionKind::ReadOnlyData | SectionKind::ReadOnlyDataWithRel => 0, - SectionKind::ReadOnlyString => macho::S_CSTRING_LITERALS, - SectionKind::UninitializedData | SectionKind::Common => macho::S_ZEROFILL, - SectionKind::Tls => macho::S_THREAD_LOCAL_REGULAR, - SectionKind::UninitializedTls => macho::S_THREAD_LOCAL_ZEROFILL, - SectionKind::TlsVariables => macho::S_THREAD_LOCAL_VARIABLES, - SectionKind::Debug => macho::S_ATTR_DEBUG, - SectionKind::OtherString => macho::S_CSTRING_LITERALS, - SectionKind::Other | SectionKind::Linker | SectionKind::Metadata => 0, - SectionKind::Note | SectionKind::Unknown | SectionKind::Elf(_) => { - return Err(Error(format!( - "unimplemented section `{}` kind {:?}", - section.name().unwrap_or(""), - section.kind - ))); - } - } - }; - macho.write_section( - buffer, - SectionHeader { - sectname, - segname, - addr: section_offsets[index].address, - size: section.size, - offset: section_offsets[index].offset as u32, - align: section.align.trailing_zeros(), - reloff: section_offsets[index].reloc_offset as u32, - nreloc: section_offsets[index].reloc_count as u32, - flags, - }, - ); - } - - // Write build version. - if let Some(version) = &self.macho_build_version { - debug_assert_eq!(build_version_offset, buffer.len()); - buffer.write(&macho::BuildVersionCommand { - cmd: U32::new(endian, macho::LC_BUILD_VERSION), - cmdsize: U32::new(endian, version.cmdsize()), - platform: U32::new(endian, version.platform), - minos: U32::new(endian, version.minos), - sdk: U32::new(endian, version.sdk), - ntools: U32::new(endian, 0), - }); - } - - // Write symtab command. - debug_assert_eq!(symtab_command_offset, buffer.len()); - let symtab_command = macho::SymtabCommand { - cmd: U32::new(endian, macho::LC_SYMTAB), - cmdsize: U32::new(endian, symtab_command_len as u32), - symoff: U32::new(endian, symtab_offset as u32), - nsyms: U32::new(endian, nsyms as u32), - stroff: U32::new(endian, strtab_offset as u32), - strsize: U32::new(endian, strtab_data.len() as u32), - }; - buffer.write(&symtab_command); - - // Write dysymtab command. - debug_assert_eq!(dysymtab_command_offset, buffer.len()); - let dysymtab_command = macho::DysymtabCommand { - cmd: U32::new(endian, macho::LC_DYSYMTAB), - cmdsize: U32::new(endian, dysymtab_command_len as u32), - ilocalsym: U32::new(endian, 0), - nlocalsym: U32::new(endian, local_symbols.len() as u32), - iextdefsym: U32::new(endian, local_symbols.len() as u32), - nextdefsym: U32::new(endian, external_symbols.len() as u32), - iundefsym: U32::new( - endian, - local_symbols.len() as u32 + external_symbols.len() as u32, - ), - nundefsym: U32::new(endian, undefined_symbols.len() as u32), - tocoff: U32::default(), - ntoc: U32::default(), - modtaboff: U32::default(), - nmodtab: U32::default(), - extrefsymoff: U32::default(), - nextrefsyms: U32::default(), - indirectsymoff: U32::default(), - nindirectsyms: U32::default(), - extreloff: U32::default(), - nextrel: U32::default(), - locreloff: U32::default(), - nlocrel: U32::default(), - }; - buffer.write(&dysymtab_command); - - // Write section data. - for (index, section) in self.sections.iter().enumerate() { - if !section.is_bss() { - buffer.resize(section_offsets[index].offset); - buffer.write_bytes(§ion.data); - } - } - debug_assert_eq!(segment_file_offset + segment_file_size, buffer.len()); - - // Write relocations. - for (index, section) in self.sections.iter().enumerate() { - if !section.relocations.is_empty() { - write_align(buffer, pointer_align); - debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); - for reloc in §ion.relocations { - let r_length = match reloc.size { - 8 => 0, - 16 => 1, - 32 => 2, - 64 => 3, - _ => return Err(Error(format!("unimplemented reloc size {:?}", reloc))), - }; - - // Write explicit addend. - if reloc.addend != 0 { - let r_type = match self.architecture { - Architecture::Aarch64 | Architecture::Aarch64_Ilp32 => { - macho::ARM64_RELOC_ADDEND - } - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))) - } - }; - - let reloc_info = macho::RelocationInfo { - r_address: reloc.offset as u32, - r_symbolnum: reloc.addend as u32, - r_pcrel: false, - r_length, - r_extern: false, - r_type, - }; - buffer.write(&reloc_info.relocation(endian)); - } - - let r_extern; - let r_symbolnum; - let symbol = &self.symbols[reloc.symbol.0]; - if symbol.kind == SymbolKind::Section { - r_symbolnum = section_offsets[symbol.section.id().unwrap().0].index as u32; - r_extern = false; - } else { - r_symbolnum = symbol_offsets[reloc.symbol.0].index as u32; - r_extern = true; - } - let (r_pcrel, r_type) = match self.architecture { - Architecture::I386 => match reloc.kind { - RelocationKind::Absolute => (false, macho::GENERIC_RELOC_VANILLA), - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::X86_64 => match (reloc.kind, reloc.encoding) { - (RelocationKind::Absolute, RelocationEncoding::Generic) => { - (false, macho::X86_64_RELOC_UNSIGNED) - } - (RelocationKind::Relative, RelocationEncoding::Generic) => { - (true, macho::X86_64_RELOC_SIGNED) - } - (RelocationKind::Relative, RelocationEncoding::X86RipRelative) => { - (true, macho::X86_64_RELOC_SIGNED) - } - (RelocationKind::Relative, RelocationEncoding::X86Branch) => { - (true, macho::X86_64_RELOC_BRANCH) - } - (RelocationKind::PltRelative, RelocationEncoding::X86Branch) => { - (true, macho::X86_64_RELOC_BRANCH) - } - (RelocationKind::GotRelative, RelocationEncoding::Generic) => { - (true, macho::X86_64_RELOC_GOT) - } - ( - RelocationKind::GotRelative, - RelocationEncoding::X86RipRelativeMovq, - ) => (true, macho::X86_64_RELOC_GOT_LOAD), - (RelocationKind::MachO { value, relative }, _) => (relative, value), - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }, - Architecture::Aarch64 | Architecture::Aarch64_Ilp32 => { - match (reloc.kind, reloc.encoding) { - (RelocationKind::Absolute, RelocationEncoding::Generic) => { - (false, macho::ARM64_RELOC_UNSIGNED) - } - (RelocationKind::Relative, RelocationEncoding::AArch64Call) => { - (true, macho::ARM64_RELOC_BRANCH26) - } - ( - RelocationKind::MachO { value, relative }, - RelocationEncoding::Generic, - ) => (relative, value), - _ => { - return Err(Error(format!( - "unimplemented relocation {:?}", - reloc - ))); - } - } - } - _ => { - if let RelocationKind::MachO { value, relative } = reloc.kind { - (relative, value) - } else { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - } - }; - let reloc_info = macho::RelocationInfo { - r_address: reloc.offset as u32, - r_symbolnum, - r_pcrel, - r_length, - r_extern, - r_type, - }; - buffer.write(&reloc_info.relocation(endian)); - } - } - } - - // Write symtab. - write_align(buffer, pointer_align); - debug_assert_eq!(symtab_offset, buffer.len()); - for index in local_symbols - .iter() - .copied() - .chain(external_symbols.iter().copied()) - .chain(undefined_symbols.iter().copied()) - { - let symbol = &self.symbols[index]; - // TODO: N_STAB - let (mut n_type, n_sect) = match symbol.section { - SymbolSection::Undefined => (macho::N_UNDF | macho::N_EXT, 0), - SymbolSection::Absolute => (macho::N_ABS, 0), - SymbolSection::Section(id) => (macho::N_SECT, id.0 + 1), - SymbolSection::None | SymbolSection::Common => { - return Err(Error(format!( - "unimplemented symbol `{}` section {:?}", - symbol.name().unwrap_or(""), - symbol.section - ))); - } - }; - match symbol.scope { - SymbolScope::Unknown | SymbolScope::Compilation => {} - SymbolScope::Linkage => { - n_type |= macho::N_EXT | macho::N_PEXT; - } - SymbolScope::Dynamic => { - n_type |= macho::N_EXT; - } - } - - let n_desc = if let SymbolFlags::MachO { n_desc } = symbol.flags { - n_desc - } else { - let mut n_desc = 0; - if symbol.weak { - if symbol.is_undefined() { - n_desc |= macho::N_WEAK_REF; - } else { - n_desc |= macho::N_WEAK_DEF; - } - } - n_desc - }; - - let n_value = match symbol.section.id() { - Some(section) => section_offsets[section.0].address + symbol.value, - None => symbol.value, - }; - - let n_strx = symbol_offsets[index] - .str_id - .map(|id| strtab.get_offset(id)) - .unwrap_or(0); - - macho.write_nlist( - buffer, - Nlist { - n_strx: n_strx as u32, - n_type, - n_sect: n_sect as u8, - n_desc, - n_value, - }, - ); - } - - // Write strtab. - debug_assert_eq!(strtab_offset, buffer.len()); - buffer.write_bytes(&strtab_data); - - debug_assert_eq!(offset, buffer.len()); - - Ok(()) - } -} - -struct MachHeader { - cputype: u32, - cpusubtype: u32, - filetype: u32, - ncmds: u32, - sizeofcmds: u32, - flags: u32, -} - -struct SegmentCommand { - cmdsize: u32, - segname: [u8; 16], - vmaddr: u64, - vmsize: u64, - fileoff: u64, - filesize: u64, - maxprot: u32, - initprot: u32, - nsects: u32, - flags: u32, -} - -pub struct SectionHeader { - sectname: [u8; 16], - segname: [u8; 16], - addr: u64, - size: u64, - offset: u32, - align: u32, - reloff: u32, - nreloc: u32, - flags: u32, -} - -struct Nlist { - n_strx: u32, - n_type: u8, - n_sect: u8, - n_desc: u16, - n_value: u64, -} - -trait MachO { - fn mach_header_size(&self) -> usize; - fn segment_command_size(&self) -> usize; - fn section_header_size(&self) -> usize; - fn nlist_size(&self) -> usize; - fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, section: MachHeader); - fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand); - fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader); - fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist); -} - -struct MachO32<E> { - endian: E, -} - -impl<E: Endian> MachO for MachO32<E> { - fn mach_header_size(&self) -> usize { - mem::size_of::<macho::MachHeader32<E>>() - } - - fn segment_command_size(&self) -> usize { - mem::size_of::<macho::SegmentCommand32<E>>() - } - - fn section_header_size(&self) -> usize { - mem::size_of::<macho::Section32<E>>() - } - - fn nlist_size(&self) -> usize { - mem::size_of::<macho::Nlist32<E>>() - } - - fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) { - let endian = self.endian; - let magic = if endian.is_big_endian() { - macho::MH_MAGIC - } else { - macho::MH_CIGAM - }; - let header = macho::MachHeader32 { - magic: U32::new(BigEndian, magic), - cputype: U32::new(endian, header.cputype), - cpusubtype: U32::new(endian, header.cpusubtype), - filetype: U32::new(endian, header.filetype), - ncmds: U32::new(endian, header.ncmds), - sizeofcmds: U32::new(endian, header.sizeofcmds), - flags: U32::new(endian, header.flags), - }; - buffer.write(&header); - } - - fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) { - let endian = self.endian; - let segment = macho::SegmentCommand32 { - cmd: U32::new(endian, macho::LC_SEGMENT), - cmdsize: U32::new(endian, segment.cmdsize), - segname: segment.segname, - vmaddr: U32::new(endian, segment.vmaddr as u32), - vmsize: U32::new(endian, segment.vmsize as u32), - fileoff: U32::new(endian, segment.fileoff as u32), - filesize: U32::new(endian, segment.filesize as u32), - maxprot: U32::new(endian, segment.maxprot), - initprot: U32::new(endian, segment.initprot), - nsects: U32::new(endian, segment.nsects), - flags: U32::new(endian, segment.flags), - }; - buffer.write(&segment); - } - - fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { - let endian = self.endian; - let section = macho::Section32 { - sectname: section.sectname, - segname: section.segname, - addr: U32::new(endian, section.addr as u32), - size: U32::new(endian, section.size as u32), - offset: U32::new(endian, section.offset), - align: U32::new(endian, section.align), - reloff: U32::new(endian, section.reloff), - nreloc: U32::new(endian, section.nreloc), - flags: U32::new(endian, section.flags), - reserved1: U32::default(), - reserved2: U32::default(), - }; - buffer.write(§ion); - } - - fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) { - let endian = self.endian; - let nlist = macho::Nlist32 { - n_strx: U32::new(endian, nlist.n_strx), - n_type: nlist.n_type, - n_sect: nlist.n_sect, - n_desc: U16::new(endian, nlist.n_desc), - n_value: U32::new(endian, nlist.n_value as u32), - }; - buffer.write(&nlist); - } -} - -struct MachO64<E> { - endian: E, -} - -impl<E: Endian> MachO for MachO64<E> { - fn mach_header_size(&self) -> usize { - mem::size_of::<macho::MachHeader64<E>>() - } - - fn segment_command_size(&self) -> usize { - mem::size_of::<macho::SegmentCommand64<E>>() - } - - fn section_header_size(&self) -> usize { - mem::size_of::<macho::Section64<E>>() - } - - fn nlist_size(&self) -> usize { - mem::size_of::<macho::Nlist64<E>>() - } - - fn write_mach_header(&self, buffer: &mut dyn WritableBuffer, header: MachHeader) { - let endian = self.endian; - let magic = if endian.is_big_endian() { - macho::MH_MAGIC_64 - } else { - macho::MH_CIGAM_64 - }; - let header = macho::MachHeader64 { - magic: U32::new(BigEndian, magic), - cputype: U32::new(endian, header.cputype), - cpusubtype: U32::new(endian, header.cpusubtype), - filetype: U32::new(endian, header.filetype), - ncmds: U32::new(endian, header.ncmds), - sizeofcmds: U32::new(endian, header.sizeofcmds), - flags: U32::new(endian, header.flags), - reserved: U32::default(), - }; - buffer.write(&header); - } - - fn write_segment_command(&self, buffer: &mut dyn WritableBuffer, segment: SegmentCommand) { - let endian = self.endian; - let segment = macho::SegmentCommand64 { - cmd: U32::new(endian, macho::LC_SEGMENT_64), - cmdsize: U32::new(endian, segment.cmdsize), - segname: segment.segname, - vmaddr: U64::new(endian, segment.vmaddr), - vmsize: U64::new(endian, segment.vmsize), - fileoff: U64::new(endian, segment.fileoff), - filesize: U64::new(endian, segment.filesize), - maxprot: U32::new(endian, segment.maxprot), - initprot: U32::new(endian, segment.initprot), - nsects: U32::new(endian, segment.nsects), - flags: U32::new(endian, segment.flags), - }; - buffer.write(&segment); - } - - fn write_section(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) { - let endian = self.endian; - let section = macho::Section64 { - sectname: section.sectname, - segname: section.segname, - addr: U64::new(endian, section.addr), - size: U64::new(endian, section.size), - offset: U32::new(endian, section.offset), - align: U32::new(endian, section.align), - reloff: U32::new(endian, section.reloff), - nreloc: U32::new(endian, section.nreloc), - flags: U32::new(endian, section.flags), - reserved1: U32::default(), - reserved2: U32::default(), - reserved3: U32::default(), - }; - buffer.write(§ion); - } - - fn write_nlist(&self, buffer: &mut dyn WritableBuffer, nlist: Nlist) { - let endian = self.endian; - let nlist = macho::Nlist64 { - n_strx: U32::new(endian, nlist.n_strx), - n_type: nlist.n_type, - n_sect: nlist.n_sect, - n_desc: U16::new(endian, nlist.n_desc), - n_value: U64Bytes::new(endian, nlist.n_value), - }; - buffer.write(&nlist); - } -} diff --git a/vendor/object/src/write/mod.rs b/vendor/object/src/write/mod.rs deleted file mode 100644 index cea4d2e..0000000 --- a/vendor/object/src/write/mod.rs +++ /dev/null @@ -1,961 +0,0 @@ -//! 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, SubArchitecture, SymbolFlags, SymbolKind, SymbolScope, -}; - -#[cfg(feature = "coff")] -pub 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<T> = result::Result<T, Error>; - -/// A writable relocatable object file. -#[derive(Debug)] -pub struct Object<'a> { - format: BinaryFormat, - architecture: Architecture, - sub_architecture: Option<SubArchitecture>, - endian: Endianness, - sections: Vec<Section<'a>>, - standard_sections: HashMap<StandardSection, SectionId>, - symbols: Vec<Symbol>, - symbol_map: HashMap<Vec<u8>, SymbolId>, - stub_symbols: HashMap<SymbolId, SymbolId>, - comdats: Vec<Comdat>, - /// 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<SymbolId>, - /// Mach-O CPU subtype. - #[cfg(feature = "macho")] - macho_cpu_subtype: Option<u32>, - #[cfg(feature = "macho")] - macho_build_version: Option<MachOBuildVersion>, -} - -impl<'a> Object<'a> { - /// Create an empty object file. - pub fn new(format: BinaryFormat, architecture: Architecture, endian: Endianness) -> Object<'a> { - Object { - format, - architecture, - sub_architecture: None, - 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_cpu_subtype: 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 sub-architecture. - #[inline] - pub fn sub_architecture(&self) -> Option<SubArchitecture> { - self.sub_architecture - } - - /// Specify the sub-architecture. - pub fn set_sub_architecture(&mut self, sub_architecture: Option<SubArchitecture>) { - self.sub_architecture = sub_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<T>(&mut self, 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. - 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<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); - } - } - } - - 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<u8>, 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<u8> { - 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<SymbolId> { - 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<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. - 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<Vec<u8>> { - 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<W: io::Write>(&self, w: W) -> result::Result<(), Box<dyn error::Error>> { - 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<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] - 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<T>(&mut self, 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. - 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<SectionId> { - 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<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] - 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<SectionId>, -} - -/// 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<u8> { - match self { - Mangling::None | Mangling::Elf | Mangling::Coff | Mangling::Xcoff => None, - Mangling::CoffI386 | Mangling::MachO => Some(b'_'), - } - } -} diff --git a/vendor/object/src/write/pe.rs b/vendor/object/src/write/pe.rs deleted file mode 100644 index 70da3a0..0000000 --- a/vendor/object/src/write/pe.rs +++ /dev/null @@ -1,847 +0,0 @@ -//! Helper for writing PE files. -use alloc::string::String; -use alloc::vec::Vec; -use core::mem; - -use crate::endian::{LittleEndian as LE, *}; -use crate::pe; -use crate::write::util; -use crate::write::{Error, Result, WritableBuffer}; - -/// A helper for writing PE files. -/// -/// Writing uses a two phase approach. The first phase reserves file ranges and virtual -/// address ranges for everything in the order that they will be written. -/// -/// The second phase writes everything out in order. Thus the caller must ensure writing -/// is in the same order that file ranges were reserved. -#[allow(missing_debug_implementations)] -pub struct Writer<'a> { - is_64: bool, - section_alignment: u32, - file_alignment: u32, - - buffer: &'a mut dyn WritableBuffer, - len: u32, - virtual_len: u32, - headers_len: u32, - - code_address: u32, - data_address: u32, - code_len: u32, - data_len: u32, - bss_len: u32, - - nt_headers_offset: u32, - data_directories: Vec<DataDirectory>, - section_header_num: u16, - sections: Vec<Section>, - - symbol_offset: u32, - symbol_num: u32, - - reloc_blocks: Vec<RelocBlock>, - relocs: Vec<U16<LE>>, - reloc_offset: u32, -} - -impl<'a> Writer<'a> { - /// Create a new `Writer`. - pub fn new( - is_64: bool, - section_alignment: u32, - file_alignment: u32, - buffer: &'a mut dyn WritableBuffer, - ) -> Self { - Writer { - is_64, - section_alignment, - file_alignment, - - buffer, - len: 0, - virtual_len: 0, - headers_len: 0, - - code_address: 0, - data_address: 0, - code_len: 0, - data_len: 0, - bss_len: 0, - - nt_headers_offset: 0, - data_directories: Vec::new(), - section_header_num: 0, - sections: Vec::new(), - - symbol_offset: 0, - symbol_num: 0, - - reloc_blocks: Vec::new(), - relocs: Vec::new(), - reloc_offset: 0, - } - } - - /// Return the current virtual address size that has been reserved. - /// - /// This is only valid after section headers have been reserved. - pub fn virtual_len(&self) -> u32 { - self.virtual_len - } - - /// Reserve a virtual address range with the given size. - /// - /// The reserved length will be increased to match the section alignment. - /// - /// Returns the aligned offset of the start of the range. - pub fn reserve_virtual(&mut self, len: u32) -> u32 { - let offset = self.virtual_len; - self.virtual_len += len; - self.virtual_len = util::align_u32(self.virtual_len, self.section_alignment); - offset - } - - /// Reserve up to the given virtual address. - /// - /// The reserved length will be increased to match the section alignment. - pub fn reserve_virtual_until(&mut self, address: u32) { - debug_assert!(self.virtual_len <= address); - self.virtual_len = util::align_u32(address, self.section_alignment); - } - - /// Return the current file length that has been reserved. - pub fn reserved_len(&self) -> u32 { - 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: u32, align_start: u32) -> u32 { - if len == 0 { - return self.len; - } - self.reserve_align(align_start); - let offset = self.len; - self.len += len; - offset - } - - /// Reserve a file range with the given size and using the file alignment. - /// - /// Returns the aligned offset of the start of the range. - pub fn reserve_file(&mut self, len: u32) -> u32 { - self.reserve(len, self.file_alignment) - } - - /// Write data. - pub fn write(&mut self, data: &[u8]) { - self.buffer.write_bytes(data); - } - - /// Reserve alignment padding bytes. - pub fn reserve_align(&mut self, align_start: u32) { - self.len = util::align_u32(self.len, align_start); - } - - /// Write alignment padding bytes. - pub fn write_align(&mut self, align_start: u32) { - util::write_align(self.buffer, align_start as usize); - } - - /// Write padding up to the next multiple of file alignment. - pub fn write_file_align(&mut self) { - self.write_align(self.file_alignment); - } - - /// Reserve the file range up to the given file offset. - pub fn reserve_until(&mut self, offset: u32) { - debug_assert!(self.len <= offset); - self.len = offset; - } - - /// Write padding up to the given file offset. - pub fn pad_until(&mut self, offset: u32) { - debug_assert!(self.buffer.len() <= offset as usize); - self.buffer.resize(offset as usize); - } - - /// Reserve the range for the DOS header. - /// - /// This must be at the start of the file. - /// - /// When writing, you may use `write_custom_dos_header` or `write_empty_dos_header`. - pub fn reserve_dos_header(&mut self) { - debug_assert_eq!(self.len, 0); - self.reserve(mem::size_of::<pe::ImageDosHeader>() as u32, 1); - } - - /// Write a custom DOS header. - /// - /// This must be at the start of the file. - pub fn write_custom_dos_header(&mut self, dos_header: &pe::ImageDosHeader) -> Result<()> { - debug_assert_eq!(self.buffer.len(), 0); - - // Start writing. - self.buffer - .reserve(self.len as usize) - .map_err(|_| Error(String::from("Cannot allocate buffer")))?; - - self.buffer.write(dos_header); - Ok(()) - } - - /// Write the DOS header for a file without a stub. - /// - /// This must be at the start of the file. - /// - /// Uses default values for all fields. - pub fn write_empty_dos_header(&mut self) -> Result<()> { - self.write_custom_dos_header(&pe::ImageDosHeader { - e_magic: U16::new(LE, pe::IMAGE_DOS_SIGNATURE), - e_cblp: U16::new(LE, 0), - e_cp: U16::new(LE, 0), - e_crlc: U16::new(LE, 0), - e_cparhdr: U16::new(LE, 0), - e_minalloc: U16::new(LE, 0), - e_maxalloc: U16::new(LE, 0), - e_ss: U16::new(LE, 0), - e_sp: U16::new(LE, 0), - e_csum: U16::new(LE, 0), - e_ip: U16::new(LE, 0), - e_cs: U16::new(LE, 0), - e_lfarlc: U16::new(LE, 0), - e_ovno: U16::new(LE, 0), - e_res: [U16::new(LE, 0); 4], - e_oemid: U16::new(LE, 0), - e_oeminfo: U16::new(LE, 0), - e_res2: [U16::new(LE, 0); 10], - e_lfanew: U32::new(LE, self.nt_headers_offset), - }) - } - - /// Reserve a fixed DOS header and stub. - /// - /// Use `reserve_dos_header` and `reserve` if you need a custom stub. - pub fn reserve_dos_header_and_stub(&mut self) { - self.reserve_dos_header(); - self.reserve(64, 1); - } - - /// Write a fixed DOS header and stub. - /// - /// Use `write_custom_dos_header` and `write` if you need a custom stub. - pub fn write_dos_header_and_stub(&mut self) -> Result<()> { - self.write_custom_dos_header(&pe::ImageDosHeader { - e_magic: U16::new(LE, pe::IMAGE_DOS_SIGNATURE), - e_cblp: U16::new(LE, 0x90), - e_cp: U16::new(LE, 3), - e_crlc: U16::new(LE, 0), - e_cparhdr: U16::new(LE, 4), - e_minalloc: U16::new(LE, 0), - e_maxalloc: U16::new(LE, 0xffff), - e_ss: U16::new(LE, 0), - e_sp: U16::new(LE, 0xb8), - e_csum: U16::new(LE, 0), - e_ip: U16::new(LE, 0), - e_cs: U16::new(LE, 0), - e_lfarlc: U16::new(LE, 0x40), - e_ovno: U16::new(LE, 0), - e_res: [U16::new(LE, 0); 4], - e_oemid: U16::new(LE, 0), - e_oeminfo: U16::new(LE, 0), - e_res2: [U16::new(LE, 0); 10], - e_lfanew: U32::new(LE, self.nt_headers_offset), - })?; - - #[rustfmt::skip] - self.buffer.write_bytes(&[ - 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, - 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, - 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, - 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, - 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, - 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]); - - Ok(()) - } - - fn nt_headers_size(&self) -> u32 { - if self.is_64 { - mem::size_of::<pe::ImageNtHeaders64>() as u32 - } else { - mem::size_of::<pe::ImageNtHeaders32>() as u32 - } - } - - fn optional_header_size(&self) -> u32 { - let size = if self.is_64 { - mem::size_of::<pe::ImageOptionalHeader64>() as u32 - } else { - mem::size_of::<pe::ImageOptionalHeader32>() as u32 - }; - size + self.data_directories.len() as u32 * mem::size_of::<pe::ImageDataDirectory>() as u32 - } - - /// Return the offset of the NT headers, if reserved. - pub fn nt_headers_offset(&self) -> u32 { - self.nt_headers_offset - } - - /// Reserve the range for the NT headers. - pub fn reserve_nt_headers(&mut self, data_directory_num: usize) { - debug_assert_eq!(self.nt_headers_offset, 0); - self.nt_headers_offset = self.reserve(self.nt_headers_size(), 8); - self.data_directories = vec![DataDirectory::default(); data_directory_num]; - self.reserve( - data_directory_num as u32 * mem::size_of::<pe::ImageDataDirectory>() as u32, - 1, - ); - } - - /// Set the virtual address and size of a data directory. - pub fn set_data_directory(&mut self, index: usize, virtual_address: u32, size: u32) { - self.data_directories[index] = DataDirectory { - virtual_address, - size, - } - } - - /// Write the NT headers. - pub fn write_nt_headers(&mut self, nt_headers: NtHeaders) { - self.pad_until(self.nt_headers_offset); - self.buffer.write(&U32::new(LE, pe::IMAGE_NT_SIGNATURE)); - let file_header = pe::ImageFileHeader { - machine: U16::new(LE, nt_headers.machine), - number_of_sections: U16::new(LE, self.section_header_num), - time_date_stamp: U32::new(LE, nt_headers.time_date_stamp), - pointer_to_symbol_table: U32::new(LE, self.symbol_offset), - number_of_symbols: U32::new(LE, self.symbol_num), - size_of_optional_header: U16::new(LE, self.optional_header_size() as u16), - characteristics: U16::new(LE, nt_headers.characteristics), - }; - self.buffer.write(&file_header); - if self.is_64 { - let optional_header = pe::ImageOptionalHeader64 { - magic: U16::new(LE, pe::IMAGE_NT_OPTIONAL_HDR64_MAGIC), - major_linker_version: nt_headers.major_linker_version, - minor_linker_version: nt_headers.minor_linker_version, - size_of_code: U32::new(LE, self.code_len), - size_of_initialized_data: U32::new(LE, self.data_len), - size_of_uninitialized_data: U32::new(LE, self.bss_len), - address_of_entry_point: U32::new(LE, nt_headers.address_of_entry_point), - base_of_code: U32::new(LE, self.code_address), - image_base: U64::new(LE, nt_headers.image_base), - section_alignment: U32::new(LE, self.section_alignment), - file_alignment: U32::new(LE, self.file_alignment), - major_operating_system_version: U16::new( - LE, - nt_headers.major_operating_system_version, - ), - minor_operating_system_version: U16::new( - LE, - nt_headers.minor_operating_system_version, - ), - major_image_version: U16::new(LE, nt_headers.major_image_version), - minor_image_version: U16::new(LE, nt_headers.minor_image_version), - major_subsystem_version: U16::new(LE, nt_headers.major_subsystem_version), - minor_subsystem_version: U16::new(LE, nt_headers.minor_subsystem_version), - win32_version_value: U32::new(LE, 0), - size_of_image: U32::new(LE, self.virtual_len), - size_of_headers: U32::new(LE, self.headers_len), - check_sum: U32::new(LE, 0), - subsystem: U16::new(LE, nt_headers.subsystem), - dll_characteristics: U16::new(LE, nt_headers.dll_characteristics), - size_of_stack_reserve: U64::new(LE, nt_headers.size_of_stack_reserve), - size_of_stack_commit: U64::new(LE, nt_headers.size_of_stack_commit), - size_of_heap_reserve: U64::new(LE, nt_headers.size_of_heap_reserve), - size_of_heap_commit: U64::new(LE, nt_headers.size_of_heap_commit), - loader_flags: U32::new(LE, 0), - number_of_rva_and_sizes: U32::new(LE, self.data_directories.len() as u32), - }; - self.buffer.write(&optional_header); - } else { - let optional_header = pe::ImageOptionalHeader32 { - magic: U16::new(LE, pe::IMAGE_NT_OPTIONAL_HDR32_MAGIC), - major_linker_version: nt_headers.major_linker_version, - minor_linker_version: nt_headers.minor_linker_version, - size_of_code: U32::new(LE, self.code_len), - size_of_initialized_data: U32::new(LE, self.data_len), - size_of_uninitialized_data: U32::new(LE, self.bss_len), - address_of_entry_point: U32::new(LE, nt_headers.address_of_entry_point), - base_of_code: U32::new(LE, self.code_address), - base_of_data: U32::new(LE, self.data_address), - image_base: U32::new(LE, nt_headers.image_base as u32), - section_alignment: U32::new(LE, self.section_alignment), - file_alignment: U32::new(LE, self.file_alignment), - major_operating_system_version: U16::new( - LE, - nt_headers.major_operating_system_version, - ), - minor_operating_system_version: U16::new( - LE, - nt_headers.minor_operating_system_version, - ), - major_image_version: U16::new(LE, nt_headers.major_image_version), - minor_image_version: U16::new(LE, nt_headers.minor_image_version), - major_subsystem_version: U16::new(LE, nt_headers.major_subsystem_version), - minor_subsystem_version: U16::new(LE, nt_headers.minor_subsystem_version), - win32_version_value: U32::new(LE, 0), - size_of_image: U32::new(LE, self.virtual_len), - size_of_headers: U32::new(LE, self.headers_len), - check_sum: U32::new(LE, 0), - subsystem: U16::new(LE, nt_headers.subsystem), - dll_characteristics: U16::new(LE, nt_headers.dll_characteristics), - size_of_stack_reserve: U32::new(LE, nt_headers.size_of_stack_reserve as u32), - size_of_stack_commit: U32::new(LE, nt_headers.size_of_stack_commit as u32), - size_of_heap_reserve: U32::new(LE, nt_headers.size_of_heap_reserve as u32), - size_of_heap_commit: U32::new(LE, nt_headers.size_of_heap_commit as u32), - loader_flags: U32::new(LE, 0), - number_of_rva_and_sizes: U32::new(LE, self.data_directories.len() as u32), - }; - self.buffer.write(&optional_header); - } - - for dir in &self.data_directories { - self.buffer.write(&pe::ImageDataDirectory { - virtual_address: U32::new(LE, dir.virtual_address), - size: U32::new(LE, dir.size), - }) - } - } - - /// Reserve the section headers. - /// - /// The number of reserved section headers must be the same as the number of sections that - /// are later reserved. - // TODO: change this to a maximum number of sections? - pub fn reserve_section_headers(&mut self, section_header_num: u16) { - debug_assert_eq!(self.section_header_num, 0); - self.section_header_num = section_header_num; - self.reserve( - u32::from(section_header_num) * mem::size_of::<pe::ImageSectionHeader>() as u32, - 1, - ); - // Padding before sections must be included in headers_len. - self.reserve_align(self.file_alignment); - self.headers_len = self.len; - self.reserve_virtual(self.len); - } - - /// Write the section headers. - /// - /// This uses information that was recorded when the sections were reserved. - pub fn write_section_headers(&mut self) { - debug_assert_eq!(self.section_header_num as usize, self.sections.len()); - for section in &self.sections { - let section_header = pe::ImageSectionHeader { - name: section.name, - virtual_size: U32::new(LE, section.range.virtual_size), - virtual_address: U32::new(LE, section.range.virtual_address), - size_of_raw_data: U32::new(LE, section.range.file_size), - pointer_to_raw_data: U32::new(LE, section.range.file_offset), - pointer_to_relocations: U32::new(LE, 0), - pointer_to_linenumbers: U32::new(LE, 0), - number_of_relocations: U16::new(LE, 0), - number_of_linenumbers: U16::new(LE, 0), - characteristics: U32::new(LE, section.characteristics), - }; - self.buffer.write(§ion_header); - } - } - - /// Reserve a section. - /// - /// Returns the file range and virtual address range that are reserved - /// for the section. - pub fn reserve_section( - &mut self, - name: [u8; 8], - characteristics: u32, - virtual_size: u32, - data_size: u32, - ) -> SectionRange { - let virtual_address = self.reserve_virtual(virtual_size); - - // Padding after section must be included in section file size. - let file_size = util::align_u32(data_size, self.file_alignment); - let file_offset = if file_size != 0 { - self.reserve(file_size, self.file_alignment) - } else { - 0 - }; - - // Sizes in optional header use the virtual size with the file alignment. - let aligned_virtual_size = util::align_u32(virtual_size, self.file_alignment); - if characteristics & pe::IMAGE_SCN_CNT_CODE != 0 { - if self.code_address == 0 { - self.code_address = virtual_address; - } - self.code_len += aligned_virtual_size; - } else if characteristics & pe::IMAGE_SCN_CNT_INITIALIZED_DATA != 0 { - if self.data_address == 0 { - self.data_address = virtual_address; - } - self.data_len += aligned_virtual_size; - } else if characteristics & pe::IMAGE_SCN_CNT_UNINITIALIZED_DATA != 0 { - if self.data_address == 0 { - self.data_address = virtual_address; - } - self.bss_len += aligned_virtual_size; - } - - let range = SectionRange { - virtual_address, - virtual_size, - file_offset, - file_size, - }; - self.sections.push(Section { - name, - characteristics, - range, - }); - range - } - - /// Write the data for a section. - pub fn write_section(&mut self, offset: u32, data: &[u8]) { - if data.is_empty() { - return; - } - self.pad_until(offset); - self.write(data); - self.write_align(self.file_alignment); - } - - /// Reserve a `.text` section. - /// - /// Contains executable code. - pub fn reserve_text_section(&mut self, size: u32) -> SectionRange { - self.reserve_section( - *b".text\0\0\0", - pe::IMAGE_SCN_CNT_CODE | pe::IMAGE_SCN_MEM_EXECUTE | pe::IMAGE_SCN_MEM_READ, - size, - size, - ) - } - - /// Reserve a `.data` section. - /// - /// Contains initialized data. - /// - /// May also contain uninitialized data if `virtual_size` is greater than `data_size`. - pub fn reserve_data_section(&mut self, virtual_size: u32, data_size: u32) -> SectionRange { - self.reserve_section( - *b".data\0\0\0", - pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ | pe::IMAGE_SCN_MEM_WRITE, - virtual_size, - data_size, - ) - } - - /// Reserve a `.rdata` section. - /// - /// Contains read-only initialized data. - pub fn reserve_rdata_section(&mut self, size: u32) -> SectionRange { - self.reserve_section( - *b".rdata\0\0", - pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ, - size, - size, - ) - } - - /// Reserve a `.bss` section. - /// - /// Contains uninitialized data. - pub fn reserve_bss_section(&mut self, size: u32) -> SectionRange { - self.reserve_section( - *b".bss\0\0\0\0", - pe::IMAGE_SCN_CNT_UNINITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ | pe::IMAGE_SCN_MEM_WRITE, - size, - 0, - ) - } - - /// Reserve an `.idata` section. - /// - /// Contains import tables. Note that it is permissible to store import tables in a different - /// section. - /// - /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_IMPORT` data directory. - pub fn reserve_idata_section(&mut self, size: u32) -> SectionRange { - let range = self.reserve_section( - *b".idata\0\0", - pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ | pe::IMAGE_SCN_MEM_WRITE, - size, - size, - ); - let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_IMPORT]; - debug_assert_eq!(dir.virtual_address, 0); - *dir = DataDirectory { - virtual_address: range.virtual_address, - size, - }; - range - } - - /// Reserve an `.edata` section. - /// - /// Contains export tables. - /// - /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_EXPORT` data directory. - pub fn reserve_edata_section(&mut self, size: u32) -> SectionRange { - let range = self.reserve_section( - *b".edata\0\0", - pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ, - size, - size, - ); - let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_EXPORT]; - debug_assert_eq!(dir.virtual_address, 0); - *dir = DataDirectory { - virtual_address: range.virtual_address, - size, - }; - range - } - - /// Reserve a `.pdata` section. - /// - /// Contains exception information. - /// - /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_EXCEPTION` data directory. - pub fn reserve_pdata_section(&mut self, size: u32) -> SectionRange { - let range = self.reserve_section( - *b".pdata\0\0", - pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ, - size, - size, - ); - let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_EXCEPTION]; - debug_assert_eq!(dir.virtual_address, 0); - *dir = DataDirectory { - virtual_address: range.virtual_address, - size, - }; - range - } - - /// Reserve a `.xdata` section. - /// - /// Contains exception information. - pub fn reserve_xdata_section(&mut self, size: u32) -> SectionRange { - self.reserve_section( - *b".xdata\0\0", - pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ, - size, - size, - ) - } - - /// Reserve a `.rsrc` section. - /// - /// Contains the resource directory. - /// - /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_RESOURCE` data directory. - pub fn reserve_rsrc_section(&mut self, size: u32) -> SectionRange { - let range = self.reserve_section( - *b".rsrc\0\0\0", - pe::IMAGE_SCN_CNT_INITIALIZED_DATA | pe::IMAGE_SCN_MEM_READ, - size, - size, - ); - let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_RESOURCE]; - debug_assert_eq!(dir.virtual_address, 0); - *dir = DataDirectory { - virtual_address: range.virtual_address, - size, - }; - range - } - - /// Add a base relocation. - /// - /// `typ` must be one of the `IMAGE_REL_BASED_*` constants. - pub fn add_reloc(&mut self, mut virtual_address: u32, typ: u16) { - let reloc = U16::new(LE, typ << 12 | (virtual_address & 0xfff) as u16); - virtual_address &= !0xfff; - if let Some(block) = self.reloc_blocks.last_mut() { - if block.virtual_address == virtual_address { - self.relocs.push(reloc); - block.count += 1; - return; - } - // Blocks must have an even number of relocations. - if block.count & 1 != 0 { - self.relocs.push(U16::new(LE, 0)); - block.count += 1; - } - debug_assert!(block.virtual_address < virtual_address); - } - self.relocs.push(reloc); - self.reloc_blocks.push(RelocBlock { - virtual_address, - count: 1, - }); - } - - /// Return true if a base relocation has been added. - pub fn has_relocs(&mut self) -> bool { - !self.relocs.is_empty() - } - - /// Reserve a `.reloc` section. - /// - /// This contains the base relocations that were added with `add_reloc`. - /// - /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_BASERELOC` data directory. - pub fn reserve_reloc_section(&mut self) -> SectionRange { - if let Some(block) = self.reloc_blocks.last_mut() { - // Blocks must have an even number of relocations. - if block.count & 1 != 0 { - self.relocs.push(U16::new(LE, 0)); - block.count += 1; - } - } - let size = self.reloc_blocks.iter().map(RelocBlock::size).sum(); - let range = self.reserve_section( - *b".reloc\0\0", - pe::IMAGE_SCN_CNT_INITIALIZED_DATA - | pe::IMAGE_SCN_MEM_READ - | pe::IMAGE_SCN_MEM_DISCARDABLE, - size, - size, - ); - let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_BASERELOC]; - debug_assert_eq!(dir.virtual_address, 0); - *dir = DataDirectory { - virtual_address: range.virtual_address, - size, - }; - self.reloc_offset = range.file_offset; - range - } - - /// Write a `.reloc` section. - /// - /// This contains the base relocations that were added with `add_reloc`. - pub fn write_reloc_section(&mut self) { - if self.reloc_offset == 0 { - return; - } - self.pad_until(self.reloc_offset); - - let mut total = 0; - for block in &self.reloc_blocks { - self.buffer.write(&pe::ImageBaseRelocation { - virtual_address: U32::new(LE, block.virtual_address), - size_of_block: U32::new(LE, block.size()), - }); - self.buffer - .write_slice(&self.relocs[total..][..block.count as usize]); - total += block.count as usize; - } - debug_assert_eq!(total, self.relocs.len()); - - self.write_align(self.file_alignment); - } - - /// Reserve the certificate table. - /// - /// This also sets the `pe::IMAGE_DIRECTORY_ENTRY_SECURITY` data directory. - // TODO: reserve individual certificates - pub fn reserve_certificate_table(&mut self, size: u32) { - let size = util::align_u32(size, 8); - let offset = self.reserve(size, 8); - let dir = &mut self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_SECURITY]; - debug_assert_eq!(dir.virtual_address, 0); - *dir = DataDirectory { - virtual_address: offset, - size, - }; - } - - /// Write the certificate table. - // TODO: write individual certificates - pub fn write_certificate_table(&mut self, data: &[u8]) { - let dir = self.data_directories[pe::IMAGE_DIRECTORY_ENTRY_SECURITY]; - self.pad_until(dir.virtual_address); - self.write(data); - self.pad_until(dir.virtual_address + dir.size); - } -} - -/// Information required for writing [`pe::ImageNtHeaders32`] or [`pe::ImageNtHeaders64`]. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub struct NtHeaders { - // ImageFileHeader - pub machine: u16, - pub time_date_stamp: u32, - pub characteristics: u16, - // ImageOptionalHeader - pub major_linker_version: u8, - pub minor_linker_version: u8, - pub address_of_entry_point: u32, - pub image_base: u64, - pub major_operating_system_version: u16, - pub minor_operating_system_version: u16, - pub major_image_version: u16, - pub minor_image_version: u16, - pub major_subsystem_version: u16, - pub minor_subsystem_version: u16, - pub subsystem: u16, - pub dll_characteristics: u16, - pub size_of_stack_reserve: u64, - pub size_of_stack_commit: u64, - pub size_of_heap_reserve: u64, - pub size_of_heap_commit: u64, -} - -#[derive(Default, Clone, Copy)] -struct DataDirectory { - virtual_address: u32, - size: u32, -} - -/// Information required for writing [`pe::ImageSectionHeader`]. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub struct Section { - pub name: [u8; pe::IMAGE_SIZEOF_SHORT_NAME], - pub characteristics: u32, - pub range: SectionRange, -} - -/// The file range and virtual address range for a section. -#[allow(missing_docs)] -#[derive(Debug, Default, Clone, Copy)] -pub struct SectionRange { - pub virtual_address: u32, - pub virtual_size: u32, - pub file_offset: u32, - pub file_size: u32, -} - -struct RelocBlock { - virtual_address: u32, - count: u32, -} - -impl RelocBlock { - fn size(&self) -> u32 { - mem::size_of::<pe::ImageBaseRelocation>() as u32 + self.count * mem::size_of::<u16>() as u32 - } -} diff --git a/vendor/object/src/write/string.rs b/vendor/object/src/write/string.rs deleted file mode 100644 index b23274a..0000000 --- a/vendor/object/src/write/string.rs +++ /dev/null @@ -1,159 +0,0 @@ -use alloc::vec::Vec; - -#[cfg(feature = "std")] -type IndexSet<K> = indexmap::IndexSet<K>; -#[cfg(not(feature = "std"))] -type IndexSet<K> = indexmap::IndexSet<K, hashbrown::hash_map::DefaultHashBuilder>; - -/// An identifier for an entry in a string table. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct StringId(usize); - -#[derive(Debug, Default)] -pub(crate) struct StringTable<'a> { - strings: IndexSet<&'a [u8]>, - offsets: Vec<usize>, -} - -impl<'a> StringTable<'a> { - /// Add a string to the string table. - /// - /// Panics if the string table has already been written, or - /// if the string contains a null byte. - pub fn add(&mut self, string: &'a [u8]) -> StringId { - assert!(self.offsets.is_empty()); - assert!(!string.contains(&0)); - let id = self.strings.insert_full(string).0; - StringId(id) - } - - /// Return the id of the given string. - /// - /// Panics if the string is not in the string table. - pub fn get_id(&self, string: &[u8]) -> StringId { - let id = self.strings.get_index_of(string).unwrap(); - StringId(id) - } - - /// Return the string for the given id. - /// - /// Panics if the string is not in the string table. - pub fn get_string(&self, id: StringId) -> &'a [u8] { - self.strings.get_index(id.0).unwrap() - } - - /// Return the offset of the given string. - /// - /// Panics if the string table has not been written, or - /// if the string is not in the string table. - pub fn get_offset(&self, id: StringId) -> usize { - self.offsets[id.0] - } - - /// Append the string table to the given `Vec`, and - /// calculate the list of string offsets. - /// - /// `base` is the initial string table offset. For example, - /// this should be 1 for ELF, to account for the initial - /// null byte (which must have been written by the caller). - pub fn write(&mut self, base: usize, w: &mut Vec<u8>) { - assert!(self.offsets.is_empty()); - - let mut ids: Vec<_> = (0..self.strings.len()).collect(); - sort(&mut ids, 1, &self.strings); - - self.offsets = vec![0; ids.len()]; - let mut offset = base; - let mut previous = &[][..]; - for id in ids { - let string = self.strings.get_index(id).unwrap(); - if previous.ends_with(string) { - self.offsets[id] = offset - string.len() - 1; - } else { - self.offsets[id] = offset; - w.extend_from_slice(string); - w.push(0); - offset += string.len() + 1; - previous = string; - } - } - } -} - -// Multi-key quicksort. -// -// Ordering is such that if a string is a suffix of at least one other string, -// then it is placed immediately after one of those strings. That is: -// - comparison starts at the end of the string -// - shorter strings come later -// -// Based on the implementation in LLVM. -fn sort(mut ids: &mut [usize], mut pos: usize, strings: &IndexSet<&[u8]>) { - loop { - if ids.len() <= 1 { - return; - } - - let pivot = byte(ids[0], pos, strings); - let mut lower = 0; - let mut upper = ids.len(); - let mut i = 1; - while i < upper { - let b = byte(ids[i], pos, strings); - if b > pivot { - ids.swap(lower, i); - lower += 1; - i += 1; - } else if b < pivot { - upper -= 1; - ids.swap(upper, i); - } else { - i += 1; - } - } - - sort(&mut ids[..lower], pos, strings); - sort(&mut ids[upper..], pos, strings); - - if pivot == 0 { - return; - } - ids = &mut ids[lower..upper]; - pos += 1; - } -} - -fn byte(id: usize, pos: usize, strings: &IndexSet<&[u8]>) -> u8 { - let string = strings.get_index(id).unwrap(); - let len = string.len(); - if len >= pos { - string[len - pos] - } else { - // We know the strings don't contain null bytes. - 0 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn string_table() { - let mut table = StringTable::default(); - let id0 = table.add(b""); - let id1 = table.add(b"foo"); - let id2 = table.add(b"bar"); - let id3 = table.add(b"foobar"); - - let mut data = Vec::new(); - data.push(0); - table.write(1, &mut data); - assert_eq!(data, b"\0foobar\0foo\0"); - - assert_eq!(table.get_offset(id0), 11); - assert_eq!(table.get_offset(id1), 8); - assert_eq!(table.get_offset(id2), 4); - assert_eq!(table.get_offset(id3), 1); - } -} diff --git a/vendor/object/src/write/util.rs b/vendor/object/src/write/util.rs deleted file mode 100644 index f7ee2f4..0000000 --- a/vendor/object/src/write/util.rs +++ /dev/null @@ -1,260 +0,0 @@ -use alloc::vec::Vec; -#[cfg(feature = "std")] -use std::{io, mem}; - -use crate::pod::{bytes_of, bytes_of_slice, Pod}; - -/// Trait for writable buffer. -#[allow(clippy::len_without_is_empty)] -pub trait WritableBuffer { - /// Returns position/offset for data to be written at. - /// - /// Should only be used in debug assertions - fn len(&self) -> usize; - - /// Reserves specified number of bytes in the buffer. - /// - /// This will be called exactly once before writing anything to the buffer, - /// and the given size is the exact total number of bytes that will be written. - fn reserve(&mut self, size: usize) -> Result<(), ()>; - - /// Writes zero bytes at the end of the buffer until the buffer - /// has the specified length. - fn resize(&mut self, new_len: usize); - - /// Writes the specified slice of bytes at the end of the buffer. - fn write_bytes(&mut self, val: &[u8]); - - /// Writes the specified `Pod` type at the end of the buffer. - fn write_pod<T: Pod>(&mut self, val: &T) - where - Self: Sized, - { - self.write_bytes(bytes_of(val)) - } - - /// Writes the specified `Pod` slice at the end of the buffer. - fn write_pod_slice<T: Pod>(&mut self, val: &[T]) - where - Self: Sized, - { - self.write_bytes(bytes_of_slice(val)) - } -} - -impl<'a> dyn WritableBuffer + 'a { - /// Writes the specified `Pod` type at the end of the buffer. - pub fn write<T: Pod>(&mut self, val: &T) { - self.write_bytes(bytes_of(val)) - } - - /// Writes the specified `Pod` slice at the end of the buffer. - pub fn write_slice<T: Pod>(&mut self, val: &[T]) { - self.write_bytes(bytes_of_slice(val)) - } -} - -impl WritableBuffer for Vec<u8> { - #[inline] - fn len(&self) -> usize { - self.len() - } - - #[inline] - fn reserve(&mut self, size: usize) -> Result<(), ()> { - debug_assert!(self.is_empty()); - self.reserve(size); - Ok(()) - } - - #[inline] - fn resize(&mut self, new_len: usize) { - debug_assert!(new_len >= self.len()); - self.resize(new_len, 0); - } - - #[inline] - fn write_bytes(&mut self, val: &[u8]) { - debug_assert!(self.len() + val.len() <= self.capacity()); - self.extend_from_slice(val) - } -} - -/// A [`WritableBuffer`] that streams data to a [`Write`](std::io::Write) implementation. -/// -/// [`Self::result`] must be called to determine if an I/O error occurred during writing. -/// -/// 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")] -#[derive(Debug)] -pub struct StreamingBuffer<W> { - writer: W, - len: usize, - result: Result<(), io::Error>, -} - -#[cfg(feature = "std")] -impl<W> StreamingBuffer<W> { - /// Create a new `StreamingBuffer` backed by the given writer. - pub fn new(writer: W) -> Self { - StreamingBuffer { - writer, - len: 0, - result: Ok(()), - } - } - - /// Unwraps this [`StreamingBuffer`] giving back the original writer. - pub fn into_inner(self) -> W { - self.writer - } - - /// Returns any error that occurred during writing. - pub fn result(&mut self) -> Result<(), io::Error> { - mem::replace(&mut self.result, Ok(())) - } -} - -#[cfg(feature = "std")] -impl<W: io::Write> WritableBuffer for StreamingBuffer<W> { - #[inline] - fn len(&self) -> usize { - self.len - } - - #[inline] - fn reserve(&mut self, _size: usize) -> Result<(), ()> { - Ok(()) - } - - #[inline] - fn resize(&mut self, new_len: usize) { - debug_assert!(self.len <= new_len); - while self.len < new_len { - let write_amt = (new_len - self.len - 1) % 1024 + 1; - self.write_bytes(&[0; 1024][..write_amt]); - } - } - - #[inline] - fn write_bytes(&mut self, val: &[u8]) { - if self.result.is_ok() { - self.result = self.writer.write_all(val); - } - self.len += val.len(); - } -} - -/// A trait for mutable byte slices. -/// -/// It provides convenience methods for `Pod` types. -pub(crate) trait BytesMut { - fn write_at<T: Pod>(self, offset: usize, val: &T) -> Result<(), ()>; -} - -impl<'a> BytesMut for &'a mut [u8] { - #[inline] - fn write_at<T: Pod>(self, offset: usize, val: &T) -> Result<(), ()> { - let src = bytes_of(val); - let dest = self.get_mut(offset..).ok_or(())?; - let dest = dest.get_mut(..src.len()).ok_or(())?; - dest.copy_from_slice(src); - Ok(()) - } -} - -/// Write an unsigned number using the LEB128 encoding to a buffer. -/// -/// Returns the number of bytes written. -pub(crate) fn write_uleb128(buf: &mut Vec<u8>, mut val: u64) -> usize { - let mut len = 0; - loop { - let mut byte = (val & 0x7f) as u8; - val >>= 7; - let done = val == 0; - if !done { - byte |= 0x80; - } - - buf.push(byte); - len += 1; - - if done { - return len; - } - } -} - -/// Write a signed number using the LEB128 encoding to a buffer. -/// -/// Returns the number of bytes written. -#[allow(dead_code)] -pub(crate) fn write_sleb128(buf: &mut Vec<u8>, mut val: i64) -> usize { - let mut len = 0; - loop { - let mut byte = val as u8; - // Keep the sign bit for testing - val >>= 6; - let done = val == 0 || val == -1; - if done { - byte &= !0x80; - } else { - // Remove the sign bit - val >>= 1; - byte |= 0x80; - } - - buf.push(byte); - len += 1; - - if done { - return len; - } - } -} - -pub(crate) fn align(offset: usize, size: usize) -> usize { - (offset + (size - 1)) & !(size - 1) -} - -#[allow(dead_code)] -pub(crate) fn align_u32(offset: u32, size: u32) -> u32 { - (offset + (size - 1)) & !(size - 1) -} - -#[allow(dead_code)] -pub(crate) fn align_u64(offset: u64, size: u64) -> u64 { - (offset + (size - 1)) & !(size - 1) -} - -pub(crate) fn write_align(buffer: &mut dyn WritableBuffer, size: usize) { - let new_len = align(buffer.len(), size); - buffer.resize(new_len); -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn bytes_mut() { - let data = vec![0x01, 0x23, 0x45, 0x67]; - - let mut bytes = data.clone(); - bytes.extend_from_slice(bytes_of(&u16::to_be(0x89ab))); - assert_eq!(bytes, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab]); - - let mut bytes = data.clone(); - assert_eq!(bytes.write_at(0, &u16::to_be(0x89ab)), Ok(())); - assert_eq!(bytes, [0x89, 0xab, 0x45, 0x67]); - - let mut bytes = data.clone(); - assert_eq!(bytes.write_at(2, &u16::to_be(0x89ab)), Ok(())); - assert_eq!(bytes, [0x01, 0x23, 0x89, 0xab]); - - assert_eq!(bytes.write_at(3, &u16::to_be(0x89ab)), Err(())); - assert_eq!(bytes.write_at(4, &u16::to_be(0x89ab)), Err(())); - assert_eq!(vec![].write_at(0, &u32::to_be(0x89ab)), Err(())); - } -} diff --git a/vendor/object/src/write/xcoff.rs b/vendor/object/src/write/xcoff.rs deleted file mode 100644 index fc58886..0000000 --- a/vendor/object/src/write/xcoff.rs +++ /dev/null @@ -1,556 +0,0 @@ -use core::mem; - -use crate::endian::{BigEndian as BE, I16, U16, U32}; -use crate::write::string::*; -use crate::write::util::*; -use crate::write::*; - -use crate::{xcoff, AddressSize}; - -#[derive(Default, Clone, Copy)] -struct SectionOffsets { - address: u64, - data_offset: usize, - reloc_offset: usize, -} - -#[derive(Default, Clone, Copy)] -struct SymbolOffsets { - index: usize, - str_id: Option<StringId>, - aux_count: u8, - storage_class: u8, -} - -impl<'a> Object<'a> { - pub(crate) fn xcoff_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, - ), - StandardSection::Tls => (&[], &b".tdata"[..], SectionKind::Tls, SectionFlags::None), - StandardSection::UninitializedTls => ( - &[], - &b".tbss"[..], - 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 xcoff_fixup_relocation(&mut self, relocation: &mut Relocation) -> i64 { - let constant = match relocation.kind { - RelocationKind::Relative => relocation.addend + 4, - _ => relocation.addend, - }; - relocation.addend -= constant; - constant - } - - pub(crate) fn xcoff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { - let is_64 = match self.architecture.address_size().unwrap() { - AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => false, - AddressSize::U64 => true, - }; - - let (hdr_size, sechdr_size, rel_size, sym_size) = if is_64 { - ( - mem::size_of::<xcoff::FileHeader64>(), - mem::size_of::<xcoff::SectionHeader64>(), - mem::size_of::<xcoff::Rel64>(), - mem::size_of::<xcoff::Symbol64>(), - ) - } else { - ( - mem::size_of::<xcoff::FileHeader32>(), - mem::size_of::<xcoff::SectionHeader32>(), - mem::size_of::<xcoff::Rel32>(), - mem::size_of::<xcoff::Symbol32>(), - ) - }; - - // Calculate offsets and build strtab. - let mut offset = 0; - let mut strtab = StringTable::default(); - // We place the shared address 0 immediately after the section header table. - let mut address = 0; - - // XCOFF file header. - offset += hdr_size; - // Section headers. - offset += self.sections.len() * sechdr_size; - - // Calculate size of section data. - let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()]; - for (index, section) in self.sections.iter().enumerate() { - let len = section.data.len(); - let sectype = section.kind; - // Section address should be 0 for all sections except the .text, .data, and .bss sections. - if sectype == SectionKind::Data - || sectype == SectionKind::Text - || sectype == SectionKind::UninitializedData - { - section_offsets[index].address = address as u64; - address += len; - address = align(address, 4); - } else { - section_offsets[index].address = 0; - } - if len != 0 { - // Set the default section alignment as 4. - offset = align(offset, 4); - section_offsets[index].data_offset = offset; - offset += len; - } else { - section_offsets[index].data_offset = 0; - } - } - - // Calculate size of relocations. - for (index, section) in self.sections.iter().enumerate() { - let count = section.relocations.len(); - if count != 0 { - section_offsets[index].reloc_offset = offset; - offset += count * rel_size; - } else { - section_offsets[index].reloc_offset = 0; - } - } - - // Calculate size of symbols. - let mut file_str_id = None; - let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; - let mut symtab_count = 0; - for (index, symbol) in self.symbols.iter().enumerate() { - symbol_offsets[index].index = symtab_count; - symtab_count += 1; - - let storage_class = if let SymbolFlags::Xcoff { n_sclass, .. } = symbol.flags { - n_sclass - } else { - match symbol.kind { - SymbolKind::Null => xcoff::C_NULL, - SymbolKind::File => xcoff::C_FILE, - SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => { - if symbol.is_local() { - xcoff::C_STAT - } else if symbol.weak { - xcoff::C_WEAKEXT - } else { - xcoff::C_EXT - } - } - SymbolKind::Section | SymbolKind::Label | SymbolKind::Unknown => { - return Err(Error(format!( - "unimplemented symbol `{}` kind {:?}", - symbol.name().unwrap_or(""), - symbol.kind - ))); - } - } - }; - symbol_offsets[index].storage_class = storage_class; - - if storage_class == xcoff::C_FILE { - if is_64 && file_str_id.is_none() { - file_str_id = Some(strtab.add(b".file")); - } - if symbol.name.len() > 8 { - symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); - } - } else if is_64 || symbol.name.len() > 8 { - symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); - } - - symbol_offsets[index].aux_count = 0; - match storage_class { - xcoff::C_FILE => { - symbol_offsets[index].aux_count = 1; - symtab_count += 1; - } - xcoff::C_EXT | xcoff::C_WEAKEXT | xcoff::C_HIDEXT => { - symbol_offsets[index].aux_count = 1; - symtab_count += 1; - } - // TODO: support auxiliary entry for other types of symbol. - _ => {} - } - } - let symtab_offset = offset; - let symtab_len = symtab_count * sym_size; - offset += symtab_len; - - // Calculate size of strtab. - let strtab_offset = offset; - let mut strtab_data = Vec::new(); - // First 4 bytes of strtab are the length. - strtab.write(4, &mut strtab_data); - let strtab_len = strtab_data.len() + 4; - offset += strtab_len; - - // Start writing. - buffer - .reserve(offset) - .map_err(|_| Error(String::from("Cannot allocate buffer")))?; - - // Write file header. - if is_64 { - let header = xcoff::FileHeader64 { - f_magic: U16::new(BE, xcoff::MAGIC_64), - f_nscns: U16::new(BE, self.sections.len() as u16), - f_timdat: U32::new(BE, 0), - f_symptr: U64::new(BE, symtab_offset as u64), - f_nsyms: U32::new(BE, symtab_count as u32), - f_opthdr: U16::new(BE, 0), - f_flags: match self.flags { - FileFlags::Xcoff { f_flags } => U16::new(BE, f_flags), - _ => U16::default(), - }, - }; - buffer.write(&header); - } else { - let header = xcoff::FileHeader32 { - f_magic: U16::new(BE, xcoff::MAGIC_32), - f_nscns: U16::new(BE, self.sections.len() as u16), - f_timdat: U32::new(BE, 0), - f_symptr: U32::new(BE, symtab_offset as u32), - f_nsyms: U32::new(BE, symtab_count as u32), - f_opthdr: U16::new(BE, 0), - f_flags: match self.flags { - FileFlags::Xcoff { f_flags } => U16::new(BE, f_flags), - _ => U16::default(), - }, - }; - buffer.write(&header); - } - - // Write section headers. - for (index, section) in self.sections.iter().enumerate() { - let mut sectname = [0; 8]; - sectname - .get_mut(..section.name.len()) - .ok_or_else(|| { - Error(format!( - "section name `{}` is too long", - section.name().unwrap_or(""), - )) - })? - .copy_from_slice(§ion.name); - let flags = if let SectionFlags::Xcoff { s_flags } = section.flags { - s_flags - } else { - match section.kind { - SectionKind::Text - | SectionKind::ReadOnlyData - | SectionKind::ReadOnlyString - | SectionKind::ReadOnlyDataWithRel => xcoff::STYP_TEXT, - SectionKind::Data => xcoff::STYP_DATA, - SectionKind::UninitializedData => xcoff::STYP_BSS, - SectionKind::Tls => xcoff::STYP_TDATA, - SectionKind::UninitializedTls => xcoff::STYP_TBSS, - SectionKind::OtherString => xcoff::STYP_INFO, - SectionKind::Debug => xcoff::STYP_DEBUG, - SectionKind::Other | SectionKind::Metadata => 0, - SectionKind::Note - | SectionKind::Linker - | SectionKind::Common - | SectionKind::Unknown - | SectionKind::TlsVariables - | SectionKind::Elf(_) => { - return Err(Error(format!( - "unimplemented section `{}` kind {:?}", - section.name().unwrap_or(""), - section.kind - ))); - } - } - .into() - }; - if is_64 { - let section_header = xcoff::SectionHeader64 { - s_name: sectname, - s_paddr: U64::new(BE, section_offsets[index].address), - // This field has the same value as the s_paddr field. - s_vaddr: U64::new(BE, section_offsets[index].address), - s_size: U64::new(BE, section.data.len() as u64), - s_scnptr: U64::new(BE, section_offsets[index].data_offset as u64), - s_relptr: U64::new(BE, section_offsets[index].reloc_offset as u64), - s_lnnoptr: U64::new(BE, 0), - s_nreloc: U32::new(BE, section.relocations.len() as u32), - s_nlnno: U32::new(BE, 0), - s_flags: U32::new(BE, flags), - s_reserve: U32::new(BE, 0), - }; - buffer.write(§ion_header); - } else { - let section_header = xcoff::SectionHeader32 { - s_name: sectname, - s_paddr: U32::new(BE, section_offsets[index].address as u32), - // This field has the same value as the s_paddr field. - s_vaddr: U32::new(BE, section_offsets[index].address as u32), - s_size: U32::new(BE, section.data.len() as u32), - s_scnptr: U32::new(BE, section_offsets[index].data_offset as u32), - s_relptr: U32::new(BE, section_offsets[index].reloc_offset as u32), - s_lnnoptr: U32::new(BE, 0), - // TODO: If more than 65,534 relocation entries are required, the field - // value will be 65535, and an STYP_OVRFLO section header will contain - // the actual count of relocation entries in the s_paddr field. - s_nreloc: U16::new(BE, section.relocations.len() as u16), - s_nlnno: U16::new(BE, 0), - s_flags: U32::new(BE, flags), - }; - buffer.write(§ion_header); - } - } - - // Write section data. - for (index, section) in self.sections.iter().enumerate() { - let len = section.data.len(); - if len != 0 { - write_align(buffer, 4); - debug_assert_eq!(section_offsets[index].data_offset, buffer.len()); - buffer.write_bytes(§ion.data); - } - } - - // Write relocations. - for (index, section) in self.sections.iter().enumerate() { - if !section.relocations.is_empty() { - debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); - for reloc in §ion.relocations { - let rtype = match reloc.kind { - RelocationKind::Absolute => xcoff::R_POS, - RelocationKind::Relative => xcoff::R_REL, - RelocationKind::Got => xcoff::R_TOC, - RelocationKind::Xcoff(x) => x, - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); - } - }; - if is_64 { - let xcoff_rel = xcoff::Rel64 { - r_vaddr: U64::new(BE, reloc.offset), - r_symndx: U32::new(BE, symbol_offsets[reloc.symbol.0].index as u32), - // Specifies the bit length of the relocatable reference minus one. - r_rsize: (reloc.size - 1), - r_rtype: rtype, - }; - buffer.write(&xcoff_rel); - } else { - let xcoff_rel = xcoff::Rel32 { - r_vaddr: U32::new(BE, reloc.offset as u32), - r_symndx: U32::new(BE, symbol_offsets[reloc.symbol.0].index as u32), - r_rsize: (reloc.size - 1), - r_rtype: rtype, - }; - buffer.write(&xcoff_rel); - } - } - } - } - - // Write symbols. - debug_assert_eq!(symtab_offset, buffer.len()); - for (index, symbol) in self.symbols.iter().enumerate() { - let (n_value, section_kind) = if let SymbolSection::Section(id) = symbol.section { - ( - section_offsets[id.0].address + symbol.value, - self.sections[id.0].kind, - ) - } else { - (symbol.value, SectionKind::Unknown) - }; - let n_scnum = match symbol.section { - SymbolSection::None => { - debug_assert_eq!(symbol.kind, SymbolKind::File); - xcoff::N_DEBUG - } - SymbolSection::Undefined | SymbolSection::Common => xcoff::N_UNDEF, - SymbolSection::Absolute => xcoff::N_ABS, - SymbolSection::Section(id) => id.0 as i16 + 1, - }; - let n_sclass = symbol_offsets[index].storage_class; - let n_type = if (symbol.scope == SymbolScope::Linkage) - && (n_sclass == xcoff::C_EXT - || n_sclass == xcoff::C_WEAKEXT - || n_sclass == xcoff::C_HIDEXT) - { - xcoff::SYM_V_HIDDEN - } else { - 0 - }; - let n_numaux = symbol_offsets[index].aux_count; - if is_64 { - let str_id = if n_sclass == xcoff::C_FILE { - file_str_id.unwrap() - } else { - symbol_offsets[index].str_id.unwrap() - }; - let xcoff_sym = xcoff::Symbol64 { - n_value: U64::new(BE, n_value), - n_offset: U32::new(BE, strtab.get_offset(str_id) as u32), - n_scnum: I16::new(BE, n_scnum), - n_type: U16::new(BE, n_type), - n_sclass, - n_numaux, - }; - buffer.write(&xcoff_sym); - } else { - let mut sym_name = [0; 8]; - if n_sclass == xcoff::C_FILE { - sym_name[..5].copy_from_slice(b".file"); - } else if symbol.name.len() <= 8 { - sym_name[..symbol.name.len()].copy_from_slice(&symbol.name[..]); - } else { - let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap()); - sym_name[4..8].copy_from_slice(&u32::to_be_bytes(str_offset as u32)); - } - let xcoff_sym = xcoff::Symbol32 { - n_name: sym_name, - n_value: U32::new(BE, n_value as u32), - n_scnum: I16::new(BE, n_scnum), - n_type: U16::new(BE, n_type), - n_sclass, - n_numaux, - }; - buffer.write(&xcoff_sym); - } - // Generate auxiliary entries. - if n_sclass == xcoff::C_FILE { - debug_assert_eq!(n_numaux, 1); - let mut x_fname = [0; 8]; - if symbol.name.len() <= 8 { - x_fname[..symbol.name.len()].copy_from_slice(&symbol.name[..]); - } else { - let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap()); - x_fname[4..8].copy_from_slice(&u32::to_be_bytes(str_offset as u32)); - } - if is_64 { - let file_aux = xcoff::FileAux64 { - x_fname, - x_fpad: Default::default(), - x_ftype: xcoff::XFT_FN, - x_freserve: Default::default(), - x_auxtype: xcoff::AUX_FILE, - }; - buffer.write(&file_aux); - } else { - let file_aux = xcoff::FileAux32 { - x_fname, - x_fpad: Default::default(), - x_ftype: xcoff::XFT_FN, - x_freserve: Default::default(), - }; - buffer.write(&file_aux); - } - } else if n_sclass == xcoff::C_EXT - || n_sclass == xcoff::C_WEAKEXT - || n_sclass == xcoff::C_HIDEXT - { - debug_assert_eq!(n_numaux, 1); - let (x_smtyp, x_smclas) = if let SymbolFlags::Xcoff { - x_smtyp, x_smclas, .. - } = symbol.flags - { - (x_smtyp, x_smclas) - } else { - match symbol.kind { - SymbolKind::Text => (xcoff::XTY_SD, xcoff::XMC_PR), - SymbolKind::Data => { - if section_kind == SectionKind::UninitializedData { - (xcoff::XTY_CM, xcoff::XMC_BS) - } else if section_kind == SectionKind::ReadOnlyData { - (xcoff::XTY_SD, xcoff::XMC_RO) - } else { - (xcoff::XTY_SD, xcoff::XMC_RW) - } - } - SymbolKind::Tls => { - if section_kind == SectionKind::UninitializedTls { - (xcoff::XTY_CM, xcoff::XMC_UL) - } else { - (xcoff::XTY_SD, xcoff::XMC_TL) - } - } - _ => { - return Err(Error(format!( - "unimplemented symbol `{}` kind {:?}", - symbol.name().unwrap_or(""), - symbol.kind - ))); - } - } - }; - let scnlen = if let SymbolFlags::Xcoff { - containing_csect: Some(containing_csect), - .. - } = symbol.flags - { - symbol_offsets[containing_csect.0].index as u64 - } else { - symbol.size - }; - if is_64 { - let csect_aux = xcoff::CsectAux64 { - x_scnlen_lo: U32::new(BE, (scnlen & 0xFFFFFFFF) as u32), - x_scnlen_hi: U32::new(BE, ((scnlen >> 32) & 0xFFFFFFFF) as u32), - x_parmhash: U32::new(BE, 0), - x_snhash: U16::new(BE, 0), - x_smtyp, - x_smclas, - pad: 0, - x_auxtype: xcoff::AUX_CSECT, - }; - buffer.write(&csect_aux); - } else { - let csect_aux = xcoff::CsectAux32 { - x_scnlen: U32::new(BE, scnlen as u32), - x_parmhash: U32::new(BE, 0), - x_snhash: U16::new(BE, 0), - x_smtyp, - x_smclas, - x_stab: U32::new(BE, 0), - x_snstab: U16::new(BE, 0), - }; - buffer.write(&csect_aux); - } - } - } - - // Write string table. - debug_assert_eq!(strtab_offset, buffer.len()); - buffer.write_bytes(&u32::to_be_bytes(strtab_len as u32)); - buffer.write_bytes(&strtab_data); - - debug_assert_eq!(offset, buffer.len()); - Ok(()) - } -} |