summaryrefslogtreecommitdiffstats
path: root/vendor/object/src/write/elf
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/elf
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/elf')
-rw-r--r--vendor/object/src/write/elf/object.rs115
-rw-r--r--vendor/object/src/write/elf/writer.rs196
2 files changed, 278 insertions, 33 deletions
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`].