summaryrefslogtreecommitdiffstats
path: root/vendor/object-0.26.2/src/write
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/object-0.26.2/src/write')
-rw-r--r--vendor/object-0.26.2/src/write/coff.rs626
-rw-r--r--vendor/object-0.26.2/src/write/elf.rs1314
-rw-r--r--vendor/object-0.26.2/src/write/macho.rs844
-rw-r--r--vendor/object-0.26.2/src/write/mod.rs858
-rw-r--r--vendor/object-0.26.2/src/write/string.rs139
-rw-r--r--vendor/object-0.26.2/src/write/util.rs129
6 files changed, 3910 insertions, 0 deletions
diff --git a/vendor/object-0.26.2/src/write/coff.rs b/vendor/object-0.26.2/src/write/coff.rs
new file mode 100644
index 000000000..c8516c102
--- /dev/null
+++ b/vendor/object-0.26.2/src/write/coff.rs
@@ -0,0 +1,626 @@
+use std::mem;
+use std::vec::Vec;
+
+use crate::endian::{LittleEndian as LE, U16Bytes, U32Bytes, U16, U32};
+use crate::pe as coff;
+use crate::write::string::*;
+use crate::write::util::*;
+use crate::write::*;
+
+#[derive(Default, Clone, Copy)]
+struct SectionOffsets {
+ offset: usize,
+ str_id: Option<StringId>,
+ reloc_offset: usize,
+ selection: u8,
+ associative_section: u16,
+}
+
+#[derive(Default, Clone, Copy)]
+struct SymbolOffsets {
+ index: usize,
+ str_id: Option<StringId>,
+ aux_count: u8,
+}
+
+impl Object {
+ pub(crate) fn coff_section_info(
+ &self,
+ section: StandardSection,
+ ) -> (&'static [u8], &'static [u8], SectionKind) {
+ match section {
+ StandardSection::Text => (&[], &b".text"[..], SectionKind::Text),
+ StandardSection::Data => (&[], &b".data"[..], SectionKind::Data),
+ StandardSection::ReadOnlyData
+ | StandardSection::ReadOnlyDataWithRel
+ | StandardSection::ReadOnlyString => (&[], &b".rdata"[..], SectionKind::ReadOnlyData),
+ StandardSection::UninitializedData => {
+ (&[], &b".bss"[..], SectionKind::UninitializedData)
+ }
+ // TLS sections are data sections with a special name.
+ StandardSection::Tls => (&[], &b".tls$"[..], SectionKind::Data),
+ StandardSection::UninitializedTls => {
+ // Unsupported section.
+ (&[], &[], SectionKind::UninitializedTls)
+ }
+ StandardSection::TlsVariables => {
+ // Unsupported section.
+ (&[], &[], SectionKind::TlsVariables)
+ }
+ StandardSection::Common => {
+ // Unsupported section.
+ (&[], &[], SectionKind::Common)
+ }
+ }
+ }
+
+ 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, mut 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 => match relocation.kind {
+ RelocationKind::Relative => {
+ // IMAGE_REL_I386_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 mut name = b".rdata$.refptr.".to_vec();
+ name.extend_from_slice(&self.symbols[symbol_id.0].name);
+ 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
+ }
+
+ pub(crate) fn coff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
+ // Calculate offsets of everything, and build strtab.
+ let mut offset = 0;
+ let mut strtab = StringTable::default();
+
+ // COFF header.
+ offset += mem::size_of::<coff::ImageFileHeader>();
+
+ // Section headers.
+ offset += self.sections.len() * mem::size_of::<coff::ImageSectionHeader>();
+
+ // Calculate size of section data and add section strings to strtab.
+ let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
+ for (index, section) in self.sections.iter().enumerate() {
+ if section.name.len() > 8 {
+ section_offsets[index].str_id = Some(strtab.add(&section.name));
+ }
+
+ let len = section.data.len();
+ if len != 0 {
+ // TODO: not sure what alignment is required here, but this seems to match LLVM
+ offset = align(offset, 4);
+ section_offsets[index].offset = offset;
+ offset += len;
+ } else {
+ section_offsets[index].offset = 0;
+ }
+
+ // Calculate size of relocations.
+ let count = section.relocations.len();
+ if count != 0 {
+ section_offsets[index].reloc_offset = offset;
+ offset += count * mem::size_of::<coff::ImageRelocation>();
+ }
+ }
+
+ // 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 u16 + 1;
+ }
+ }
+ }
+
+ // Calculate size of symbols and add symbol strings to strtab.
+ 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;
+ match symbol.kind {
+ SymbolKind::File => {
+ // Name goes in auxilary symbol records.
+ let aux_count = (symbol.name.len() + coff::IMAGE_SIZEOF_SYMBOL - 1)
+ / coff::IMAGE_SIZEOF_SYMBOL;
+ symbol_offsets[index].aux_count = aux_count as u8;
+ symtab_count += aux_count;
+ // Don't add name to strtab.
+ continue;
+ }
+ SymbolKind::Section => {
+ symbol_offsets[index].aux_count = 1;
+ symtab_count += 1;
+ }
+ _ => {}
+ }
+ if symbol.name.len() > 8 {
+ symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
+ }
+ }
+
+ // Calculate size of symtab.
+ let symtab_offset = offset;
+ let symtab_len = symtab_count * coff::IMAGE_SIZEOF_SYMBOL;
+ 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.
+ let header = coff::ImageFileHeader {
+ machine: U16::new(
+ LE,
+ match self.architecture {
+ Architecture::Arm => coff::IMAGE_FILE_MACHINE_ARMNT,
+ Architecture::Aarch64 => coff::IMAGE_FILE_MACHINE_ARM64,
+ Architecture::I386 => coff::IMAGE_FILE_MACHINE_I386,
+ Architecture::X86_64 => coff::IMAGE_FILE_MACHINE_AMD64,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?}",
+ self.architecture
+ )));
+ }
+ },
+ ),
+ number_of_sections: U16::new(LE, self.sections.len() as u16),
+ time_date_stamp: U32::default(),
+ pointer_to_symbol_table: U32::new(LE, symtab_offset as u32),
+ number_of_symbols: U32::new(LE, symtab_count as u32),
+ size_of_optional_header: U16::default(),
+ characteristics: match self.flags {
+ FileFlags::Coff { characteristics } => U16::new(LE, characteristics),
+ _ => U16::default(),
+ },
+ };
+ buffer.write(&header);
+
+ // Write section headers.
+ for (index, section) in self.sections.iter().enumerate() {
+ let mut characteristics = match section.flags {
+ SectionFlags::Coff {
+ characteristics, ..
+ } => characteristics,
+ _ => 0,
+ };
+ if section_offsets[index].selection != 0 {
+ characteristics |= coff::IMAGE_SCN_LNK_COMDAT;
+ };
+ characteristics |= 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::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
+ )));
+ }
+ } | 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
+ )));
+ }
+ };
+ let mut coff_section = coff::ImageSectionHeader {
+ name: [0; 8],
+ virtual_size: U32::default(),
+ virtual_address: U32::default(),
+ size_of_raw_data: U32::new(LE, section.size as u32),
+ pointer_to_raw_data: U32::new(LE, section_offsets[index].offset as u32),
+ pointer_to_relocations: U32::new(LE, section_offsets[index].reloc_offset as u32),
+ pointer_to_linenumbers: U32::default(),
+ number_of_relocations: U16::new(LE, section.relocations.len() as u16),
+ number_of_linenumbers: U16::default(),
+ characteristics: U32::new(LE, characteristics),
+ };
+ if section.name.len() <= 8 {
+ coff_section.name[..section.name.len()].copy_from_slice(&section.name);
+ } else {
+ let mut str_offset = strtab.get_offset(section_offsets[index].str_id.unwrap());
+ 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 if 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;
+ }
+ } else {
+ return Err(Error(format!("invalid section name offset {}", str_offset)));
+ }
+ }
+ buffer.write(&coff_section);
+ }
+
+ // Write section data and relocations.
+ 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].offset, buffer.len());
+ buffer.write_bytes(&section.data);
+ }
+
+ if !section.relocations.is_empty() {
+ debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
+ for reloc in &section.relocations {
+ //assert!(reloc.implicit_addend);
+ let typ = match self.architecture {
+ Architecture::I386 => match (reloc.kind, reloc.size, reloc.addend) {
+ (RelocationKind::Absolute, 16, 0) => coff::IMAGE_REL_I386_DIR16,
+ (RelocationKind::Relative, 16, 0) => coff::IMAGE_REL_I386_REL16,
+ (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_I386_DIR32,
+ (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_I386_DIR32NB,
+ (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_I386_SECTION,
+ (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_I386_SECREL,
+ (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_I386_SECREL7,
+ (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_I386_REL32,
+ (RelocationKind::Coff(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ Architecture::X86_64 => match (reloc.kind, reloc.size, reloc.addend) {
+ (RelocationKind::Absolute, 64, 0) => coff::IMAGE_REL_AMD64_ADDR64,
+ (RelocationKind::Absolute, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32,
+ (RelocationKind::ImageOffset, 32, 0) => coff::IMAGE_REL_AMD64_ADDR32NB,
+ (RelocationKind::Relative, 32, -4) => coff::IMAGE_REL_AMD64_REL32,
+ (RelocationKind::Relative, 32, -5) => coff::IMAGE_REL_AMD64_REL32_1,
+ (RelocationKind::Relative, 32, -6) => coff::IMAGE_REL_AMD64_REL32_2,
+ (RelocationKind::Relative, 32, -7) => coff::IMAGE_REL_AMD64_REL32_3,
+ (RelocationKind::Relative, 32, -8) => coff::IMAGE_REL_AMD64_REL32_4,
+ (RelocationKind::Relative, 32, -9) => coff::IMAGE_REL_AMD64_REL32_5,
+ (RelocationKind::SectionIndex, 16, 0) => coff::IMAGE_REL_AMD64_SECTION,
+ (RelocationKind::SectionOffset, 32, 0) => coff::IMAGE_REL_AMD64_SECREL,
+ (RelocationKind::SectionOffset, 7, 0) => coff::IMAGE_REL_AMD64_SECREL7,
+ (RelocationKind::Coff(x), _, _) => x,
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?}",
+ self.architecture
+ )));
+ }
+ };
+ let coff_relocation = coff::ImageRelocation {
+ virtual_address: U32Bytes::new(LE, reloc.offset as u32),
+ symbol_table_index: U32Bytes::new(
+ LE,
+ symbol_offsets[reloc.symbol.0].index as u32,
+ ),
+ typ: U16Bytes::new(LE, typ),
+ };
+ buffer.write(&coff_relocation);
+ }
+ }
+ }
+
+ // Write symbols.
+ debug_assert_eq!(symtab_offset, buffer.len());
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ let mut name = &symbol.name[..];
+ let section_number = match symbol.section {
+ SymbolSection::None => {
+ debug_assert_eq!(symbol.kind, SymbolKind::File);
+ coff::IMAGE_SYM_DEBUG
+ }
+ SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED,
+ SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE,
+ SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED,
+ 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 => {
+ // Name goes in auxilary symbol records.
+ name = b".file";
+ coff::IMAGE_SYM_CLASS_FILE
+ }
+ SymbolKind::Section => coff::IMAGE_SYM_CLASS_STATIC,
+ 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
+ };
+ let mut coff_symbol = coff::ImageSymbol {
+ name: [0; 8],
+ value: U32Bytes::new(LE, value),
+ section_number: U16Bytes::new(LE, section_number as u16),
+ typ: U16Bytes::new(LE, typ),
+ storage_class,
+ number_of_aux_symbols,
+ };
+ if name.len() <= 8 {
+ coff_symbol.name[..name.len()].copy_from_slice(name);
+ } else {
+ let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap());
+ coff_symbol.name[4..8].copy_from_slice(&u32::to_le_bytes(str_offset as u32));
+ }
+ buffer.write(&coff_symbol);
+
+ // Write auxiliary symbols.
+ match symbol.kind {
+ SymbolKind::File => {
+ let aux_len = number_of_aux_symbols as usize * coff::IMAGE_SIZEOF_SYMBOL;
+ debug_assert!(aux_len >= symbol.name.len());
+ let old_len = buffer.len();
+ buffer.write_bytes(&symbol.name);
+ buffer.resize(old_len + aux_len, 0);
+ }
+ SymbolKind::Section => {
+ debug_assert_eq!(number_of_aux_symbols, 1);
+ let section_index = symbol.section.id().unwrap().0;
+ let section = &self.sections[section_index];
+ let aux = coff::ImageAuxSymbolSection {
+ length: U32Bytes::new(LE, section.size as u32),
+ number_of_relocations: U16Bytes::new(LE, section.relocations.len() as u16),
+ number_of_linenumbers: U16Bytes::default(),
+ check_sum: U32Bytes::new(LE, checksum(section.data.as_slice())),
+ number: U16Bytes::new(
+ LE,
+ section_offsets[section_index].associative_section,
+ ),
+ selection: section_offsets[section_index].selection,
+ reserved: 0,
+ // TODO: bigobj
+ high_number: U16Bytes::default(),
+ };
+ buffer.write(&aux);
+ }
+ _ => {
+ debug_assert_eq!(number_of_aux_symbols, 0);
+ }
+ }
+ }
+
+ // Write strtab section.
+ debug_assert_eq!(strtab_offset, buffer.len());
+ buffer.write_bytes(&u32::to_le_bytes(strtab_len as u32));
+ buffer.write_bytes(&strtab_data);
+
+ debug_assert_eq!(offset, buffer.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-0.26.2/src/write/elf.rs b/vendor/object-0.26.2/src/write/elf.rs
new file mode 100644
index 000000000..34e0abc85
--- /dev/null
+++ b/vendor/object-0.26.2/src/write/elf.rs
@@ -0,0 +1,1314 @@
+use std::mem;
+use std::vec::Vec;
+
+use crate::elf;
+use crate::endian::*;
+use crate::write::string::*;
+use crate::write::util::*;
+use crate::write::*;
+use crate::AddressSize;
+
+#[derive(Default, Clone, Copy)]
+struct ComdatOffsets {
+ offset: usize,
+ str_id: Option<StringId>,
+ len: usize,
+}
+
+#[derive(Default, Clone, Copy)]
+struct SectionOffsets {
+ index: usize,
+ offset: usize,
+ str_id: Option<StringId>,
+ reloc_index: usize,
+ reloc_offset: usize,
+ reloc_len: usize,
+ reloc_str_id: Option<StringId>,
+}
+
+#[derive(Default, Clone, Copy)]
+struct SymbolOffsets {
+ index: usize,
+ str_id: Option<StringId>,
+}
+
+impl Object {
+ pub(crate) fn elf_section_info(
+ &self,
+ section: StandardSection,
+ ) -> (&'static [u8], &'static [u8], SectionKind) {
+ match section {
+ StandardSection::Text => (&[], &b".text"[..], SectionKind::Text),
+ StandardSection::Data => (&[], &b".data"[..], SectionKind::Data),
+ StandardSection::ReadOnlyData | StandardSection::ReadOnlyString => {
+ (&[], &b".rodata"[..], SectionKind::ReadOnlyData)
+ }
+ StandardSection::ReadOnlyDataWithRel => (&[], b".data.rel.ro", SectionKind::Data),
+ StandardSection::UninitializedData => {
+ (&[], &b".bss"[..], SectionKind::UninitializedData)
+ }
+ StandardSection::Tls => (&[], &b".tdata"[..], SectionKind::Tls),
+ StandardSection::UninitializedTls => {
+ (&[], &b".tbss"[..], SectionKind::UninitializedTls)
+ }
+ StandardSection::TlsVariables => {
+ // Unsupported section.
+ (&[], &[], SectionKind::TlsVariables)
+ }
+ StandardSection::Common => {
+ // Unsupported section.
+ (&[], &[], SectionKind::Common)
+ }
+ }
+ }
+
+ 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::Arm => false,
+ Architecture::Avr => true,
+ Architecture::Bpf => false,
+ Architecture::I386 => false,
+ Architecture::X86_64 => true,
+ Architecture::X86_64_X32 => true,
+ Architecture::Hexagon => 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::Sparc64 => true,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?}",
+ self.architecture
+ )));
+ }
+ })
+ }
+
+ pub(crate) fn elf_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> Result<i64> {
+ // Return true if we should use a section symbol to avoid preemption.
+ fn want_section_symbol(relocation: &Relocation, symbol: &Symbol) -> bool {
+ if symbol.scope != SymbolScope::Dynamic {
+ // Only dynamic symbols can be preemptible.
+ return false;
+ }
+ match symbol.kind {
+ SymbolKind::Text | SymbolKind::Data => {}
+ _ => return false,
+ }
+ match relocation.kind {
+ // Anything using GOT or PLT is preemptible.
+ // We also require that `Other` relocations must already be correct.
+ RelocationKind::Got
+ | RelocationKind::GotRelative
+ | RelocationKind::GotBaseRelative
+ | RelocationKind::PltRelative
+ | RelocationKind::Elf(_) => return false,
+ // Absolute relocations are preemptible for non-local data.
+ // TODO: not sure if this rule is exactly correct
+ // This rule was added to handle global data references in debuginfo.
+ // Maybe this should be a new relocation kind so that the caller can decide.
+ RelocationKind::Absolute => {
+ if symbol.kind == SymbolKind::Data {
+ return false;
+ }
+ }
+ _ => {}
+ }
+ true
+ }
+
+ // Use section symbols for relocations where required to avoid preemption.
+ // Otherwise, the linker will fail with:
+ // relocation R_X86_64_PC32 against symbol `SomeSymbolName' can not be used when
+ // making a shared object; recompile with -fPIC
+ let symbol = &self.symbols[relocation.symbol.0];
+ if want_section_symbol(relocation, symbol) {
+ if let Some(section) = symbol.section.id() {
+ relocation.addend += symbol.value as i64;
+ relocation.symbol = self.section_symbol(section);
+ }
+ }
+
+ // 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_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> {
+ let address_size = self.architecture.address_size().unwrap();
+ let endian = self.endian;
+ let elf32 = Elf32 { endian };
+ let elf64 = Elf64 { endian };
+ let elf: &dyn Elf = match address_size {
+ AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => &elf32,
+ AddressSize::U64 => &elf64,
+ };
+ let pointer_align = address_size.bytes() as usize;
+ let is_mips64el =
+ self.architecture == Architecture::Mips64 && self.endian == Endianness::Little;
+
+ // Calculate offsets of everything.
+ let mut offset = 0;
+
+ // ELF header.
+ let e_ehsize = elf.file_header_size();
+ offset += e_ehsize;
+
+ // Create reloc section header names.
+ let is_rela = self.elf_has_relocation_addend()?;
+ let reloc_names: Vec<_> = self
+ .sections
+ .iter()
+ .map(|section| {
+ let mut reloc_name = Vec::new();
+ if !section.relocations.is_empty() {
+ reloc_name.extend_from_slice(if is_rela {
+ &b".rela"[..]
+ } else {
+ &b".rel"[..]
+ });
+ reloc_name.extend_from_slice(&section.name);
+ }
+ reloc_name
+ })
+ .collect();
+
+ // Calculate size of section data.
+ let mut shstrtab = StringTable::default();
+ let mut comdat_offsets = vec![ComdatOffsets::default(); self.comdats.len()];
+ let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
+ // Null section.
+ let mut section_num = 1;
+ for (index, comdat) in self.comdats.iter().enumerate() {
+ if comdat.kind != ComdatKind::Any {
+ return Err(Error(format!(
+ "unsupported COMDAT symbol `{}` kind {:?}",
+ self.symbols[comdat.symbol.0].name().unwrap_or(""),
+ comdat.kind
+ )));
+ }
+
+ comdat_offsets[index].str_id = Some(shstrtab.add(b".group"));
+ section_num += 1;
+ offset = align(offset, 4);
+ comdat_offsets[index].offset = offset;
+ let len = (comdat.sections.len() + 1) * 4;
+ comdat_offsets[index].len = len;
+ offset += len;
+ }
+ for (index, section) in self.sections.iter().enumerate() {
+ section_offsets[index].str_id = Some(shstrtab.add(&section.name));
+ section_offsets[index].index = section_num;
+ section_num += 1;
+
+ let len = section.data.len();
+ if len != 0 {
+ offset = align(offset, section.align as usize);
+ section_offsets[index].offset = offset;
+ offset += len;
+ } else {
+ section_offsets[index].offset = offset;
+ }
+
+ if !section.relocations.is_empty() {
+ section_offsets[index].reloc_str_id = Some(shstrtab.add(&reloc_names[index]));
+ section_offsets[index].reloc_index = section_num;
+ section_num += 1;
+ }
+ }
+
+ // Calculate index of symbols and add symbol strings to strtab.
+ let mut strtab = StringTable::default();
+ let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
+ // Null symbol.
+ let mut symtab_count = 1;
+ // Local symbols must come before global.
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ if symbol.is_local() {
+ symbol_offsets[index].index = symtab_count;
+ symtab_count += 1;
+ }
+ }
+ let symtab_count_local = symtab_count;
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ if !symbol.is_local() {
+ symbol_offsets[index].index = symtab_count;
+ symtab_count += 1;
+ }
+ }
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ if symbol.kind != SymbolKind::Section && !symbol.name.is_empty() {
+ symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
+ }
+ }
+
+ // Calculate size of symtab.
+ let symtab_str_id = shstrtab.add(&b".symtab"[..]);
+ offset = align(offset, pointer_align);
+ let symtab_offset = offset;
+ let symtab_len = symtab_count * elf.symbol_size();
+ offset += symtab_len;
+ let symtab_index = section_num;
+ section_num += 1;
+
+ // Calculate size of symtab_shndx.
+ let mut need_symtab_shndx = false;
+ for symbol in &self.symbols {
+ let index = symbol
+ .section
+ .id()
+ .map(|s| section_offsets[s.0].index)
+ .unwrap_or(0);
+ if index >= elf::SHN_LORESERVE as usize {
+ need_symtab_shndx = true;
+ break;
+ }
+ }
+ let symtab_shndx_offset = offset;
+ let mut symtab_shndx_str_id = None;
+ let mut symtab_shndx_len = 0;
+ if need_symtab_shndx {
+ symtab_shndx_str_id = Some(shstrtab.add(&b".symtab_shndx"[..]));
+ symtab_shndx_len = symtab_count * 4;
+ offset += symtab_shndx_len;
+ section_num += 1;
+ }
+
+ // Calculate size of strtab.
+ let strtab_str_id = shstrtab.add(&b".strtab"[..]);
+ let strtab_offset = offset;
+ // Start with null name.
+ let mut strtab_data = vec![0];
+ strtab.write(1, &mut strtab_data);
+ offset += strtab_data.len();
+ let strtab_index = section_num;
+ section_num += 1;
+
+ // Calculate size of relocations.
+ for (index, section) in self.sections.iter().enumerate() {
+ let count = section.relocations.len();
+ if count != 0 {
+ offset = align(offset, pointer_align);
+ section_offsets[index].reloc_offset = offset;
+ let len = count * elf.rel_size(is_rela);
+ section_offsets[index].reloc_len = len;
+ offset += len;
+ }
+ }
+
+ // Calculate size of shstrtab.
+ let shstrtab_str_id = shstrtab.add(&b".shstrtab"[..]);
+ let shstrtab_offset = offset;
+ // Start with null section name.
+ let mut shstrtab_data = vec![0];
+ shstrtab.write(1, &mut shstrtab_data);
+ offset += shstrtab_data.len();
+ let shstrtab_index = section_num;
+ section_num += 1;
+
+ // Calculate size of section headers.
+ offset = align(offset, pointer_align);
+ let e_shoff = offset;
+ let e_shentsize = elf.section_header_size();
+ offset += section_num * e_shentsize;
+
+ // Start writing.
+ buffer
+ .reserve(offset)
+ .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
+
+ // Write file header.
+ let e_ident = elf::Ident {
+ magic: elf::ELFMAG,
+ class: match address_size {
+ AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => elf::ELFCLASS32,
+ AddressSize::U64 => elf::ELFCLASS64,
+ },
+ data: if endian.is_little_endian() {
+ elf::ELFDATA2LSB
+ } else {
+ elf::ELFDATA2MSB
+ },
+ version: elf::EV_CURRENT,
+ os_abi: elf::ELFOSABI_NONE,
+ abi_version: 0,
+ padding: [0; 7],
+ };
+ let e_type = elf::ET_REL;
+ let e_machine = match self.architecture {
+ Architecture::Aarch64 => elf::EM_AARCH64,
+ Architecture::Arm => elf::EM_ARM,
+ Architecture::Avr => elf::EM_AVR,
+ Architecture::Bpf => elf::EM_BPF,
+ Architecture::I386 => elf::EM_386,
+ Architecture::X86_64 => elf::EM_X86_64,
+ Architecture::X86_64_X32 => elf::EM_X86_64,
+ Architecture::Hexagon => elf::EM_HEXAGON,
+ Architecture::Mips => elf::EM_MIPS,
+ Architecture::Mips64 => elf::EM_MIPS,
+ Architecture::Msp430 => elf::EM_MSP430,
+ Architecture::PowerPc => elf::EM_PPC,
+ Architecture::PowerPc64 => elf::EM_PPC64,
+ Architecture::Riscv32 => elf::EM_RISCV,
+ Architecture::Riscv64 => elf::EM_RISCV,
+ Architecture::S390x => elf::EM_S390,
+ Architecture::Sparc64 => elf::EM_SPARCV9,
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?}",
+ self.architecture
+ )));
+ }
+ };
+ let e_flags = if let FileFlags::Elf { e_flags } = self.flags {
+ e_flags
+ } else {
+ 0
+ };
+ let e_shnum = if section_num >= elf::SHN_LORESERVE as usize {
+ 0
+ } else {
+ section_num as u16
+ };
+ let e_shstrndx = if shstrtab_index >= elf::SHN_LORESERVE as usize {
+ elf::SHN_XINDEX
+ } else {
+ shstrtab_index as u16
+ };
+
+ elf.write_file_header(
+ buffer,
+ FileHeader {
+ e_ident,
+ e_type,
+ e_machine,
+ e_version: elf::EV_CURRENT.into(),
+ e_entry: 0,
+ e_phoff: 0,
+ e_shoff: e_shoff as u64,
+ e_flags,
+ e_ehsize: e_ehsize as u16,
+ e_phentsize: 0,
+ e_phnum: 0,
+ e_shentsize: e_shentsize as u16,
+ e_shnum,
+ e_shstrndx,
+ },
+ );
+
+ // Write section data.
+ for (index, comdat) in self.comdats.iter().enumerate() {
+ let mut data = Vec::new();
+ data.write_pod(&U32::new(self.endian, elf::GRP_COMDAT));
+ for section in &comdat.sections {
+ data.write_pod(&U32::new(
+ self.endian,
+ section_offsets[section.0].index as u32,
+ ));
+ }
+
+ write_align(buffer, 4);
+ debug_assert_eq!(comdat_offsets[index].offset, buffer.len());
+ debug_assert_eq!(comdat_offsets[index].len, data.len());
+ buffer.write_bytes(&data);
+ }
+ for (index, section) in self.sections.iter().enumerate() {
+ let len = section.data.len();
+ if len != 0 {
+ write_align(buffer, section.align as usize);
+ debug_assert_eq!(section_offsets[index].offset, buffer.len());
+ buffer.write_bytes(&section.data);
+ }
+ }
+
+ // Write symbols.
+ write_align(buffer, pointer_align);
+ debug_assert_eq!(symtab_offset, buffer.len());
+ elf.write_symbol(
+ buffer,
+ Sym {
+ st_name: 0,
+ st_info: 0,
+ st_other: 0,
+ st_shndx: 0,
+ st_value: 0,
+ st_size: 0,
+ },
+ );
+ let mut symtab_shndx = Vec::new();
+ if need_symtab_shndx {
+ symtab_shndx.write_pod(&U32::new(endian, 0));
+ }
+ 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, xindex) = match symbol.section {
+ SymbolSection::None => {
+ debug_assert_eq!(symbol.kind, SymbolKind::File);
+ (elf::SHN_ABS, 0)
+ }
+ SymbolSection::Undefined => (elf::SHN_UNDEF, 0),
+ SymbolSection::Absolute => (elf::SHN_ABS, 0),
+ SymbolSection::Common => (elf::SHN_COMMON, 0),
+ SymbolSection::Section(id) => {
+ let index = section_offsets[id.0].index as u32;
+ (
+ if index >= elf::SHN_LORESERVE as u32 {
+ elf::SHN_XINDEX
+ } else {
+ index as u16
+ },
+ index,
+ )
+ }
+ };
+ let st_name = symbol_offsets[index]
+ .str_id
+ .map(|id| strtab.get_offset(id))
+ .unwrap_or(0) as u32;
+ elf.write_symbol(
+ buffer,
+ Sym {
+ st_name,
+ st_info,
+ st_other,
+ st_shndx,
+ st_value: symbol.value,
+ st_size: symbol.size,
+ },
+ );
+ if need_symtab_shndx {
+ symtab_shndx.write_pod(&U32::new(endian, xindex));
+ }
+ 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)?;
+ }
+ }
+ if need_symtab_shndx {
+ debug_assert_eq!(symtab_shndx_offset, buffer.len());
+ debug_assert_eq!(symtab_shndx_len, symtab_shndx.len());
+ buffer.write_bytes(&symtab_shndx);
+ }
+
+ // Write strtab section.
+ debug_assert_eq!(strtab_offset, buffer.len());
+ buffer.write_bytes(&strtab_data);
+
+ // 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 &section.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::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::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, _, 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::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::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::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)));
+ }
+ },
+ _ => {
+ 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 as u32;
+ elf.write_rel(
+ buffer,
+ is_mips64el,
+ is_rela,
+ Rel {
+ r_offset: reloc.offset,
+ r_sym,
+ r_type,
+ r_addend: reloc.addend,
+ },
+ );
+ }
+ }
+ }
+
+ // Write shstrtab section.
+ debug_assert_eq!(shstrtab_offset, buffer.len());
+ buffer.write_bytes(&shstrtab_data);
+
+ // Write section headers.
+ write_align(buffer, pointer_align);
+ debug_assert_eq!(e_shoff, buffer.len());
+ elf.write_section_header(
+ buffer,
+ SectionHeader {
+ sh_name: 0,
+ sh_type: 0,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: 0,
+ sh_size: if section_num >= elf::SHN_LORESERVE as usize {
+ section_num as u64
+ } else {
+ 0
+ },
+ sh_link: if shstrtab_index >= elf::SHN_LORESERVE as usize {
+ shstrtab_index as u32
+ } else {
+ 0
+ },
+ // TODO: e_phnum overflow
+ sh_info: 0,
+ sh_addralign: 0,
+ sh_entsize: 0,
+ },
+ );
+ for (index, comdat) in self.comdats.iter().enumerate() {
+ let sh_name = comdat_offsets[index]
+ .str_id
+ .map(|id| shstrtab.get_offset(id))
+ .unwrap_or(0) as u32;
+ elf.write_section_header(
+ buffer,
+ SectionHeader {
+ sh_name,
+ sh_type: elf::SHT_GROUP,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: comdat_offsets[index].offset as u64,
+ sh_size: comdat_offsets[index].len as u64,
+ sh_link: symtab_index as u32,
+ sh_info: symbol_offsets[comdat.symbol.0].index as u32,
+ sh_addralign: 4,
+ sh_entsize: 4,
+ },
+ );
+ }
+ 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 => 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,
+ };
+ let sh_name = section_offsets[index]
+ .str_id
+ .map(|id| shstrtab.get_offset(id))
+ .unwrap_or(0) as u32;
+ elf.write_section_header(
+ buffer,
+ SectionHeader {
+ sh_name,
+ 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() {
+ let sh_name = section_offsets[index]
+ .reloc_str_id
+ .map(|id| shstrtab.get_offset(id))
+ .unwrap_or(0);
+ elf.write_section_header(
+ buffer,
+ SectionHeader {
+ sh_name: sh_name as u32,
+ sh_type: if is_rela { elf::SHT_RELA } else { elf::SHT_REL },
+ sh_flags: elf::SHF_INFO_LINK.into(),
+ sh_addr: 0,
+ sh_offset: section_offsets[index].reloc_offset as u64,
+ sh_size: section_offsets[index].reloc_len as u64,
+ sh_link: symtab_index as u32,
+ sh_info: section_offsets[index].index as u32,
+ sh_addralign: pointer_align as u64,
+ sh_entsize: elf.rel_size(is_rela) as u64,
+ },
+ );
+ }
+ }
+
+ // Write symtab section header.
+ elf.write_section_header(
+ buffer,
+ SectionHeader {
+ sh_name: shstrtab.get_offset(symtab_str_id) as u32,
+ sh_type: elf::SHT_SYMTAB,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: symtab_offset as u64,
+ sh_size: symtab_len as u64,
+ sh_link: strtab_index as u32,
+ sh_info: symtab_count_local as u32,
+ sh_addralign: pointer_align as u64,
+ sh_entsize: elf.symbol_size() as u64,
+ },
+ );
+
+ // Write symtab_shndx section header.
+ if need_symtab_shndx {
+ elf.write_section_header(
+ buffer,
+ SectionHeader {
+ sh_name: shstrtab.get_offset(symtab_shndx_str_id.unwrap()) as u32,
+ sh_type: elf::SHT_SYMTAB_SHNDX,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: symtab_shndx_offset as u64,
+ sh_size: symtab_shndx_len as u64,
+ sh_link: symtab_index as u32,
+ sh_info: symtab_count_local as u32,
+ sh_addralign: 4,
+ sh_entsize: 4,
+ },
+ );
+ }
+
+ // Write strtab section header.
+ elf.write_section_header(
+ buffer,
+ SectionHeader {
+ sh_name: shstrtab.get_offset(strtab_str_id) as u32,
+ sh_type: elf::SHT_STRTAB,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: strtab_offset as u64,
+ sh_size: strtab_data.len() as u64,
+ sh_link: 0,
+ sh_info: 0,
+ sh_addralign: 1,
+ sh_entsize: 0,
+ },
+ );
+
+ // Write shstrtab section header.
+ elf.write_section_header(
+ buffer,
+ SectionHeader {
+ sh_name: shstrtab.get_offset(shstrtab_str_id) as u32,
+ sh_type: elf::SHT_STRTAB,
+ sh_flags: 0,
+ sh_addr: 0,
+ sh_offset: shstrtab_offset as u64,
+ sh_size: shstrtab_data.len() as u64,
+ sh_link: 0,
+ sh_info: 0,
+ sh_addralign: 1,
+ sh_entsize: 0,
+ },
+ );
+
+ debug_assert_eq!(offset, buffer.len());
+
+ Ok(())
+ }
+}
+
+/// Native endian version of `FileHeader64`.
+struct FileHeader {
+ e_ident: elf::Ident,
+ e_type: u16,
+ e_machine: u16,
+ e_version: u32,
+ e_entry: u64,
+ e_phoff: u64,
+ e_shoff: u64,
+ e_flags: u32,
+ e_ehsize: u16,
+ e_phentsize: u16,
+ e_phnum: u16,
+ e_shentsize: u16,
+ e_shnum: u16,
+ e_shstrndx: u16,
+}
+
+/// Native endian version of `SectionHeader64`.
+struct SectionHeader {
+ sh_name: u32,
+ sh_type: u32,
+ sh_flags: u64,
+ sh_addr: u64,
+ sh_offset: u64,
+ sh_size: u64,
+ sh_link: u32,
+ sh_info: u32,
+ sh_addralign: u64,
+ sh_entsize: u64,
+}
+
+/// Native endian version of `Sym64`.
+struct Sym {
+ st_name: u32,
+ st_info: u8,
+ st_other: u8,
+ st_shndx: u16,
+ st_value: u64,
+ st_size: u64,
+}
+
+/// Unified native endian version of `Rel*`.
+struct Rel {
+ r_offset: u64,
+ r_sym: u32,
+ r_type: u32,
+ r_addend: i64,
+}
+
+trait Elf {
+ fn file_header_size(&self) -> usize;
+ fn section_header_size(&self) -> usize;
+ fn symbol_size(&self) -> usize;
+ fn rel_size(&self, is_rela: bool) -> usize;
+ fn write_file_header(&self, buffer: &mut dyn WritableBuffer, section: FileHeader);
+ fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader);
+ fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym);
+ fn write_rel(
+ &self,
+ buffer: &mut dyn WritableBuffer,
+ is_mips64el: bool,
+ is_rela: bool,
+ rel: Rel,
+ );
+}
+
+struct Elf32<E> {
+ endian: E,
+}
+
+impl<E: Endian> Elf for Elf32<E> {
+ fn file_header_size(&self) -> usize {
+ mem::size_of::<elf::FileHeader32<E>>()
+ }
+
+ fn section_header_size(&self) -> usize {
+ mem::size_of::<elf::SectionHeader32<E>>()
+ }
+
+ fn symbol_size(&self) -> usize {
+ mem::size_of::<elf::Sym32<E>>()
+ }
+
+ fn rel_size(&self, is_rela: bool) -> usize {
+ if is_rela {
+ mem::size_of::<elf::Rela32<E>>()
+ } else {
+ mem::size_of::<elf::Rel32<E>>()
+ }
+ }
+
+ fn write_file_header(&self, buffer: &mut dyn WritableBuffer, file: FileHeader) {
+ let endian = self.endian;
+ let file = elf::FileHeader32 {
+ e_ident: file.e_ident,
+ e_type: U16::new(endian, file.e_type),
+ e_machine: U16::new(endian, file.e_machine),
+ e_version: U32::new(endian, file.e_version),
+ e_entry: U32::new(endian, file.e_entry as u32),
+ e_phoff: U32::new(endian, file.e_phoff as u32),
+ e_shoff: U32::new(endian, file.e_shoff as u32),
+ e_flags: U32::new(endian, file.e_flags),
+ e_ehsize: U16::new(endian, file.e_ehsize),
+ e_phentsize: U16::new(endian, file.e_phentsize),
+ e_phnum: U16::new(endian, file.e_phnum),
+ e_shentsize: U16::new(endian, file.e_shentsize),
+ e_shnum: U16::new(endian, file.e_shnum),
+ e_shstrndx: U16::new(endian, file.e_shstrndx),
+ };
+ buffer.write(&file);
+ }
+
+ fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) {
+ let endian = self.endian;
+ let section = elf::SectionHeader32 {
+ sh_name: U32::new(endian, section.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),
+ };
+ buffer.write(&section);
+ }
+
+ fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym) {
+ let endian = self.endian;
+ let symbol = elf::Sym32 {
+ st_name: U32::new(endian, symbol.st_name),
+ st_info: symbol.st_info,
+ st_other: symbol.st_other,
+ st_shndx: U16::new(endian, symbol.st_shndx),
+ st_value: U32::new(endian, symbol.st_value as u32),
+ st_size: U32::new(endian, symbol.st_size as u32),
+ };
+ buffer.write(&symbol);
+ }
+
+ fn write_rel(
+ &self,
+ buffer: &mut dyn WritableBuffer,
+ _is_mips64el: bool,
+ is_rela: bool,
+ rel: Rel,
+ ) {
+ let endian = self.endian;
+ 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),
+ };
+ 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),
+ };
+ buffer.write(&rel);
+ }
+ }
+}
+
+struct Elf64<E> {
+ endian: E,
+}
+
+impl<E: Endian> Elf for Elf64<E> {
+ fn file_header_size(&self) -> usize {
+ mem::size_of::<elf::FileHeader64<E>>()
+ }
+
+ fn section_header_size(&self) -> usize {
+ mem::size_of::<elf::SectionHeader64<E>>()
+ }
+
+ fn symbol_size(&self) -> usize {
+ mem::size_of::<elf::Sym64<E>>()
+ }
+
+ fn rel_size(&self, is_rela: bool) -> usize {
+ if is_rela {
+ mem::size_of::<elf::Rela64<E>>()
+ } else {
+ mem::size_of::<elf::Rel64<E>>()
+ }
+ }
+
+ fn write_file_header(&self, buffer: &mut dyn WritableBuffer, file: FileHeader) {
+ let endian = self.endian;
+ let file = elf::FileHeader64 {
+ e_ident: file.e_ident,
+ e_type: U16::new(endian, file.e_type),
+ e_machine: U16::new(endian, file.e_machine),
+ e_version: U32::new(endian, file.e_version),
+ e_entry: U64::new(endian, file.e_entry),
+ e_phoff: U64::new(endian, file.e_phoff),
+ e_shoff: U64::new(endian, file.e_shoff),
+ e_flags: U32::new(endian, file.e_flags),
+ e_ehsize: U16::new(endian, file.e_ehsize),
+ e_phentsize: U16::new(endian, file.e_phentsize),
+ e_phnum: U16::new(endian, file.e_phnum),
+ e_shentsize: U16::new(endian, file.e_shentsize),
+ e_shnum: U16::new(endian, file.e_shnum),
+ e_shstrndx: U16::new(endian, file.e_shstrndx),
+ };
+ buffer.write(&file)
+ }
+
+ fn write_section_header(&self, buffer: &mut dyn WritableBuffer, section: SectionHeader) {
+ let endian = self.endian;
+ let section = elf::SectionHeader64 {
+ sh_name: U32::new(endian, section.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),
+ };
+ buffer.write(&section);
+ }
+
+ fn write_symbol(&self, buffer: &mut dyn WritableBuffer, symbol: Sym) {
+ let endian = self.endian;
+ let symbol = elf::Sym64 {
+ st_name: U32::new(endian, symbol.st_name),
+ st_info: symbol.st_info,
+ st_other: symbol.st_other,
+ st_shndx: U16::new(endian, symbol.st_shndx),
+ st_value: U64::new(endian, symbol.st_value),
+ st_size: U64::new(endian, symbol.st_size),
+ };
+ buffer.write(&symbol);
+ }
+
+ fn write_rel(
+ &self,
+ buffer: &mut dyn WritableBuffer,
+ is_mips64el: bool,
+ is_rela: bool,
+ rel: Rel,
+ ) {
+ let endian = self.endian;
+ if is_rela {
+ let rel = elf::Rela64 {
+ r_offset: U64::new(endian, rel.r_offset),
+ r_info: elf::Rela64::r_info(endian, is_mips64el, rel.r_sym, rel.r_type),
+ r_addend: I64::new(endian, rel.r_addend),
+ };
+ 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),
+ };
+ buffer.write(&rel);
+ }
+ }
+}
diff --git a/vendor/object-0.26.2/src/write/macho.rs b/vendor/object-0.26.2/src/write/macho.rs
new file mode 100644
index 000000000..ed25950d9
--- /dev/null
+++ b/vendor/object-0.26.2/src/write/macho.rs
@@ -0,0 +1,844 @@
+use std::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,
+}
+
+#[derive(Default, Clone, Copy)]
+struct SymbolOffsets {
+ emit: bool,
+ index: usize,
+ str_id: Option<StringId>,
+}
+
+impl Object {
+ 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) {
+ match section {
+ StandardSection::Text => (&b"__TEXT"[..], &b"__text"[..], SectionKind::Text),
+ StandardSection::Data => (&b"__DATA"[..], &b"__data"[..], SectionKind::Data),
+ StandardSection::ReadOnlyData => {
+ (&b"__TEXT"[..], &b"__const"[..], SectionKind::ReadOnlyData)
+ }
+ StandardSection::ReadOnlyDataWithRel => {
+ (&b"__DATA"[..], &b"__const"[..], SectionKind::ReadOnlyData)
+ }
+ StandardSection::ReadOnlyString => (
+ &b"__TEXT"[..],
+ &b"__cstring"[..],
+ SectionKind::ReadOnlyString,
+ ),
+ StandardSection::UninitializedData => (
+ &b"__DATA"[..],
+ &b"__bss"[..],
+ SectionKind::UninitializedData,
+ ),
+ StandardSection::Tls => (&b"__DATA"[..], &b"__thread_data"[..], SectionKind::Tls),
+ StandardSection::UninitializedTls => (
+ &b"__DATA"[..],
+ &b"__thread_bss"[..],
+ SectionKind::UninitializedTls,
+ ),
+ StandardSection::TlsVariables => (
+ &b"__DATA"[..],
+ &b"__thread_vars"[..],
+ SectionKind::TlsVariables,
+ ),
+ StandardSection::Common => (&b"__DATA"[..], &b"__common"[..], SectionKind::Common),
+ }
+ }
+
+ 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, mut relocation: &mut Relocation) -> i64 {
+ let constant = match relocation.kind {
+ RelocationKind::Relative
+ | RelocationKind::GotRelative
+ | RelocationKind::PltRelative => relocation.addend + 4,
+ _ => relocation.addend,
+ };
+ relocation.addend -= constant;
+ 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 symtab command.
+ let symtab_command_offset = offset;
+ let symtab_command_len = mem::size_of::<macho::SymtabCommand<Endianness>>();
+ offset += symtab_command_len;
+ ncmds += 1;
+
+ let sizeofcmds = offset - command_offset;
+
+ // Calculate size of section data.
+ let mut segment_file_offset = None;
+ 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() {
+ let len = section.data.len();
+ if len != 0 {
+ offset = align(offset, section.align as usize);
+ section_offsets[index].offset = offset;
+ if segment_file_offset.is_none() {
+ segment_file_offset = Some(offset);
+ }
+ offset += len;
+ } else {
+ section_offsets[index].offset = offset;
+ }
+ address = align_u64(address, section.align);
+ section_offsets[index].address = address;
+ address += section.size;
+ }
+ }
+ for (index, section) in self.sections.iter().enumerate() {
+ if section.kind.is_bss() {
+ assert!(section.data.is_empty());
+ address = align_u64(address, section.align);
+ section_offsets[index].address = address;
+ address += section.size;
+ }
+ }
+ let segment_file_offset = segment_file_offset.unwrap_or(offset);
+ let segment_file_size = offset - segment_file_offset;
+ debug_assert!(segment_file_size as u64 <= address);
+
+ // Count symbols and add symbol strings to strtab.
+ let mut strtab = StringTable::default();
+ let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
+ let mut nsyms = 0;
+ 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::File | SymbolKind::Section => continue,
+ SymbolKind::Unknown => {
+ if symbol.section != SymbolSection::Undefined {
+ return Err(Error(format!(
+ "defined symbol `{}` with unknown kind",
+ symbol.name().unwrap_or(""),
+ )));
+ }
+ }
+ SymbolKind::Null | SymbolKind::Label => {
+ return Err(Error(format!(
+ "unimplemented symbol `{}` kind {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.kind
+ )));
+ }
+ }
+ symbol_offsets[index].emit = true;
+ symbol_offsets[index].index = nsyms;
+ nsyms += 1;
+ if !symbol.name.is_empty() {
+ symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
+ }
+ }
+
+ // 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);
+ offset += strtab_data.len();
+
+ // Calculate size of relocations.
+ for (index, section) in self.sections.iter().enumerate() {
+ let count = section.relocations.len();
+ if count != 0 {
+ offset = align(offset, 4);
+ section_offsets[index].reloc_offset = offset;
+ let len = count * mem::size_of::<macho::Relocation<Endianness>>();
+ offset += len;
+ }
+ }
+
+ // Start writing.
+ buffer
+ .reserve(offset)
+ .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
+
+ // Write file header.
+ let (cputype, cpusubtype) = match self.architecture {
+ Architecture::Arm => (macho::CPU_TYPE_ARM, macho::CPU_SUBTYPE_ARM_ALL),
+ Architecture::Aarch64 => (macho::CPU_TYPE_ARM64, macho::CPU_SUBTYPE_ARM64_ALL),
+ Architecture::I386 => (macho::CPU_TYPE_X86, macho::CPU_SUBTYPE_I386_ALL),
+ Architecture::X86_64 => (macho::CPU_TYPE_X86_64, macho::CPU_SUBTYPE_X86_64_ALL),
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?}",
+ self.architecture
+ )));
+ }
+ };
+
+ 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(&section.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(&section.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 => 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.relocations.len() as u32,
+ flags,
+ },
+ );
+ }
+
+ // 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 section data.
+ for (index, section) in self.sections.iter().enumerate() {
+ let len = section.data.len();
+ if len != 0 {
+ write_align(buffer, section.align as usize);
+ debug_assert_eq!(section_offsets[index].offset, buffer.len());
+ buffer.write_bytes(&section.data);
+ }
+ }
+ debug_assert_eq!(segment_file_offset + segment_file_size, buffer.len());
+
+ // Write symtab.
+ write_align(buffer, pointer_align);
+ debug_assert_eq!(symtab_offset, buffer.len());
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ if !symbol_offsets[index].emit {
+ continue;
+ }
+ // 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);
+
+ // Write relocations.
+ for (index, section) in self.sections.iter().enumerate() {
+ if !section.relocations.is_empty() {
+ write_align(buffer, 4);
+ debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len());
+ for reloc in &section.relocations {
+ 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_length = match reloc.size {
+ 8 => 0,
+ 16 => 1,
+ 32 => 2,
+ 64 => 3,
+ _ => return Err(Error(format!("unimplemented reloc size {:?}", reloc))),
+ };
+ 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, reloc.addend) {
+ (RelocationKind::Absolute, RelocationEncoding::Generic, 0) => {
+ (false, macho::X86_64_RELOC_UNSIGNED)
+ }
+ (RelocationKind::Relative, RelocationEncoding::Generic, -4) => {
+ (true, macho::X86_64_RELOC_SIGNED)
+ }
+ (RelocationKind::Relative, RelocationEncoding::X86RipRelative, -4) => {
+ (true, macho::X86_64_RELOC_SIGNED)
+ }
+ (RelocationKind::Relative, RelocationEncoding::X86Branch, -4) => {
+ (true, macho::X86_64_RELOC_BRANCH)
+ }
+ (RelocationKind::PltRelative, RelocationEncoding::X86Branch, -4) => {
+ (true, macho::X86_64_RELOC_BRANCH)
+ }
+ (RelocationKind::GotRelative, RelocationEncoding::Generic, -4) => {
+ (true, macho::X86_64_RELOC_GOT)
+ }
+ (
+ RelocationKind::GotRelative,
+ RelocationEncoding::X86RipRelativeMovq,
+ -4,
+ ) => (true, macho::X86_64_RELOC_GOT_LOAD),
+ (RelocationKind::MachO { value, relative }, _, _) => (relative, value),
+ _ => {
+ return Err(Error(format!("unimplemented relocation {:?}", reloc)));
+ }
+ },
+ _ => {
+ return Err(Error(format!(
+ "unimplemented architecture {:?}",
+ self.architecture
+ )));
+ }
+ };
+ 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));
+ }
+ }
+ }
+
+ 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(&section);
+ }
+
+ 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(&section);
+ }
+
+ 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-0.26.2/src/write/mod.rs b/vendor/object-0.26.2/src/write/mod.rs
new file mode 100644
index 000000000..747e2a02e
--- /dev/null
+++ b/vendor/object-0.26.2/src/write/mod.rs
@@ -0,0 +1,858 @@
+//! Interface for writing object files.
+
+use std::collections::HashMap;
+use std::string::String;
+use std::vec::Vec;
+use std::{error, fmt, result, str};
+
+use crate::endian::{Endianness, U32, U64};
+use crate::{
+ Architecture, BinaryFormat, ComdatKind, FileFlags, RelocationEncoding, RelocationKind,
+ SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
+};
+
+#[cfg(feature = "coff")]
+mod coff;
+#[cfg(feature = "elf")]
+mod elf;
+#[cfg(feature = "macho")]
+mod macho;
+mod string;
+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)
+ }
+}
+
+impl error::Error for Error {}
+
+/// The result type used within the write module.
+pub type Result<T> = result::Result<T, Error>;
+
+/// A writable object file.
+#[derive(Debug)]
+pub struct Object {
+ format: BinaryFormat,
+ architecture: Architecture,
+ endian: Endianness,
+ sections: Vec<Section>,
+ 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>,
+}
+
+impl Object {
+ /// Create an empty object file.
+ pub fn new(format: BinaryFormat, architecture: Architecture, endian: Endianness) -> Object {
+ Object {
+ format,
+ architecture,
+ endian,
+ sections: Vec::new(),
+ standard_sections: HashMap::new(),
+ symbols: Vec::new(),
+ symbol_map: HashMap::new(),
+ stub_symbols: HashMap::new(),
+ comdats: Vec::new(),
+ flags: FileFlags::None,
+ mangling: Mangling::default(format, architecture),
+ tlv_bootstrap: None,
+ }
+ }
+
+ /// Return the file format.
+ #[inline]
+ pub fn format(&self) -> BinaryFormat {
+ self.format
+ }
+
+ /// Return the architecture.
+ #[inline]
+ pub fn architecture(&self) -> Architecture {
+ self.architecture
+ }
+
+ /// Return the current mangling setting.
+ #[inline]
+ pub fn mangling(&self) -> Mangling {
+ self.mangling
+ }
+
+ /// Specify the mangling setting.
+ #[inline]
+ pub fn set_mangling(&mut self, mangling: Mangling) {
+ self.mangling = mangling;
+ }
+
+ /// Return the name for a standard segment.
+ ///
+ /// This will vary based on the file format.
+ #[allow(unused_variables)]
+ pub fn segment_name(&self, segment: StandardSegment) -> &'static [u8] {
+ match self.format {
+ #[cfg(feature = "coff")]
+ BinaryFormat::Coff => &[],
+ #[cfg(feature = "elf")]
+ BinaryFormat::Elf => &[],
+ #[cfg(feature = "macho")]
+ BinaryFormat::MachO => self.macho_segment_name(segment),
+ _ => unimplemented!(),
+ }
+ }
+
+ /// Get the section with the given `SectionId`.
+ #[inline]
+ pub fn section(&self, section: SectionId) -> &Section {
+ &self.sections[section.0]
+ }
+
+ /// Mutably get the section with the given `SectionId`.
+ #[inline]
+ pub fn section_mut(&mut self, section: SectionId) -> &mut Section {
+ &mut self.sections[section.0]
+ }
+
+ /// 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(&section)
+ .cloned()
+ .unwrap_or_else(|| {
+ let (segment, name, kind) = self.section_info(section);
+ self.add_section(segment.to_vec(), name.to_vec(), kind)
+ })
+ }
+
+ /// 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: Vec::new(),
+ 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) = 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) {
+ 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),
+ _ => 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) = self.subsection_info(section, name);
+ self.add_section(segment.to_vec(), name, kind)
+ };
+ 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 => 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) {
+ let (segment, section, kind) = self.section_info(section);
+ let name = self.subsection_name(section, value);
+ (segment, name, kind)
+ }
+
+ #[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),
+ _ => 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 = &mut self.sections[section.0].data;
+ 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 `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),
+ _ => 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,
+}
+
+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 | StandardSection::ReadOnlyDataWithRel => {
+ SectionKind::ReadOnlyData
+ }
+ StandardSection::ReadOnlyString => SectionKind::ReadOnlyString,
+ StandardSection::UninitializedData => SectionKind::UninitializedData,
+ StandardSection::Tls => SectionKind::Tls,
+ StandardSection::UninitializedTls => SectionKind::UninitializedTls,
+ StandardSection::TlsVariables => SectionKind::TlsVariables,
+ StandardSection::Common => SectionKind::Common,
+ }
+ }
+
+ // 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,
+ ]
+ }
+}
+
+/// 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 {
+ segment: Vec<u8>,
+ name: Vec<u8>,
+ kind: SectionKind,
+ size: u64,
+ align: u64,
+ data: Vec<u8>,
+ relocations: Vec<Relocation>,
+ symbol: Option<SymbolId>,
+ /// Section flags that are specific to each file format.
+ pub flags: SectionFlags,
+}
+
+impl Section {
+ /// Try to convert the name to a utf8 string.
+ #[inline]
+ pub fn name(&self) -> Option<&str> {
+ str::from_utf8(&self.name).ok()
+ }
+
+ /// Try to convert the segment to a utf8 string.
+ #[inline]
+ pub fn segment(&self) -> Option<&str> {
+ str::from_utf8(&self.segment).ok()
+ }
+
+ /// Return true if this section contains zerofill data.
+ #[inline]
+ pub fn is_bss(&self) -> bool {
+ self.kind.is_bss()
+ }
+
+ /// Set the data for a section.
+ ///
+ /// Must not be called for sections that already have data, or that contain uninitialized data.
+ pub fn set_data(&mut self, data: Vec<u8>, align: u64) {
+ debug_assert!(!self.is_bss());
+ debug_assert_eq!(align & (align - 1), 0);
+ debug_assert!(self.data.is_empty());
+ self.size = data.len() as u64;
+ self.data = data;
+ self.align = align;
+ }
+
+ /// Append data to a section.
+ ///
+ /// Must not be called for sections that contain uninitialized data.
+ pub fn append_data(&mut self, 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 mut offset = self.data.len();
+ if offset & (align - 1) != 0 {
+ offset += align - (offset & (align - 1));
+ self.data.resize(offset, 0);
+ }
+ self.data.extend_from_slice(data);
+ self.size = self.data.len() as u64;
+ offset as u64
+ }
+
+ /// Append unitialized 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 as u64
+ }
+}
+
+/// 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>,
+}
+
+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,
+}
+
+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,
+ _ => 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 => None,
+ Mangling::CoffI386 | Mangling::MachO => Some(b'_'),
+ }
+ }
+}
diff --git a/vendor/object-0.26.2/src/write/string.rs b/vendor/object-0.26.2/src/write/string.rs
new file mode 100644
index 000000000..c27934e60
--- /dev/null
+++ b/vendor/object-0.26.2/src/write/string.rs
@@ -0,0 +1,139 @@
+use indexmap::IndexSet;
+use std::vec::Vec;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) 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 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-0.26.2/src/write/util.rs b/vendor/object-0.26.2/src/write/util.rs
new file mode 100644
index 000000000..bb6b8597b
--- /dev/null
+++ b/vendor/object-0.26.2/src/write/util.rs
@@ -0,0 +1,129 @@
+use std::vec::Vec;
+
+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.
+ fn len(&self) -> usize;
+
+ /// Reserves specified number of bytes in the buffer.
+ fn reserve(&mut self, additional: usize) -> Result<(), ()>;
+
+ /// Writes the specified value at the end of the buffer
+ /// until the buffer has the specified length.
+ fn resize(&mut self, new_len: usize, value: u8);
+
+ /// 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, additional: usize) -> Result<(), ()> {
+ self.reserve(additional);
+ Ok(())
+ }
+
+ #[inline]
+ fn resize(&mut self, new_len: usize, value: u8) {
+ self.resize(new_len, value);
+ }
+
+ #[inline]
+ fn write_bytes(&mut self, val: &[u8]) {
+ self.extend_from_slice(val)
+ }
+}
+
+/// 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(())
+ }
+}
+
+pub(crate) fn align(offset: usize, size: usize) -> usize {
+ (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, 0);
+}
+
+#[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(()));
+ }
+}