From 9835e2ae736235810b4ea1c162ca5e65c547e770 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 18 May 2024 04:49:50 +0200 Subject: Merging upstream version 1.71.1+dfsg1. Signed-off-by: Daniel Baumann --- vendor/object/src/write/coff.rs | 52 ++-- vendor/object/src/write/elf/object.rs | 115 +++++-- vendor/object/src/write/elf/writer.rs | 196 +++++++++++- vendor/object/src/write/macho.rs | 198 ++++++++---- vendor/object/src/write/mod.rs | 63 ++-- vendor/object/src/write/string.rs | 2 +- vendor/object/src/write/util.rs | 50 +++ vendor/object/src/write/xcoff.rs | 556 ++++++++++++++++++++++++++++++++++ 8 files changed, 1107 insertions(+), 125 deletions(-) create mode 100644 vendor/object/src/write/xcoff.rs (limited to 'vendor/object/src/write') diff --git a/vendor/object/src/write/coff.rs b/vendor/object/src/write/coff.rs index c7489d3d6..d2f7ccc64 100644 --- a/vendor/object/src/write/coff.rs +++ b/vendor/object/src/write/coff.rs @@ -37,29 +37,41 @@ impl<'a> Object<'a> { pub(crate) fn coff_section_info( &self, section: StandardSection, - ) -> (&'static [u8], &'static [u8], SectionKind) { + ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { match section { - StandardSection::Text => (&[], &b".text"[..], SectionKind::Text), - StandardSection::Data => (&[], &b".data"[..], SectionKind::Data), + StandardSection::Text => (&[], &b".text"[..], SectionKind::Text, SectionFlags::None), + StandardSection::Data => (&[], &b".data"[..], SectionKind::Data, SectionFlags::None), StandardSection::ReadOnlyData | StandardSection::ReadOnlyDataWithRel - | StandardSection::ReadOnlyString => (&[], &b".rdata"[..], SectionKind::ReadOnlyData), - StandardSection::UninitializedData => { - (&[], &b".bss"[..], SectionKind::UninitializedData) - } + | StandardSection::ReadOnlyString => ( + &[], + &b".rdata"[..], + SectionKind::ReadOnlyData, + SectionFlags::None, + ), + StandardSection::UninitializedData => ( + &[], + &b".bss"[..], + SectionKind::UninitializedData, + SectionFlags::None, + ), // TLS sections are data sections with a special name. - StandardSection::Tls => (&[], &b".tls$"[..], SectionKind::Data), + StandardSection::Tls => (&[], &b".tls$"[..], SectionKind::Data, SectionFlags::None), StandardSection::UninitializedTls => { // Unsupported section. - (&[], &[], SectionKind::UninitializedTls) + (&[], &[], SectionKind::UninitializedTls, SectionFlags::None) } StandardSection::TlsVariables => { // Unsupported section. - (&[], &[], SectionKind::TlsVariables) + (&[], &[], SectionKind::TlsVariables, SectionFlags::None) } StandardSection::Common => { // Unsupported section. - (&[], &[], SectionKind::Common) + (&[], &[], SectionKind::Common, SectionFlags::None) + } + StandardSection::GnuProperty => { + // Unsupported section. + (&[], &[], SectionKind::Note, SectionFlags::None) } } } @@ -265,7 +277,7 @@ impl<'a> Object<'a> { symtab_count += 1; match symbol.kind { SymbolKind::File => { - // Name goes in auxilary symbol records. + // Name goes in auxiliary 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; @@ -355,7 +367,9 @@ impl<'a> Object<'a> { | coff::IMAGE_SCN_MEM_READ | coff::IMAGE_SCN_MEM_WRITE } - SectionKind::ReadOnlyData | SectionKind::ReadOnlyString => { + SectionKind::ReadOnlyData + | SectionKind::ReadOnlyDataWithRel + | SectionKind::ReadOnlyString => { coff::IMAGE_SCN_CNT_INITIALIZED_DATA | coff::IMAGE_SCN_MEM_READ } SectionKind::Debug | SectionKind::Other | SectionKind::OtherString => { @@ -573,11 +587,11 @@ impl<'a> Object<'a> { let section_number = match symbol.section { SymbolSection::None => { debug_assert_eq!(symbol.kind, SymbolKind::File); - coff::IMAGE_SYM_DEBUG + coff::IMAGE_SYM_DEBUG as u16 } - SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED, - SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE, - SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED, + SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED as u16, + SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE as u16, + SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED as u16, SymbolSection::Section(id) => id.0 as u16 + 1, }; let typ = if symbol.kind == SymbolKind::Text { @@ -587,7 +601,7 @@ impl<'a> Object<'a> { }; let storage_class = match symbol.kind { SymbolKind::File => { - // Name goes in auxilary symbol records. + // Name goes in auxiliary symbol records. name = b".file"; coff::IMAGE_SYM_CLASS_FILE } @@ -640,7 +654,7 @@ impl<'a> Object<'a> { let mut coff_symbol = coff::ImageSymbol { name: [0; 8], value: U32Bytes::new(LE, value), - section_number: U16Bytes::new(LE, section_number as u16), + section_number: U16Bytes::new(LE, section_number), typ: U16Bytes::new(LE, typ), storage_class, number_of_aux_symbols, diff --git a/vendor/object/src/write/elf/object.rs b/vendor/object/src/write/elf/object.rs index 068ada6bd..8b9eadaf8 100644 --- a/vendor/object/src/write/elf/object.rs +++ b/vendor/object/src/write/elf/object.rs @@ -1,10 +1,10 @@ use alloc::vec::Vec; -use crate::elf; use crate::write::elf::writer::*; use crate::write::string::StringId; use crate::write::*; use crate::AddressSize; +use crate::{elf, pod}; #[derive(Clone, Copy)] struct ComdatOffsets { @@ -27,33 +27,88 @@ struct SymbolOffsets { str_id: Option, } +// Public methods. +impl<'a> Object<'a> { + /// Add a property with a u32 value to the ELF ".note.gnu.property" section. + /// + /// Requires `feature = "elf"`. + pub fn add_elf_gnu_property_u32(&mut self, property: u32, value: u32) { + if self.format != BinaryFormat::Elf { + return; + } + + let align = if self.elf_is_64() { 8 } else { 4 }; + let mut data = Vec::with_capacity(32); + let n_name = b"GNU\0"; + data.extend_from_slice(pod::bytes_of(&elf::NoteHeader32 { + n_namesz: U32::new(self.endian, n_name.len() as u32), + n_descsz: U32::new(self.endian, util::align(3 * 4, align) as u32), + n_type: U32::new(self.endian, elf::NT_GNU_PROPERTY_TYPE_0), + })); + data.extend_from_slice(n_name); + // This happens to already be aligned correctly. + debug_assert_eq!(util::align(data.len(), align), data.len()); + data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, property))); + // Value size + data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, 4))); + data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, value))); + util::write_align(&mut data, align); + + let section = self.section_id(StandardSection::GnuProperty); + self.append_section_data(section, &data, align as u64); + } +} + +// Private methods. impl<'a> Object<'a> { pub(crate) fn elf_section_info( &self, section: StandardSection, - ) -> (&'static [u8], &'static [u8], SectionKind) { + ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { 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::Text => (&[], &b".text"[..], SectionKind::Text, SectionFlags::None), + StandardSection::Data => (&[], &b".data"[..], SectionKind::Data, SectionFlags::None), + StandardSection::ReadOnlyData | StandardSection::ReadOnlyString => ( + &[], + &b".rodata"[..], + SectionKind::ReadOnlyData, + SectionFlags::None, + ), + StandardSection::ReadOnlyDataWithRel => ( + &[], + b".data.rel.ro", + SectionKind::ReadOnlyDataWithRel, + SectionFlags::None, + ), + StandardSection::UninitializedData => ( + &[], + &b".bss"[..], + SectionKind::UninitializedData, + SectionFlags::None, + ), + StandardSection::Tls => (&[], &b".tdata"[..], SectionKind::Tls, SectionFlags::None), + StandardSection::UninitializedTls => ( + &[], + &b".tbss"[..], + SectionKind::UninitializedTls, + SectionFlags::None, + ), StandardSection::TlsVariables => { // Unsupported section. - (&[], &[], SectionKind::TlsVariables) + (&[], &[], SectionKind::TlsVariables, SectionFlags::None) } StandardSection::Common => { // Unsupported section. - (&[], &[], SectionKind::Common) + (&[], &[], SectionKind::Common, SectionFlags::None) } + StandardSection::GnuProperty => ( + &[], + &b".note.gnu.property"[..], + SectionKind::Note, + SectionFlags::Elf { + sh_flags: u64::from(elf::SHF_ALLOC), + }, + ), } } @@ -151,6 +206,13 @@ impl<'a> Object<'a> { } } + pub(crate) fn elf_is_64(&self) -> bool { + match self.architecture.address_size().unwrap() { + AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => false, + AddressSize::U64 => true, + } + } + pub(crate) fn elf_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { // Create reloc section header names so we can reference them. let is_rela = self.elf_has_relocation_addend()?; @@ -174,11 +236,7 @@ impl<'a> Object<'a> { .collect(); // Start calculating offsets of everything. - let is_64 = match self.architecture.address_size().unwrap() { - AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => false, - AddressSize::U64 => true, - }; - let mut writer = Writer::new(self.endian, is_64, buffer); + let mut writer = Writer::new(self.endian, self.elf_is_64(), buffer); writer.reserve_file_header(); // Calculate size of section data. @@ -321,12 +379,9 @@ impl<'a> Object<'a> { } } for (index, section) in self.sections.iter().enumerate() { - let len = section.data.len(); - if len != 0 { - writer.write_align(section.align as usize); - debug_assert_eq!(section_offsets[index].offset, writer.len()); - writer.write(§ion.data); - } + writer.write_align(section.align as usize); + debug_assert_eq!(section_offsets[index].offset, writer.len()); + writer.write(§ion.data); } // Write symbols. @@ -767,7 +822,9 @@ impl<'a> Object<'a> { } else { match section.kind { SectionKind::Text => elf::SHF_ALLOC | elf::SHF_EXECINSTR, - SectionKind::Data => elf::SHF_ALLOC | elf::SHF_WRITE, + SectionKind::Data | SectionKind::ReadOnlyDataWithRel => { + elf::SHF_ALLOC | elf::SHF_WRITE + } SectionKind::Tls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS, SectionKind::UninitializedData => elf::SHF_ALLOC | elf::SHF_WRITE, SectionKind::UninitializedTls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS, diff --git a/vendor/object/src/write/elf/writer.rs b/vendor/object/src/write/elf/writer.rs index 3c9d85a12..975092496 100644 --- a/vendor/object/src/write/elf/writer.rs +++ b/vendor/object/src/write/elf/writer.rs @@ -5,6 +5,7 @@ use core::mem; use crate::elf; use crate::endian::*; +use crate::pod; use crate::write::string::{StringId, StringTable}; use crate::write::util; use crate::write::{Error, Result, WritableBuffer}; @@ -113,6 +114,10 @@ pub struct Writer<'a> { gnu_verneed_count: u16, gnu_verneed_remaining: u16, gnu_vernaux_remaining: u16, + + gnu_attributes_str_id: Option, + gnu_attributes_offset: usize, + gnu_attributes_size: usize, } impl<'a> Writer<'a> { @@ -198,6 +203,10 @@ impl<'a> Writer<'a> { gnu_verneed_count: 0, gnu_verneed_remaining: 0, gnu_vernaux_remaining: 0, + + gnu_attributes_str_id: None, + gnu_attributes_offset: 0, + gnu_attributes_size: 0, } } @@ -216,10 +225,9 @@ impl<'a> Writer<'a> { /// /// Returns the aligned offset of the start of the range. pub fn reserve(&mut self, len: usize, align_start: usize) -> usize { - if len == 0 { - return self.len; + if align_start > 1 { + self.len = util::align(self.len, align_start); } - self.len = util::align(self.len, align_start); let offset = self.len; self.len += len; offset @@ -227,7 +235,9 @@ impl<'a> Writer<'a> { /// Write alignment padding bytes. pub fn write_align(&mut self, align_start: usize) { - util::write_align(self.buffer, align_start); + if align_start > 1 { + util::write_align(self.buffer, align_start); + } } /// Write data. @@ -1735,6 +1745,54 @@ impl<'a> Writer<'a> { }); } + /// Reserve the section index for the `.gnu.attributes` section. + pub fn reserve_gnu_attributes_section_index(&mut self) -> SectionIndex { + debug_assert!(self.gnu_attributes_str_id.is_none()); + self.gnu_attributes_str_id = Some(self.add_section_name(&b".gnu.attributes"[..])); + self.reserve_section_index() + } + + /// Reserve the range for the `.gnu.attributes` section. + pub fn reserve_gnu_attributes(&mut self, gnu_attributes_size: usize) { + debug_assert_eq!(self.gnu_attributes_offset, 0); + if gnu_attributes_size == 0 { + return; + } + self.gnu_attributes_size = gnu_attributes_size; + self.gnu_attributes_offset = self.reserve(self.gnu_attributes_size, self.elf_align); + } + + /// Write the section header for the `.gnu.attributes` section. + /// + /// This function does nothing if the section index was not reserved. + pub fn write_gnu_attributes_section_header(&mut self) { + if self.gnu_attributes_str_id.is_none() { + return; + } + self.write_section_header(&SectionHeader { + name: self.gnu_attributes_str_id, + sh_type: elf::SHT_GNU_ATTRIBUTES, + sh_flags: 0, + sh_addr: 0, + sh_offset: self.gnu_attributes_offset as u64, + sh_size: self.gnu_attributes_size as u64, + sh_link: self.dynstr_index.0, + sh_info: 0, // TODO + sh_addralign: self.elf_align as u64, + sh_entsize: 0, + }); + } + + /// Write the data for the `.gnu.attributes` section. + pub fn write_gnu_attributes(&mut self, data: &[u8]) { + if self.gnu_attributes_offset == 0 { + return; + } + util::write_align(self.buffer, self.elf_align); + debug_assert_eq!(self.gnu_attributes_offset, self.buffer.len()); + self.buffer.write_bytes(data); + } + /// Reserve a file range for the given number of relocations. /// /// Returns the offset of the range. @@ -1857,6 +1915,136 @@ impl<'a> Writer<'a> { sh_entsize: 4, }); } + + /// Return a helper for writing an attributes section. + pub fn attributes_writer(&self) -> AttributesWriter { + AttributesWriter::new(self.endian) + } +} + +/// A helper for writing an attributes section. +/// +/// Attributes have a variable length encoding, so it is awkward to write them in a +/// single pass. Instead, we build the entire attributes section data in memory, using +/// placeholders for unknown lengths that are filled in later. +#[allow(missing_debug_implementations)] +pub struct AttributesWriter { + endian: Endianness, + data: Vec, + subsection_offset: usize, + subsubsection_offset: usize, +} + +impl AttributesWriter { + /// Create a new `AttributesWriter` for the given endianness. + pub fn new(endian: Endianness) -> Self { + AttributesWriter { + endian, + data: vec![0x41], + subsection_offset: 0, + subsubsection_offset: 0, + } + } + + /// Start a new subsection with the given vendor name. + pub fn start_subsection(&mut self, vendor: &[u8]) { + debug_assert_eq!(self.subsection_offset, 0); + debug_assert_eq!(self.subsubsection_offset, 0); + self.subsection_offset = self.data.len(); + self.data.extend_from_slice(&[0; 4]); + self.data.extend_from_slice(vendor); + self.data.push(0); + } + + /// End the subsection. + /// + /// The subsection length is automatically calculated and written. + pub fn end_subsection(&mut self) { + debug_assert_ne!(self.subsection_offset, 0); + debug_assert_eq!(self.subsubsection_offset, 0); + let length = self.data.len() - self.subsection_offset; + self.data[self.subsection_offset..][..4] + .copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32))); + self.subsection_offset = 0; + } + + /// Start a new sub-subsection with the given tag. + pub fn start_subsubsection(&mut self, tag: u8) { + debug_assert_ne!(self.subsection_offset, 0); + debug_assert_eq!(self.subsubsection_offset, 0); + self.subsubsection_offset = self.data.len(); + self.data.push(tag); + self.data.extend_from_slice(&[0; 4]); + } + + /// Write a section or symbol index to the sub-subsection. + /// + /// The user must also call this function to write the terminating 0 index. + pub fn write_subsubsection_index(&mut self, index: u32) { + debug_assert_ne!(self.subsection_offset, 0); + debug_assert_ne!(self.subsubsection_offset, 0); + util::write_uleb128(&mut self.data, u64::from(index)); + } + + /// Write raw index data to the sub-subsection. + /// + /// The terminating 0 index is automatically written. + pub fn write_subsubsection_indices(&mut self, indices: &[u8]) { + debug_assert_ne!(self.subsection_offset, 0); + debug_assert_ne!(self.subsubsection_offset, 0); + self.data.extend_from_slice(indices); + self.data.push(0); + } + + /// Write an attribute tag to the sub-subsection. + pub fn write_attribute_tag(&mut self, tag: u64) { + debug_assert_ne!(self.subsection_offset, 0); + debug_assert_ne!(self.subsubsection_offset, 0); + util::write_uleb128(&mut self.data, tag); + } + + /// Write an attribute integer value to the sub-subsection. + pub fn write_attribute_integer(&mut self, value: u64) { + debug_assert_ne!(self.subsection_offset, 0); + debug_assert_ne!(self.subsubsection_offset, 0); + util::write_uleb128(&mut self.data, value); + } + + /// Write an attribute string value to the sub-subsection. + /// + /// The value must not include the null terminator. + pub fn write_attribute_string(&mut self, value: &[u8]) { + debug_assert_ne!(self.subsection_offset, 0); + debug_assert_ne!(self.subsubsection_offset, 0); + self.data.extend_from_slice(value); + self.data.push(0); + } + + /// Write raw attribute data to the sub-subsection. + pub fn write_subsubsection_attributes(&mut self, attributes: &[u8]) { + debug_assert_ne!(self.subsection_offset, 0); + debug_assert_ne!(self.subsubsection_offset, 0); + self.data.extend_from_slice(attributes); + } + + /// End the sub-subsection. + /// + /// The sub-subsection length is automatically calculated and written. + pub fn end_subsubsection(&mut self) { + debug_assert_ne!(self.subsection_offset, 0); + debug_assert_ne!(self.subsubsection_offset, 0); + let length = self.data.len() - self.subsubsection_offset; + self.data[self.subsubsection_offset + 1..][..4] + .copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32))); + self.subsubsection_offset = 0; + } + + /// Return the completed section data. + pub fn data(self) -> Vec { + debug_assert_eq!(self.subsection_offset, 0); + debug_assert_eq!(self.subsubsection_offset, 0); + self.data + } } /// Native endian version of [`elf::FileHeader64`]. diff --git a/vendor/object/src/write/macho.rs b/vendor/object/src/write/macho.rs index 8ef722fae..0e082b69d 100644 --- a/vendor/object/src/write/macho.rs +++ b/vendor/object/src/write/macho.rs @@ -22,6 +22,42 @@ struct SymbolOffsets { str_id: Option, } +/// The customizable portion of a [`macho::BuildVersionCommand`]. +#[derive(Debug, Default, Clone, Copy)] +#[non_exhaustive] // May want to add the tool list? +pub struct MachOBuildVersion { + /// One of the `PLATFORM_` constants (for example, + /// [`object::macho::PLATFORM_MACOS`](macho::PLATFORM_MACOS)). + pub platform: u32, + /// The minimum OS version, where `X.Y.Z` is encoded in nibbles as + /// `xxxx.yy.zz`. + pub minos: u32, + /// The SDK version as `X.Y.Z`, where `X.Y.Z` is encoded in nibbles as + /// `xxxx.yy.zz`. + pub sdk: u32, +} + +impl MachOBuildVersion { + fn cmdsize(&self) -> u32 { + // Same size for both endianness, and we don't have `ntools`. + let sz = mem::size_of::>(); + debug_assert!(sz <= u32::MAX as usize); + sz as u32 + } +} + +// Public methods. +impl<'a> Object<'a> { + /// Specify information for a Mach-O `LC_BUILD_VERSION` command. + /// + /// Requires `feature = "macho"`. + #[inline] + pub fn set_macho_build_version(&mut self, info: MachOBuildVersion) { + self.macho_build_version = Some(info); + } +} + +// Private methods. impl<'a> Object<'a> { pub(crate) fn macho_set_subsections_via_symbols(&mut self) { let flags = match self.flags { @@ -44,38 +80,72 @@ impl<'a> Object<'a> { pub(crate) fn macho_section_info( &self, section: StandardSection, - ) -> (&'static [u8], &'static [u8], SectionKind) { + ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { 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::Text => ( + &b"__TEXT"[..], + &b"__text"[..], + SectionKind::Text, + SectionFlags::None, + ), + StandardSection::Data => ( + &b"__DATA"[..], + &b"__data"[..], + SectionKind::Data, + SectionFlags::None, + ), + StandardSection::ReadOnlyData => ( + &b"__TEXT"[..], + &b"__const"[..], + SectionKind::ReadOnlyData, + SectionFlags::None, + ), + StandardSection::ReadOnlyDataWithRel => ( + &b"__DATA"[..], + &b"__const"[..], + SectionKind::ReadOnlyDataWithRel, + SectionFlags::None, + ), StandardSection::ReadOnlyString => ( &b"__TEXT"[..], &b"__cstring"[..], SectionKind::ReadOnlyString, + SectionFlags::None, ), StandardSection::UninitializedData => ( &b"__DATA"[..], &b"__bss"[..], SectionKind::UninitializedData, + SectionFlags::None, + ), + StandardSection::Tls => ( + &b"__DATA"[..], + &b"__thread_data"[..], + SectionKind::Tls, + SectionFlags::None, ), - StandardSection::Tls => (&b"__DATA"[..], &b"__thread_data"[..], SectionKind::Tls), StandardSection::UninitializedTls => ( &b"__DATA"[..], &b"__thread_bss"[..], SectionKind::UninitializedTls, + SectionFlags::None, ), StandardSection::TlsVariables => ( &b"__DATA"[..], &b"__thread_vars"[..], SectionKind::TlsVariables, + SectionFlags::None, ), - StandardSection::Common => (&b"__DATA"[..], &b"__common"[..], SectionKind::Common), + StandardSection::Common => ( + &b"__DATA"[..], + &b"__common"[..], + SectionKind::Common, + SectionFlags::None, + ), + StandardSection::GnuProperty => { + // Unsupported section. + (&[], &[], SectionKind::Note, SectionFlags::None) + } } } @@ -211,6 +281,12 @@ impl<'a> Object<'a> { let mut ncmds = 0; let command_offset = offset; + let build_version_offset = offset; + if let Some(version) = &self.macho_build_version { + offset += version.cmdsize() as usize; + ncmds += 1; + } + // Calculate size of segment command and section headers. let segment_command_offset = offset; let segment_command_len = @@ -271,16 +347,8 @@ impl<'a> Object<'a> { // // Since we don't actually emit the symbol kind, we validate it here too. match symbol.kind { - SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => {} + SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls | SymbolKind::Unknown => {} 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 {:?}", @@ -330,6 +398,9 @@ impl<'a> Object<'a> { 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::Aarch64_Ilp32 => { + (macho::CPU_TYPE_ARM64_32, macho::CPU_SUBTYPE_ARM64_32_V8) + } 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), Architecture::PowerPc => (macho::CPU_TYPE_POWERPC, macho::CPU_SUBTYPE_POWERPC_ALL), @@ -358,6 +429,18 @@ impl<'a> Object<'a> { }, ); + if let Some(version) = &self.macho_build_version { + debug_assert_eq!(build_version_offset, buffer.len()); + buffer.write(&macho::BuildVersionCommand { + cmd: U32::new(endian, macho::LC_BUILD_VERSION), + cmdsize: U32::new(endian, version.cmdsize()), + platform: U32::new(endian, version.platform), + minos: U32::new(endian, version.minos), + sdk: U32::new(endian, version.sdk), + ntools: U32::new(endian, 0), + }); + } + // Write segment command. debug_assert_eq!(segment_command_offset, buffer.len()); macho.write_segment_command( @@ -406,7 +489,7 @@ impl<'a> Object<'a> { macho::S_ATTR_PURE_INSTRUCTIONS | macho::S_ATTR_SOME_INSTRUCTIONS } SectionKind::Data => 0, - SectionKind::ReadOnlyData => 0, + SectionKind::ReadOnlyData | SectionKind::ReadOnlyDataWithRel => 0, SectionKind::ReadOnlyString => macho::S_CSTRING_LITERALS, SectionKind::UninitializedData | SectionKind::Common => macho::S_ZEROFILL, SectionKind::Tls => macho::S_THREAD_LOCAL_REGULAR, @@ -592,39 +675,48 @@ impl<'a> Object<'a> { return Err(Error(format!("unimplemented relocation {:?}", reloc))); } }, - Architecture::Aarch64 => match (reloc.kind, reloc.encoding, reloc.addend) { - (RelocationKind::Absolute, RelocationEncoding::Generic, 0) => { - (false, macho::ARM64_RELOC_UNSIGNED) - } - (RelocationKind::Relative, RelocationEncoding::AArch64Call, 0) => { - (true, macho::ARM64_RELOC_BRANCH26) - } - // Non-zero addend, so we have to encode the addend separately - (RelocationKind::Relative, RelocationEncoding::AArch64Call, value) => { - // first emit the BR26 relocation - let reloc_info = macho::RelocationInfo { - r_address: reloc.offset as u32, - r_symbolnum, - r_pcrel: true, - r_length, - r_extern: true, - r_type: macho::ARM64_RELOC_BRANCH26, - }; - buffer.write(&reloc_info.relocation(endian)); - - // set up a separate relocation for the addend - r_symbolnum = value as u32; - (false, macho::ARM64_RELOC_ADDEND) - } - ( - RelocationKind::MachO { value, relative }, - RelocationEncoding::Generic, - 0, - ) => (relative, value), - _ => { - return Err(Error(format!("unimplemented relocation {:?}", reloc))); + Architecture::Aarch64 | Architecture::Aarch64_Ilp32 => { + match (reloc.kind, reloc.encoding, reloc.addend) { + (RelocationKind::Absolute, RelocationEncoding::Generic, 0) => { + (false, macho::ARM64_RELOC_UNSIGNED) + } + (RelocationKind::Relative, RelocationEncoding::AArch64Call, 0) => { + (true, macho::ARM64_RELOC_BRANCH26) + } + // Non-zero addend, so we have to encode the addend separately + ( + RelocationKind::Relative, + RelocationEncoding::AArch64Call, + value, + ) => { + // first emit the BR26 relocation + let reloc_info = macho::RelocationInfo { + r_address: reloc.offset as u32, + r_symbolnum, + r_pcrel: true, + r_length, + r_extern: true, + r_type: macho::ARM64_RELOC_BRANCH26, + }; + buffer.write(&reloc_info.relocation(endian)); + + // set up a separate relocation for the addend + r_symbolnum = value as u32; + (false, macho::ARM64_RELOC_ADDEND) + } + ( + RelocationKind::MachO { value, relative }, + RelocationEncoding::Generic, + 0, + ) => (relative, value), + _ => { + return Err(Error(format!( + "unimplemented relocation {:?}", + reloc + ))); + } } - }, + } _ => { if let RelocationKind::MachO { value, relative } = reloc.kind { (relative, value) diff --git a/vendor/object/src/write/mod.rs b/vendor/object/src/write/mod.rs index aa4980b1e..711ff16d2 100644 --- a/vendor/object/src/write/mod.rs +++ b/vendor/object/src/write/mod.rs @@ -25,10 +25,15 @@ pub mod elf; #[cfg(feature = "macho")] mod macho; +#[cfg(feature = "macho")] +pub use macho::MachOBuildVersion; #[cfg(feature = "pe")] pub mod pe; +#[cfg(feature = "xcoff")] +mod xcoff; + mod string; pub use string::StringId; @@ -41,7 +46,7 @@ pub struct Error(String); impl fmt::Display for Error { #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.0) } } @@ -52,7 +57,7 @@ impl error::Error for Error {} /// The result type used within the write module. pub type Result = result::Result; -/// A writable object file. +/// A writable relocatable object file. #[derive(Debug)] pub struct Object<'a> { format: BinaryFormat, @@ -70,6 +75,8 @@ pub struct Object<'a> { pub mangling: Mangling, /// Mach-O "_tlv_bootstrap" symbol. tlv_bootstrap: Option, + #[cfg(feature = "macho")] + macho_build_version: Option, } impl<'a> Object<'a> { @@ -88,6 +95,8 @@ impl<'a> Object<'a> { flags: FileFlags::None, mangling: Mangling::default(format, architecture), tlv_bootstrap: None, + #[cfg(feature = "macho")] + macho_build_version: None, } } @@ -171,8 +180,10 @@ impl<'a> Object<'a> { .get(§ion) .cloned() .unwrap_or_else(|| { - let (segment, name, kind) = self.section_info(section); - self.add_section(segment.to_vec(), name.to_vec(), kind) + let (segment, name, kind, flags) = self.section_info(section); + let id = self.add_section(segment.to_vec(), name.to_vec(), kind); + self.section_mut(id).flags = flags; + id }) } @@ -197,7 +208,7 @@ impl<'a> Object<'a> { 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); + let (segment, name, kind, _flags) = self.section_info(*standard_section); if segment == &*section.segment && name == &*section.name && kind == section.kind { self.standard_sections.insert(*standard_section, id); } @@ -210,7 +221,7 @@ impl<'a> Object<'a> { fn section_info( &self, section: StandardSection, - ) -> (&'static [u8], &'static [u8], SectionKind) { + ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { match self.format { #[cfg(feature = "coff")] BinaryFormat::Coff => self.coff_section_info(section), @@ -218,6 +229,8 @@ impl<'a> Object<'a> { BinaryFormat::Elf => self.elf_section_info(section), #[cfg(feature = "macho")] BinaryFormat::MachO => self.macho_section_info(section), + #[cfg(feature = "xcoff")] + BinaryFormat::Xcoff => self.xcoff_section_info(section), _ => unimplemented!(), } } @@ -234,8 +247,10 @@ impl<'a> Object<'a> { 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 (segment, name, kind, flags) = self.subsection_info(section, name); + let id = self.add_section(segment.to_vec(), name, kind); + self.section_mut(id).flags = flags; + id }; let offset = self.append_section_data(section_id, data, align); (section_id, offset) @@ -243,7 +258,7 @@ impl<'a> Object<'a> { fn has_subsections_via_symbols(&self) -> bool { match self.format { - BinaryFormat::Coff | BinaryFormat::Elf => false, + BinaryFormat::Coff | BinaryFormat::Elf | BinaryFormat::Xcoff => false, BinaryFormat::MachO => true, _ => unimplemented!(), } @@ -261,10 +276,10 @@ impl<'a> Object<'a> { &self, section: StandardSection, value: &[u8], - ) -> (&'static [u8], Vec, SectionKind) { - let (segment, section, kind) = self.section_info(section); + ) -> (&'static [u8], Vec, SectionKind, SectionFlags) { + let (segment, section, kind, flags) = self.section_info(section); let name = self.subsection_name(section, value); - (segment, name, kind) + (segment, name, kind, flags) } #[allow(unused_variables)] @@ -506,6 +521,8 @@ impl<'a> Object<'a> { BinaryFormat::Elf => self.elf_fixup_relocation(&mut relocation)?, #[cfg(feature = "macho")] BinaryFormat::MachO => self.macho_fixup_relocation(&mut relocation), + #[cfg(feature = "xcoff")] + BinaryFormat::Xcoff => self.xcoff_fixup_relocation(&mut relocation), _ => unimplemented!(), }; if addend != 0 { @@ -574,6 +591,8 @@ impl<'a> Object<'a> { BinaryFormat::Elf => self.elf_write(buffer), #[cfg(feature = "macho")] BinaryFormat::MachO => self.macho_write(buffer), + #[cfg(feature = "xcoff")] + BinaryFormat::Xcoff => self.xcoff_write(buffer), _ => unimplemented!(), } } @@ -607,6 +626,8 @@ pub enum StandardSection { TlsVariables, /// Common data. Only supported for Mach-O. Common, + /// Notes for GNU properties. Only supported for ELF. + GnuProperty, } impl StandardSection { @@ -615,15 +636,15 @@ impl StandardSection { match self { StandardSection::Text => SectionKind::Text, StandardSection::Data => SectionKind::Data, - StandardSection::ReadOnlyData | StandardSection::ReadOnlyDataWithRel => { - SectionKind::ReadOnlyData - } + StandardSection::ReadOnlyData => SectionKind::ReadOnlyData, + StandardSection::ReadOnlyDataWithRel => SectionKind::ReadOnlyDataWithRel, StandardSection::ReadOnlyString => SectionKind::ReadOnlyString, StandardSection::UninitializedData => SectionKind::UninitializedData, StandardSection::Tls => SectionKind::Tls, StandardSection::UninitializedTls => SectionKind::UninitializedTls, StandardSection::TlsVariables => SectionKind::TlsVariables, StandardSection::Common => SectionKind::Common, + StandardSection::GnuProperty => SectionKind::Note, } } @@ -640,6 +661,7 @@ impl StandardSection { StandardSection::UninitializedTls, StandardSection::TlsVariables, StandardSection::Common, + StandardSection::GnuProperty, ] } } @@ -718,7 +740,7 @@ impl<'a> Section<'a> { offset as u64 } - /// Append unitialized data to a section. + /// Append uninitialized data to a section. /// /// Must not be called for sections that contain initialized data. pub fn append_bss(&mut self, size: u64, align: u64) -> u64 { @@ -733,7 +755,7 @@ impl<'a> Section<'a> { self.size = offset; } self.size += size; - offset as u64 + offset } /// Returns the section as-built so far. @@ -807,7 +829,7 @@ pub struct Symbol { /// The section containing the symbol. pub section: SymbolSection, /// Symbol flags that are specific to each file format. - pub flags: SymbolFlags, + pub flags: SymbolFlags, } impl Symbol { @@ -894,6 +916,8 @@ pub enum Mangling { Elf, /// Mach-O symbol mangling. MachO, + /// Xcoff symbol mangling. + Xcoff, } impl Mangling { @@ -904,6 +928,7 @@ impl Mangling { (BinaryFormat::Coff, _) => Mangling::Coff, (BinaryFormat::Elf, _) => Mangling::Elf, (BinaryFormat::MachO, _) => Mangling::MachO, + (BinaryFormat::Xcoff, _) => Mangling::Xcoff, _ => Mangling::None, } } @@ -911,7 +936,7 @@ impl Mangling { /// Return the prefix to use for global symbols. pub fn global_prefix(self) -> Option { match self { - Mangling::None | Mangling::Elf | Mangling::Coff => None, + Mangling::None | Mangling::Elf | Mangling::Coff | Mangling::Xcoff => None, Mangling::CoffI386 | Mangling::MachO => Some(b'_'), } } diff --git a/vendor/object/src/write/string.rs b/vendor/object/src/write/string.rs index 3bdfcccaa..b23274a0a 100644 --- a/vendor/object/src/write/string.rs +++ b/vendor/object/src/write/string.rs @@ -5,7 +5,7 @@ type IndexSet = indexmap::IndexSet; #[cfg(not(feature = "std"))] type IndexSet = indexmap::IndexSet; -/// An identifer for an entry in a string table. +/// An identifier for an entry in a string table. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct StringId(usize); diff --git a/vendor/object/src/write/util.rs b/vendor/object/src/write/util.rs index 51bc3515f..b05b14d92 100644 --- a/vendor/object/src/write/util.rs +++ b/vendor/object/src/write/util.rs @@ -164,6 +164,56 @@ impl<'a> BytesMut for &'a mut [u8] { } } +/// Write an unsigned number using the LEB128 encoding to a buffer. +/// +/// Returns the number of bytes written. +pub(crate) fn write_uleb128(buf: &mut Vec, mut val: u64) -> usize { + let mut len = 0; + loop { + let mut byte = (val & 0x7f) as u8; + val >>= 7; + let done = val == 0; + if !done { + byte |= 0x80; + } + + buf.push(byte); + len += 1; + + if done { + return len; + } + } +} + +/// Write a signed number using the LEB128 encoding to a buffer. +/// +/// Returns the number of bytes written. +#[allow(dead_code)] +pub(crate) fn write_sleb128(buf: &mut Vec, mut val: i64) -> usize { + let mut len = 0; + loop { + let mut byte = val as u8; + // Keep the sign bit for testing + val >>= 6; + let done = val == 0 || val == -1; + if done { + byte &= !0x80; + } else { + // Remove the sign bit + val >>= 1; + byte |= 0x80; + } + + buf.push(byte); + len += 1; + + if done { + return len; + } + } +} + pub(crate) fn align(offset: usize, size: usize) -> usize { (offset + (size - 1)) & !(size - 1) } diff --git a/vendor/object/src/write/xcoff.rs b/vendor/object/src/write/xcoff.rs new file mode 100644 index 000000000..6c9a80384 --- /dev/null +++ b/vendor/object/src/write/xcoff.rs @@ -0,0 +1,556 @@ +use core::mem; + +use crate::endian::{BigEndian as BE, I16, U16, U32}; +use crate::write::string::*; +use crate::write::util::*; +use crate::write::*; + +use crate::{xcoff, AddressSize}; + +#[derive(Default, Clone, Copy)] +struct SectionOffsets { + address: u64, + data_offset: usize, + reloc_offset: usize, +} + +#[derive(Default, Clone, Copy)] +struct SymbolOffsets { + index: usize, + str_id: Option, + aux_count: u8, + storage_class: u8, +} + +impl<'a> Object<'a> { + pub(crate) fn xcoff_section_info( + &self, + section: StandardSection, + ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { + match section { + StandardSection::Text => (&[], &b".text"[..], SectionKind::Text, SectionFlags::None), + StandardSection::Data => (&[], &b".data"[..], SectionKind::Data, SectionFlags::None), + StandardSection::ReadOnlyData + | StandardSection::ReadOnlyDataWithRel + | StandardSection::ReadOnlyString => ( + &[], + &b".rdata"[..], + SectionKind::ReadOnlyData, + SectionFlags::None, + ), + StandardSection::UninitializedData => ( + &[], + &b".bss"[..], + SectionKind::UninitializedData, + SectionFlags::None, + ), + StandardSection::Tls => (&[], &b".tdata"[..], SectionKind::Tls, SectionFlags::None), + StandardSection::UninitializedTls => ( + &[], + &b".tbss"[..], + SectionKind::UninitializedTls, + SectionFlags::None, + ), + StandardSection::TlsVariables => { + // Unsupported section. + (&[], &[], SectionKind::TlsVariables, SectionFlags::None) + } + StandardSection::Common => { + // Unsupported section. + (&[], &[], SectionKind::Common, SectionFlags::None) + } + StandardSection::GnuProperty => { + // Unsupported section. + (&[], &[], SectionKind::Note, SectionFlags::None) + } + } + } + + pub(crate) fn xcoff_fixup_relocation(&mut self, mut relocation: &mut Relocation) -> i64 { + let constant = match relocation.kind { + RelocationKind::Relative => relocation.addend + 4, + _ => relocation.addend, + }; + relocation.addend -= constant; + constant + } + + pub(crate) fn xcoff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { + let is_64 = match self.architecture.address_size().unwrap() { + AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => false, + AddressSize::U64 => true, + }; + + let (hdr_size, sechdr_size, rel_size, sym_size) = if is_64 { + ( + mem::size_of::(), + mem::size_of::(), + mem::size_of::(), + mem::size_of::(), + ) + } else { + ( + mem::size_of::(), + mem::size_of::(), + mem::size_of::(), + mem::size_of::(), + ) + }; + + // Calculate offsets and build strtab. + let mut offset = 0; + let mut strtab = StringTable::default(); + // We place the shared address 0 immediately after the section header table. + let mut address = 0; + + // XCOFF file header. + offset += hdr_size; + // Section headers. + offset += self.sections.len() * sechdr_size; + + // Calculate size of section data. + let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()]; + for (index, section) in self.sections.iter().enumerate() { + let len = section.data.len(); + let sectype = section.kind; + // Section address should be 0 for all sections except the .text, .data, and .bss sections. + if sectype == SectionKind::Data + || sectype == SectionKind::Text + || sectype == SectionKind::UninitializedData + { + section_offsets[index].address = address as u64; + address += len; + address = align(address, 4); + } else { + section_offsets[index].address = 0; + } + if len != 0 { + // Set the default section alignment as 4. + offset = align(offset, 4); + section_offsets[index].data_offset = offset; + offset += len; + } else { + section_offsets[index].data_offset = 0; + } + } + + // Calculate size of relocations. + for (index, section) in self.sections.iter().enumerate() { + let count = section.relocations.len(); + if count != 0 { + section_offsets[index].reloc_offset = offset; + offset += count * rel_size; + } else { + section_offsets[index].reloc_offset = 0; + } + } + + // Calculate size of symbols. + let mut file_str_id = None; + let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; + let mut symtab_count = 0; + for (index, symbol) in self.symbols.iter().enumerate() { + symbol_offsets[index].index = symtab_count; + symtab_count += 1; + + let storage_class = if let SymbolFlags::Xcoff { n_sclass, .. } = symbol.flags { + n_sclass + } else { + match symbol.kind { + SymbolKind::Null => xcoff::C_NULL, + SymbolKind::File => xcoff::C_FILE, + SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => { + if symbol.is_local() { + xcoff::C_STAT + } else if symbol.weak { + xcoff::C_WEAKEXT + } else { + xcoff::C_EXT + } + } + SymbolKind::Section | SymbolKind::Label | SymbolKind::Unknown => { + return Err(Error(format!( + "unimplemented symbol `{}` kind {:?}", + symbol.name().unwrap_or(""), + symbol.kind + ))); + } + } + }; + symbol_offsets[index].storage_class = storage_class; + + if storage_class == xcoff::C_FILE { + if is_64 && file_str_id.is_none() { + file_str_id = Some(strtab.add(b".file")); + } + if symbol.name.len() > 8 { + symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); + } + } else if is_64 || symbol.name.len() > 8 { + symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); + } + + symbol_offsets[index].aux_count = 0; + match storage_class { + xcoff::C_FILE => { + symbol_offsets[index].aux_count = 1; + symtab_count += 1; + } + xcoff::C_EXT | xcoff::C_WEAKEXT | xcoff::C_HIDEXT => { + symbol_offsets[index].aux_count = 1; + symtab_count += 1; + } + // TODO: support auxiliary entry for other types of symbol. + _ => {} + } + } + let symtab_offset = offset; + let symtab_len = symtab_count * sym_size; + offset += symtab_len; + + // Calculate size of strtab. + let strtab_offset = offset; + let mut strtab_data = Vec::new(); + // First 4 bytes of strtab are the length. + strtab.write(4, &mut strtab_data); + let strtab_len = strtab_data.len() + 4; + offset += strtab_len; + + // Start writing. + buffer + .reserve(offset) + .map_err(|_| Error(String::from("Cannot allocate buffer")))?; + + // Write file header. + if is_64 { + let header = xcoff::FileHeader64 { + f_magic: U16::new(BE, xcoff::MAGIC_64), + f_nscns: U16::new(BE, self.sections.len() as u16), + f_timdat: U32::new(BE, 0), + f_symptr: U64::new(BE, symtab_offset as u64), + f_nsyms: U32::new(BE, symtab_count as u32), + f_opthdr: U16::new(BE, 0), + f_flags: match self.flags { + FileFlags::Xcoff { f_flags } => U16::new(BE, f_flags), + _ => U16::default(), + }, + }; + buffer.write(&header); + } else { + let header = xcoff::FileHeader32 { + f_magic: U16::new(BE, xcoff::MAGIC_32), + f_nscns: U16::new(BE, self.sections.len() as u16), + f_timdat: U32::new(BE, 0), + f_symptr: U32::new(BE, symtab_offset as u32), + f_nsyms: U32::new(BE, symtab_count as u32), + f_opthdr: U16::new(BE, 0), + f_flags: match self.flags { + FileFlags::Xcoff { f_flags } => U16::new(BE, f_flags), + _ => U16::default(), + }, + }; + buffer.write(&header); + } + + // Write section headers. + for (index, section) in self.sections.iter().enumerate() { + let mut sectname = [0; 8]; + sectname + .get_mut(..section.name.len()) + .ok_or_else(|| { + Error(format!( + "section name `{}` is too long", + section.name().unwrap_or(""), + )) + })? + .copy_from_slice(§ion.name); + let flags = if let SectionFlags::Xcoff { s_flags } = section.flags { + s_flags + } else { + match section.kind { + SectionKind::Text + | SectionKind::ReadOnlyData + | SectionKind::ReadOnlyString + | SectionKind::ReadOnlyDataWithRel => xcoff::STYP_TEXT, + SectionKind::Data => xcoff::STYP_DATA, + SectionKind::UninitializedData => xcoff::STYP_BSS, + SectionKind::Tls => xcoff::STYP_TDATA, + SectionKind::UninitializedTls => xcoff::STYP_TBSS, + SectionKind::OtherString => xcoff::STYP_INFO, + SectionKind::Debug => xcoff::STYP_DEBUG, + SectionKind::Other | SectionKind::Metadata => 0, + SectionKind::Note + | SectionKind::Linker + | SectionKind::Common + | SectionKind::Unknown + | SectionKind::TlsVariables + | SectionKind::Elf(_) => { + return Err(Error(format!( + "unimplemented section `{}` kind {:?}", + section.name().unwrap_or(""), + section.kind + ))); + } + } + .into() + }; + if is_64 { + let section_header = xcoff::SectionHeader64 { + s_name: sectname, + s_paddr: U64::new(BE, section_offsets[index].address), + // This field has the same value as the s_paddr field. + s_vaddr: U64::new(BE, section_offsets[index].address), + s_size: U64::new(BE, section.data.len() as u64), + s_scnptr: U64::new(BE, section_offsets[index].data_offset as u64), + s_relptr: U64::new(BE, section_offsets[index].reloc_offset as u64), + s_lnnoptr: U64::new(BE, 0), + s_nreloc: U32::new(BE, section.relocations.len() as u32), + s_nlnno: U32::new(BE, 0), + s_flags: U32::new(BE, flags), + s_reserve: U32::new(BE, 0), + }; + buffer.write(§ion_header); + } else { + let section_header = xcoff::SectionHeader32 { + s_name: sectname, + s_paddr: U32::new(BE, section_offsets[index].address as u32), + // This field has the same value as the s_paddr field. + s_vaddr: U32::new(BE, section_offsets[index].address as u32), + s_size: U32::new(BE, section.data.len() as u32), + s_scnptr: U32::new(BE, section_offsets[index].data_offset as u32), + s_relptr: U32::new(BE, section_offsets[index].reloc_offset as u32), + s_lnnoptr: U32::new(BE, 0), + // TODO: If more than 65,534 relocation entries are required, the field + // value will be 65535, and an STYP_OVRFLO section header will contain + // the actual count of relocation entries in the s_paddr field. + s_nreloc: U16::new(BE, section.relocations.len() as u16), + s_nlnno: U16::new(BE, 0), + s_flags: U32::new(BE, flags), + }; + buffer.write(§ion_header); + } + } + + // Write section data. + for (index, section) in self.sections.iter().enumerate() { + let len = section.data.len(); + if len != 0 { + write_align(buffer, 4); + debug_assert_eq!(section_offsets[index].data_offset, buffer.len()); + buffer.write_bytes(§ion.data); + } + } + + // Write relocations. + for (index, section) in self.sections.iter().enumerate() { + if !section.relocations.is_empty() { + debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); + for reloc in §ion.relocations { + let rtype = match reloc.kind { + RelocationKind::Absolute => xcoff::R_POS, + RelocationKind::Relative => xcoff::R_REL, + RelocationKind::Got => xcoff::R_TOC, + RelocationKind::Xcoff(x) => x, + _ => { + return Err(Error(format!("unimplemented relocation {:?}", reloc))); + } + }; + if is_64 { + let xcoff_rel = xcoff::Rel64 { + r_vaddr: U64::new(BE, reloc.offset), + r_symndx: U32::new(BE, symbol_offsets[reloc.symbol.0].index as u32), + // Specifies the bit length of the relocatable reference minus one. + r_rsize: (reloc.size - 1), + r_rtype: rtype, + }; + buffer.write(&xcoff_rel); + } else { + let xcoff_rel = xcoff::Rel32 { + r_vaddr: U32::new(BE, reloc.offset as u32), + r_symndx: U32::new(BE, symbol_offsets[reloc.symbol.0].index as u32), + r_rsize: (reloc.size - 1), + r_rtype: rtype, + }; + buffer.write(&xcoff_rel); + } + } + } + } + + // Write symbols. + debug_assert_eq!(symtab_offset, buffer.len()); + for (index, symbol) in self.symbols.iter().enumerate() { + let (n_value, section_kind) = if let SymbolSection::Section(id) = symbol.section { + ( + section_offsets[id.0].address + symbol.value, + self.sections[id.0].kind, + ) + } else { + (symbol.value, SectionKind::Unknown) + }; + let n_scnum = match symbol.section { + SymbolSection::None => { + debug_assert_eq!(symbol.kind, SymbolKind::File); + xcoff::N_DEBUG + } + SymbolSection::Undefined | SymbolSection::Common => xcoff::N_UNDEF, + SymbolSection::Absolute => xcoff::N_ABS, + SymbolSection::Section(id) => id.0 as i16 + 1, + }; + let n_sclass = symbol_offsets[index].storage_class; + let n_type = if (symbol.scope == SymbolScope::Linkage) + && (n_sclass == xcoff::C_EXT + || n_sclass == xcoff::C_WEAKEXT + || n_sclass == xcoff::C_HIDEXT) + { + xcoff::SYM_V_HIDDEN + } else { + 0 + }; + let n_numaux = symbol_offsets[index].aux_count; + if is_64 { + let str_id = if n_sclass == xcoff::C_FILE { + file_str_id.unwrap() + } else { + symbol_offsets[index].str_id.unwrap() + }; + let xcoff_sym = xcoff::Symbol64 { + n_value: U64::new(BE, n_value), + n_offset: U32::new(BE, strtab.get_offset(str_id) as u32), + n_scnum: I16::new(BE, n_scnum), + n_type: U16::new(BE, n_type), + n_sclass, + n_numaux, + }; + buffer.write(&xcoff_sym); + } else { + let mut sym_name = [0; 8]; + if n_sclass == xcoff::C_FILE { + sym_name[..5].copy_from_slice(b".file"); + } else if symbol.name.len() <= 8 { + sym_name[..symbol.name.len()].copy_from_slice(&symbol.name[..]); + } else { + let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap()); + sym_name[4..8].copy_from_slice(&u32::to_be_bytes(str_offset as u32)); + } + let xcoff_sym = xcoff::Symbol32 { + n_name: sym_name, + n_value: U32::new(BE, n_value as u32), + n_scnum: I16::new(BE, n_scnum), + n_type: U16::new(BE, n_type), + n_sclass, + n_numaux, + }; + buffer.write(&xcoff_sym); + } + // Generate auxiliary entries. + if n_sclass == xcoff::C_FILE { + debug_assert_eq!(n_numaux, 1); + let mut x_fname = [0; 8]; + if symbol.name.len() <= 8 { + x_fname[..symbol.name.len()].copy_from_slice(&symbol.name[..]); + } else { + let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap()); + x_fname[4..8].copy_from_slice(&u32::to_be_bytes(str_offset as u32)); + } + if is_64 { + let file_aux = xcoff::FileAux64 { + x_fname, + x_fpad: Default::default(), + x_ftype: xcoff::XFT_FN, + x_freserve: Default::default(), + x_auxtype: xcoff::AUX_FILE, + }; + buffer.write(&file_aux); + } else { + let file_aux = xcoff::FileAux32 { + x_fname, + x_fpad: Default::default(), + x_ftype: xcoff::XFT_FN, + x_freserve: Default::default(), + }; + buffer.write(&file_aux); + } + } else if n_sclass == xcoff::C_EXT + || n_sclass == xcoff::C_WEAKEXT + || n_sclass == xcoff::C_HIDEXT + { + debug_assert_eq!(n_numaux, 1); + let (x_smtyp, x_smclas) = if let SymbolFlags::Xcoff { + x_smtyp, x_smclas, .. + } = symbol.flags + { + (x_smtyp, x_smclas) + } else { + match symbol.kind { + SymbolKind::Text => (xcoff::XTY_SD, xcoff::XMC_PR), + SymbolKind::Data => { + if section_kind == SectionKind::UninitializedData { + (xcoff::XTY_CM, xcoff::XMC_BS) + } else if section_kind == SectionKind::ReadOnlyData { + (xcoff::XTY_SD, xcoff::XMC_RO) + } else { + (xcoff::XTY_SD, xcoff::XMC_RW) + } + } + SymbolKind::Tls => { + if section_kind == SectionKind::UninitializedTls { + (xcoff::XTY_CM, xcoff::XMC_UL) + } else { + (xcoff::XTY_SD, xcoff::XMC_TL) + } + } + _ => { + return Err(Error(format!( + "unimplemented symbol `{}` kind {:?}", + symbol.name().unwrap_or(""), + symbol.kind + ))); + } + } + }; + let scnlen = if let SymbolFlags::Xcoff { + containing_csect: Some(containing_csect), + .. + } = symbol.flags + { + symbol_offsets[containing_csect.0].index as u64 + } else { + symbol.size + }; + if is_64 { + let csect_aux = xcoff::CsectAux64 { + x_scnlen_lo: U32::new(BE, (scnlen & 0xFFFFFFFF) as u32), + x_scnlen_hi: U32::new(BE, ((scnlen >> 32) & 0xFFFFFFFF) as u32), + x_parmhash: U32::new(BE, 0), + x_snhash: U16::new(BE, 0), + x_smtyp, + x_smclas, + pad: 0, + x_auxtype: xcoff::AUX_CSECT, + }; + buffer.write(&csect_aux); + } else { + let csect_aux = xcoff::CsectAux32 { + x_scnlen: U32::new(BE, scnlen as u32), + x_parmhash: U32::new(BE, 0), + x_snhash: U16::new(BE, 0), + x_smtyp, + x_smclas, + x_stab: U32::new(BE, 0), + x_snstab: U16::new(BE, 0), + }; + buffer.write(&csect_aux); + } + } + } + + // Write string table. + debug_assert_eq!(strtab_offset, buffer.len()); + buffer.write_bytes(&u32::to_be_bytes(strtab_len as u32)); + buffer.write_bytes(&strtab_data); + + debug_assert_eq!(offset, buffer.len()); + Ok(()) + } +} -- cgit v1.2.3