Skip to content

Commit

Permalink
write/elf: add Object::add_elf_gnu_property_u32
Browse files Browse the repository at this point in the history
  • Loading branch information
philipc committed May 4, 2023
1 parent 0b232bb commit a1aef17
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 15 deletions.
4 changes: 4 additions & 0 deletions src/write/coff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ impl<'a> Object<'a> {
// Unsupported section.
(&[], &[], SectionKind::Common)
}
StandardSection::GnuProperty => {
// Unsupported section.
(&[], &[], SectionKind::Note)
}
}
}

Expand Down
49 changes: 43 additions & 6 deletions src/write/elf/object.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -27,6 +27,39 @@ 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,
Expand Down Expand Up @@ -56,6 +89,7 @@ impl<'a> Object<'a> {
// Unsupported section.
(&[], &[], SectionKind::Common)
}
StandardSection::GnuProperty => (&[], &b".note.gnu.property"[..], SectionKind::Note),
}
}

Expand Down Expand Up @@ -153,6 +187,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()?;
Expand All @@ -176,11 +217,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.
Expand Down
16 changes: 16 additions & 0 deletions src/write/macho.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ impl MachOBuildVersion {
}
}

// 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 {
Expand Down Expand Up @@ -102,6 +114,10 @@ impl<'a> Object<'a> {
SectionKind::TlsVariables,
),
StandardSection::Common => (&b"__DATA"[..], &b"__common"[..], SectionKind::Common),
StandardSection::GnuProperty => {
// Unsupported section.
(&[], &[], SectionKind::Note)
}
}
}

Expand Down
13 changes: 4 additions & 9 deletions src/write/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,15 +124,6 @@ impl<'a> Object<'a> {
self.mangling = mangling;
}

/// Specify information for a Mach-O `LC_BUILD_VERSION` command.
///
/// Requires `feature = "macho"`.
#[inline]
#[cfg(feature = "macho")]
pub fn set_macho_build_version(&mut self, info: MachOBuildVersion) {
self.macho_build_version = Some(info);
}

/// Return the name for a standard segment.
///
/// This will vary based on the file format.
Expand Down Expand Up @@ -631,6 +622,8 @@ pub enum StandardSection {
TlsVariables,
/// Common data. Only supported for Mach-O.
Common,
/// Notes for GNU properties. Only supported for ELF.
GnuProperty,
}

impl StandardSection {
Expand All @@ -647,6 +640,7 @@ impl StandardSection {
StandardSection::UninitializedTls => SectionKind::UninitializedTls,
StandardSection::TlsVariables => SectionKind::TlsVariables,
StandardSection::Common => SectionKind::Common,
StandardSection::GnuProperty => SectionKind::Note,
}
}

Expand All @@ -663,6 +657,7 @@ impl StandardSection {
StandardSection::UninitializedTls,
StandardSection::TlsVariables,
StandardSection::Common,
StandardSection::GnuProperty,
]
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/write/xcoff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ impl<'a> Object<'a> {
// Unsupported section.
(&[], &[], SectionKind::Common)
}
StandardSection::GnuProperty => {
// Unsupported section.
(&[], &[], SectionKind::Note)
}
}
}

Expand Down
39 changes: 39 additions & 0 deletions tests/round_trip/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,42 @@ fn note() {
assert_eq!(note.n_type(endian), 2);
assert!(notes.next().unwrap().is_none());
}

#[test]
fn gnu_property() {
gnu_property_inner::<elf::FileHeader32<Endianness>>(Architecture::I386);
gnu_property_inner::<elf::FileHeader64<Endianness>>(Architecture::X86_64);
}

fn gnu_property_inner<Elf: FileHeader<Endian = Endianness>>(architecture: Architecture) {
let endian = Endianness::Little;
let mut object = write::Object::new(BinaryFormat::Elf, architecture, endian);
object.add_elf_gnu_property_u32(
elf::GNU_PROPERTY_X86_FEATURE_1_AND,
elf::GNU_PROPERTY_X86_FEATURE_1_IBT | elf::GNU_PROPERTY_X86_FEATURE_1_SHSTK,
);

let bytes = &*object.write().unwrap();

//std::fs::write(&"note.o", &bytes).unwrap();

let header = Elf::parse(bytes).unwrap();
assert_eq!(header.endian().unwrap(), endian);
let sections = header.sections(endian, bytes).unwrap();
let section = sections.section(SectionIndex(1)).unwrap();
assert_eq!(
sections.section_name(endian, section).unwrap(),
b".note.gnu.property"
);
let mut notes = section.notes(endian, bytes).unwrap().unwrap();
let note = notes.next().unwrap().unwrap();
let mut props = note.gnu_properties(endian).unwrap();
let prop = props.next().unwrap().unwrap();
assert_eq!(prop.pr_type(), elf::GNU_PROPERTY_X86_FEATURE_1_AND);
assert_eq!(
prop.data_u32(endian).unwrap(),
elf::GNU_PROPERTY_X86_FEATURE_1_IBT | elf::GNU_PROPERTY_X86_FEATURE_1_SHSTK
);
assert!(props.next().unwrap().is_none());
assert!(notes.next().unwrap().is_none());
}

0 comments on commit a1aef17

Please sign in to comment.