summaryrefslogtreecommitdiffstats
path: root/vendor/object/src/write
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/object/src/write
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/object/src/write')
-rw-r--r--vendor/object/src/write/coff.rs52
-rw-r--r--vendor/object/src/write/elf/object.rs115
-rw-r--r--vendor/object/src/write/elf/writer.rs196
-rw-r--r--vendor/object/src/write/macho.rs198
-rw-r--r--vendor/object/src/write/mod.rs63
-rw-r--r--vendor/object/src/write/string.rs2
-rw-r--r--vendor/object/src/write/util.rs50
-rw-r--r--vendor/object/src/write/xcoff.rs556
8 files changed, 1107 insertions, 125 deletions
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<StringId>,
}
+// Public methods.
+impl<'a> Object<'a> {
+ /// Add a property with a u32 value to the ELF ".note.gnu.property" section.
+ ///
+ /// Requires `feature = "elf"`.
+ pub fn add_elf_gnu_property_u32(&mut self, property: u32, value: u32) {
+ if self.format != BinaryFormat::Elf {
+ return;
+ }
+
+ let align = if self.elf_is_64() { 8 } else { 4 };
+ let mut data = Vec::with_capacity(32);
+ let n_name = b"GNU\0";
+ data.extend_from_slice(pod::bytes_of(&elf::NoteHeader32 {
+ n_namesz: U32::new(self.endian, n_name.len() as u32),
+ n_descsz: U32::new(self.endian, util::align(3 * 4, align) as u32),
+ n_type: U32::new(self.endian, elf::NT_GNU_PROPERTY_TYPE_0),
+ }));
+ data.extend_from_slice(n_name);
+ // This happens to already be aligned correctly.
+ debug_assert_eq!(util::align(data.len(), align), data.len());
+ data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, property)));
+ // Value size
+ data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, 4)));
+ data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, value)));
+ util::write_align(&mut data, align);
+
+ let section = self.section_id(StandardSection::GnuProperty);
+ self.append_section_data(section, &data, align as u64);
+ }
+}
+
+// Private methods.
impl<'a> Object<'a> {
pub(crate) fn elf_section_info(
&self,
section: StandardSection,
- ) -> (&'static [u8], &'static [u8], SectionKind) {
+ ) -> (&'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(&section.data);
- }
+ writer.write_align(section.align as usize);
+ debug_assert_eq!(section_offsets[index].offset, writer.len());
+ writer.write(&section.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<StringId>,
+ 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<u8>,
+ subsection_offset: usize,
+ subsubsection_offset: usize,
+}
+
+impl AttributesWriter {
+ /// Create a new `AttributesWriter` for the given endianness.
+ pub fn new(endian: Endianness) -> Self {
+ AttributesWriter {
+ endian,
+ data: vec![0x41],
+ subsection_offset: 0,
+ subsubsection_offset: 0,
+ }
+ }
+
+ /// Start a new subsection with the given vendor name.
+ pub fn start_subsection(&mut self, vendor: &[u8]) {
+ debug_assert_eq!(self.subsection_offset, 0);
+ debug_assert_eq!(self.subsubsection_offset, 0);
+ self.subsection_offset = self.data.len();
+ self.data.extend_from_slice(&[0; 4]);
+ self.data.extend_from_slice(vendor);
+ self.data.push(0);
+ }
+
+ /// End the subsection.
+ ///
+ /// The subsection length is automatically calculated and written.
+ pub fn end_subsection(&mut self) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_eq!(self.subsubsection_offset, 0);
+ let length = self.data.len() - self.subsection_offset;
+ self.data[self.subsection_offset..][..4]
+ .copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32)));
+ self.subsection_offset = 0;
+ }
+
+ /// Start a new sub-subsection with the given tag.
+ pub fn start_subsubsection(&mut self, tag: u8) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_eq!(self.subsubsection_offset, 0);
+ self.subsubsection_offset = self.data.len();
+ self.data.push(tag);
+ self.data.extend_from_slice(&[0; 4]);
+ }
+
+ /// Write a section or symbol index to the sub-subsection.
+ ///
+ /// The user must also call this function to write the terminating 0 index.
+ pub fn write_subsubsection_index(&mut self, index: u32) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ util::write_uleb128(&mut self.data, u64::from(index));
+ }
+
+ /// Write raw index data to the sub-subsection.
+ ///
+ /// The terminating 0 index is automatically written.
+ pub fn write_subsubsection_indices(&mut self, indices: &[u8]) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ self.data.extend_from_slice(indices);
+ self.data.push(0);
+ }
+
+ /// Write an attribute tag to the sub-subsection.
+ pub fn write_attribute_tag(&mut self, tag: u64) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ util::write_uleb128(&mut self.data, tag);
+ }
+
+ /// Write an attribute integer value to the sub-subsection.
+ pub fn write_attribute_integer(&mut self, value: u64) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ util::write_uleb128(&mut self.data, value);
+ }
+
+ /// Write an attribute string value to the sub-subsection.
+ ///
+ /// The value must not include the null terminator.
+ pub fn write_attribute_string(&mut self, value: &[u8]) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ self.data.extend_from_slice(value);
+ self.data.push(0);
+ }
+
+ /// Write raw attribute data to the sub-subsection.
+ pub fn write_subsubsection_attributes(&mut self, attributes: &[u8]) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ self.data.extend_from_slice(attributes);
+ }
+
+ /// End the sub-subsection.
+ ///
+ /// The sub-subsection length is automatically calculated and written.
+ pub fn end_subsubsection(&mut self) {
+ debug_assert_ne!(self.subsection_offset, 0);
+ debug_assert_ne!(self.subsubsection_offset, 0);
+ let length = self.data.len() - self.subsubsection_offset;
+ self.data[self.subsubsection_offset + 1..][..4]
+ .copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32)));
+ self.subsubsection_offset = 0;
+ }
+
+ /// Return the completed section data.
+ pub fn data(self) -> Vec<u8> {
+ debug_assert_eq!(self.subsection_offset, 0);
+ debug_assert_eq!(self.subsubsection_offset, 0);
+ self.data
+ }
}
/// Native endian version of [`elf::FileHeader64`].
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<StringId>,
}
+/// The customizable portion of a [`macho::BuildVersionCommand`].
+#[derive(Debug, Default, Clone, Copy)]
+#[non_exhaustive] // May want to add the tool list?
+pub struct MachOBuildVersion {
+ /// One of the `PLATFORM_` constants (for example,
+ /// [`object::macho::PLATFORM_MACOS`](macho::PLATFORM_MACOS)).
+ pub platform: u32,
+ /// The minimum OS version, where `X.Y.Z` is encoded in nibbles as
+ /// `xxxx.yy.zz`.
+ pub minos: u32,
+ /// The SDK version as `X.Y.Z`, where `X.Y.Z` is encoded in nibbles as
+ /// `xxxx.yy.zz`.
+ pub sdk: u32,
+}
+
+impl MachOBuildVersion {
+ fn cmdsize(&self) -> u32 {
+ // Same size for both endianness, and we don't have `ntools`.
+ let sz = mem::size_of::<macho::BuildVersionCommand<Endianness>>();
+ debug_assert!(sz <= u32::MAX as usize);
+ sz as u32
+ }
+}
+
+// Public methods.
+impl<'a> Object<'a> {
+ /// Specify 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<T> = result::Result<T, Error>;
-/// 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<SymbolId>,
+ #[cfg(feature = "macho")]
+ macho_build_version: Option<MachOBuildVersion>,
}
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(&section)
.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<u8>, SectionKind) {
- let (segment, section, kind) = self.section_info(section);
+ ) -> (&'static [u8], Vec<u8>, SectionKind, SectionFlags) {
+ let (segment, section, kind, flags) = self.section_info(section);
let name = self.subsection_name(section, value);
- (segment, name, kind)
+ (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<SectionId>,
+ pub flags: SymbolFlags<SectionId, SymbolId>,
}
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<u8> {
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<K> = indexmap::IndexSet<K>;
#[cfg(not(feature = "std"))]
type IndexSet<K> = indexmap::IndexSet<K, hashbrown::hash_map::DefaultHashBuilder>;
-/// 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<u8>, mut val: u64) -> usize {
+ let mut len = 0;
+ loop {
+ let mut byte = (val & 0x7f) as u8;
+ val >>= 7;
+ let done = val == 0;
+ if !done {
+ byte |= 0x80;
+ }
+
+ buf.push(byte);
+ len += 1;
+
+ if done {
+ return len;
+ }
+ }
+}
+
+/// Write a signed number using the LEB128 encoding to a buffer.
+///
+/// Returns the number of bytes written.
+#[allow(dead_code)]
+pub(crate) fn write_sleb128<W>(buf: &mut Vec<u8>, mut val: i64) -> usize {
+ let mut len = 0;
+ loop {
+ let mut byte = val as u8;
+ // Keep the sign bit for testing
+ val >>= 6;
+ let done = val == 0 || val == -1;
+ if done {
+ byte &= !0x80;
+ } else {
+ // Remove the sign bit
+ val >>= 1;
+ byte |= 0x80;
+ }
+
+ buf.push(byte);
+ len += 1;
+
+ if done {
+ return len;
+ }
+ }
+}
+
pub(crate) fn align(offset: usize, size: usize) -> usize {
(offset + (size - 1)) & !(size - 1)
}
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<StringId>,
+ aux_count: u8,
+ storage_class: u8,
+}
+
+impl<'a> Object<'a> {
+ pub(crate) fn xcoff_section_info(
+ &self,
+ section: StandardSection,
+ ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) {
+ match section {
+ StandardSection::Text => (&[], &b".text"[..], SectionKind::Text, SectionFlags::None),
+ StandardSection::Data => (&[], &b".data"[..], SectionKind::Data, SectionFlags::None),
+ StandardSection::ReadOnlyData
+ | StandardSection::ReadOnlyDataWithRel
+ | StandardSection::ReadOnlyString => (
+ &[],
+ &b".rdata"[..],
+ SectionKind::ReadOnlyData,
+ SectionFlags::None,
+ ),
+ StandardSection::UninitializedData => (
+ &[],
+ &b".bss"[..],
+ SectionKind::UninitializedData,
+ SectionFlags::None,
+ ),
+ StandardSection::Tls => (&[], &b".tdata"[..], SectionKind::Tls, SectionFlags::None),
+ StandardSection::UninitializedTls => (
+ &[],
+ &b".tbss"[..],
+ SectionKind::UninitializedTls,
+ SectionFlags::None,
+ ),
+ StandardSection::TlsVariables => {
+ // Unsupported section.
+ (&[], &[], SectionKind::TlsVariables, SectionFlags::None)
+ }
+ StandardSection::Common => {
+ // Unsupported section.
+ (&[], &[], SectionKind::Common, SectionFlags::None)
+ }
+ StandardSection::GnuProperty => {
+ // Unsupported section.
+ (&[], &[], SectionKind::Note, SectionFlags::None)
+ }
+ }
+ }
+
+ pub(crate) fn xcoff_fixup_relocation(&mut self, 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::<xcoff::FileHeader64>(),
+ mem::size_of::<xcoff::SectionHeader64>(),
+ mem::size_of::<xcoff::Rel64>(),
+ mem::size_of::<xcoff::Symbol64>(),
+ )
+ } else {
+ (
+ mem::size_of::<xcoff::FileHeader32>(),
+ mem::size_of::<xcoff::SectionHeader32>(),
+ mem::size_of::<xcoff::Rel32>(),
+ mem::size_of::<xcoff::Symbol32>(),
+ )
+ };
+
+ // Calculate offsets and build strtab.
+ let mut offset = 0;
+ let mut strtab = StringTable::default();
+ // We place the shared address 0 immediately after the section header table.
+ let mut address = 0;
+
+ // XCOFF file header.
+ offset += hdr_size;
+ // Section headers.
+ offset += self.sections.len() * sechdr_size;
+
+ // Calculate size of section data.
+ let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()];
+ for (index, section) in self.sections.iter().enumerate() {
+ let len = section.data.len();
+ let sectype = section.kind;
+ // Section address should be 0 for all sections except the .text, .data, and .bss sections.
+ if sectype == SectionKind::Data
+ || sectype == SectionKind::Text
+ || sectype == SectionKind::UninitializedData
+ {
+ section_offsets[index].address = address as u64;
+ address += len;
+ address = align(address, 4);
+ } else {
+ section_offsets[index].address = 0;
+ }
+ if len != 0 {
+ // Set the default section alignment as 4.
+ offset = align(offset, 4);
+ section_offsets[index].data_offset = offset;
+ offset += len;
+ } else {
+ section_offsets[index].data_offset = 0;
+ }
+ }
+
+ // Calculate size of relocations.
+ for (index, section) in self.sections.iter().enumerate() {
+ let count = section.relocations.len();
+ if count != 0 {
+ section_offsets[index].reloc_offset = offset;
+ offset += count * rel_size;
+ } else {
+ section_offsets[index].reloc_offset = 0;
+ }
+ }
+
+ // Calculate size of symbols.
+ let mut file_str_id = None;
+ let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()];
+ let mut symtab_count = 0;
+ for (index, symbol) in self.symbols.iter().enumerate() {
+ symbol_offsets[index].index = symtab_count;
+ symtab_count += 1;
+
+ let storage_class = if let SymbolFlags::Xcoff { n_sclass, .. } = symbol.flags {
+ n_sclass
+ } else {
+ match symbol.kind {
+ SymbolKind::Null => xcoff::C_NULL,
+ SymbolKind::File => xcoff::C_FILE,
+ SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => {
+ if symbol.is_local() {
+ xcoff::C_STAT
+ } else if symbol.weak {
+ xcoff::C_WEAKEXT
+ } else {
+ xcoff::C_EXT
+ }
+ }
+ SymbolKind::Section | SymbolKind::Label | SymbolKind::Unknown => {
+ return Err(Error(format!(
+ "unimplemented symbol `{}` kind {:?}",
+ symbol.name().unwrap_or(""),
+ symbol.kind
+ )));
+ }
+ }
+ };
+ symbol_offsets[index].storage_class = storage_class;
+
+ if storage_class == xcoff::C_FILE {
+ if is_64 && file_str_id.is_none() {
+ file_str_id = Some(strtab.add(b".file"));
+ }
+ if symbol.name.len() > 8 {
+ symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
+ }
+ } else if is_64 || symbol.name.len() > 8 {
+ symbol_offsets[index].str_id = Some(strtab.add(&symbol.name));
+ }
+
+ symbol_offsets[index].aux_count = 0;
+ match storage_class {
+ xcoff::C_FILE => {
+ symbol_offsets[index].aux_count = 1;
+ symtab_count += 1;
+ }
+ xcoff::C_EXT | xcoff::C_WEAKEXT | xcoff::C_HIDEXT => {
+ symbol_offsets[index].aux_count = 1;
+ symtab_count += 1;
+ }
+ // TODO: support auxiliary entry for other types of symbol.
+ _ => {}
+ }
+ }
+ let symtab_offset = offset;
+ let symtab_len = symtab_count * sym_size;
+ offset += symtab_len;
+
+ // Calculate size of strtab.
+ let strtab_offset = offset;
+ let mut strtab_data = Vec::new();
+ // First 4 bytes of strtab are the length.
+ strtab.write(4, &mut strtab_data);
+ let strtab_len = strtab_data.len() + 4;
+ offset += strtab_len;
+
+ // Start writing.
+ buffer
+ .reserve(offset)
+ .map_err(|_| Error(String::from("Cannot allocate buffer")))?;
+
+ // Write file header.
+ if is_64 {
+ let header = xcoff::FileHeader64 {
+ f_magic: U16::new(BE, xcoff::MAGIC_64),
+ f_nscns: U16::new(BE, self.sections.len() as u16),
+ f_timdat: U32::new(BE, 0),
+ f_symptr: U64::new(BE, symtab_offset as u64),
+ f_nsyms: U32::new(BE, symtab_count as u32),
+ f_opthdr: U16::new(BE, 0),
+ f_flags: match self.flags {
+ FileFlags::Xcoff { f_flags } => U16::new(BE, f_flags),
+ _ => U16::default(),
+ },
+ };
+ buffer.write(&header);
+ } else {
+ let header = xcoff::FileHeader32 {
+ f_magic: U16::new(BE, xcoff::MAGIC_32),
+ f_nscns: U16::new(BE, self.sections.len() as u16),
+ f_timdat: U32::new(BE, 0),
+ f_symptr: U32::new(BE, symtab_offset as u32),
+ f_nsyms: U32::new(BE, symtab_count as u32),
+ f_opthdr: U16::new(BE, 0),
+ f_flags: match self.flags {
+ FileFlags::Xcoff { f_flags } => U16::new(BE, f_flags),
+ _ => U16::default(),
+ },
+ };
+ buffer.write(&header);
+ }
+
+ // Write section headers.
+ for (index, section) in self.sections.iter().enumerate() {
+ let mut sectname = [0; 8];
+ sectname
+ .get_mut(..section.name.len())
+ .ok_or_else(|| {
+ Error(format!(
+ "section name `{}` is too long",
+ section.name().unwrap_or(""),
+ ))
+ })?
+ .copy_from_slice(&section.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(&section_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(&section_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(&section.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 &section.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(())
+ }
+}