Skip to content

Commit

Permalink
elf: improve attributes section support (gimli-rs#525)
Browse files Browse the repository at this point in the history
- read: add iterator for section and symbol indices
- read: add AttributeReader for parsing attribute data
- write: add AttributesWriter for building the attributes section
- elfcopy: convert section and symbol indices
- elfcopy: handle attributes sections in object files
- readobj: print some contents of attributes sections
  • Loading branch information
philipc authored Mar 27, 2023
1 parent 63d502d commit 7a256e1
Show file tree
Hide file tree
Showing 10 changed files with 613 additions and 148 deletions.
79 changes: 45 additions & 34 deletions crates/examples/src/bin/elfcopy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ fn copy_file<Elf: FileHeader<Endian = Endianness>>(
let mut in_versym = None;
let mut in_verdef = None;
let mut in_verneed = None;
let mut in_attrib = None;
let mut in_attributes = None;
let mut out_sections = Vec::with_capacity(in_sections.len());
let mut out_sections_index = Vec::with_capacity(in_sections.len());
for (i, in_section) in in_sections.iter().enumerate() {
Expand Down Expand Up @@ -268,8 +268,8 @@ fn copy_file<Elf: FileHeader<Endian = Endianness>>(
index = writer.reserve_gnu_verneed_section_index();
}
elf::SHT_GNU_ATTRIBUTES => {
in_attrib = in_section.gnu_attributes(endian, in_data)?;
debug_assert!(in_attrib.is_some());
in_attributes = in_section.gnu_attributes(endian, in_data)?;
debug_assert!(in_attributes.is_some());
index = writer.reserve_gnu_attributes_section_index();
}
other => {
Expand Down Expand Up @@ -434,24 +434,40 @@ fn copy_file<Elf: FileHeader<Endian = Endianness>>(
}
}

// Add one byte for the version field at the start of the section
let mut gnu_attributes_size = 1;
// We will cache all of our attribute data here for later
let mut gnu_attrib_vendor_sections = Vec::new();
if let Some(mut vsections) = in_attrib.clone() {
while let Some((vendor_name, mut tags)) = vsections.next()? {
let mut subsection = Vec::new();
let mut subsection_length = 0;
while let Some((tag, attrib_data)) = tags.next()? {
// Add the size of our tag (1-byte) + the size of the size field (4-bytes)
// plus the size of the sub-section data
subsection_length += 5 + attrib_data.len() as u32;
subsection.push((tag, attrib_data.clone()));
}
// Add the length of our size field + the length of the vendor string + the null byte
gnu_attributes_size += subsection_length as usize + 4 + vendor_name.len() + 1;
gnu_attrib_vendor_sections.push((vendor_name, subsection_length, subsection));
let mut gnu_attributes = Vec::new();
if let Some(attributes) = in_attributes {
let mut writer = writer.attributes_writer();
let mut subsections = attributes.subsections()?;
while let Some(subsection) = subsections.next()? {
writer.start_subsection(subsection.vendor());
let mut subsubsections = subsection.subsubsections();
while let Some(subsubsection) = subsubsections.next()? {
writer.start_subsubsection(subsubsection.tag());
match subsubsection.tag() {
elf::Tag_File => {}
elf::Tag_Section => {
let mut indices = subsubsection.indices();
while let Some(index) = indices.next()? {
writer.write_subsubsection_index(out_sections_index[index as usize].0);
}
writer.write_subsubsection_index(0);
}
elf::Tag_Symbol => {
let mut indices = subsubsection.indices();
while let Some(index) = indices.next()? {
writer.write_subsubsection_index(out_syms_index[index as usize].0);
}
writer.write_subsubsection_index(0);
}
_ => unimplemented!(),
}
writer.write_subsubsection_attributes(subsubsection.attributes_data());
writer.end_subsubsection();
}
writer.end_subsection();
}
gnu_attributes = writer.data();
assert_ne!(gnu_attributes.len(), 0);
}

// Start reserving file ranges.
Expand All @@ -465,7 +481,6 @@ fn copy_file<Elf: FileHeader<Endian = Endianness>>(
let mut dynamic_addr = 0;
let mut dynsym_addr = 0;
let mut dynstr_addr = 0;
let mut attributes_addr = 0;

let mut alloc_sections = Vec::new();
if in_segments.is_empty() {
Expand All @@ -478,6 +493,9 @@ fn copy_file<Elf: FileHeader<Endian = Endianness>>(
in_section.sh_addralign(endian).into() as usize,
);
}
elf::SHT_GNU_ATTRIBUTES => {
writer.reserve_gnu_attributes(gnu_attributes.len());
}
_ => {}
}
}
Expand Down Expand Up @@ -570,8 +588,7 @@ fn copy_file<Elf: FileHeader<Endian = Endianness>>(
);
}
elf::SHT_GNU_ATTRIBUTES => {
attributes_addr = in_section.sh_addr(endian).into();
writer.reserve_gnu_attributes(gnu_attributes_size);
writer.reserve_gnu_attributes(gnu_attributes.len());
}
_ => {}
}
Expand Down Expand Up @@ -621,6 +638,9 @@ fn copy_file<Elf: FileHeader<Endian = Endianness>>(
debug_assert_eq!(out_sections[i].offset, writer.len());
writer.write(in_section.data(endian, in_data)?);
}
elf::SHT_GNU_ATTRIBUTES => {
writer.write_gnu_attributes(&gnu_attributes);
}
_ => {}
}
}
Expand Down Expand Up @@ -806,16 +826,7 @@ fn copy_file<Elf: FileHeader<Endian = Endianness>>(
writer.write(in_section.data(endian, in_data)?);
}
elf::SHT_GNU_ATTRIBUTES => {
writer.write_align_gnu_attributes();
writer.write_gnu_attributes_version();
for (vendor_name, section_length, subsections) in
gnu_attrib_vendor_sections.iter()
{
writer.write_gnu_attributes_subsection(*section_length, vendor_name);
for (tag, tag_data) in subsections.iter() {
writer.write_gnu_attributes_subsubsection(*tag, tag_data);
}
}
writer.write_gnu_attributes(&gnu_attributes);
}
_ => {}
}
Expand Down Expand Up @@ -979,7 +990,7 @@ fn copy_file<Elf: FileHeader<Endian = Endianness>>(
writer.write_gnu_verneed_section_header(verneed_addr);
}
elf::SHT_GNU_ATTRIBUTES => {
writer.write_gnu_attributes_section_header(attributes_addr);
writer.write_gnu_attributes_section_header();
}
other => {
panic!("Unsupported section type {:x}", other);
Expand Down
35 changes: 35 additions & 0 deletions crates/examples/src/readobj/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ fn print_section_headers<Elf: FileHeader>(
SHT_GNU_VERDEF => print_gnu_verdef(p, endian, data, elf, sections, section),
SHT_GNU_VERNEED => print_gnu_verneed(p, endian, data, elf, sections, section),
SHT_GNU_VERSYM => print_gnu_versym(p, endian, data, elf, sections, section),
// TODO: other sections that contain attributes
SHT_GNU_ATTRIBUTES => print_attributes(p, endian, data, elf, section),
// TODO:
//SHT_SHLIB =>
//SHT_INIT_ARRAY =>
Expand Down Expand Up @@ -781,6 +783,38 @@ fn print_gnu_versym<Elf: FileHeader>(
}
}

fn print_attributes<Elf: FileHeader>(
p: &mut Printer<'_>,
endian: Elf::Endian,
data: &[u8],
_elf: &Elf,
section: &Elf::SectionHeader,
) {
if let Some(section) = section.attributes(endian, data).print_err(p) {
p.group("Attributes", |p| {
p.field("Version", section.version());
if let Some(mut subsections) = section.subsections().print_err(p) {
while let Some(Some(subsection)) = subsections.next().print_err(p) {
p.group("Subsection", |p| {
p.field_inline_string("Vendor", subsection.vendor());
let mut subsubsections = subsection.subsubsections();
while let Some(Some(subsubsection)) = subsubsections.next().print_err(p) {
p.group("Subsubsection", |p| {
p.field_enum("Tag", subsubsection.tag(), FLAGS_TAG);
let mut indices = subsubsection.indices();
while let Some(Some(index)) = indices.next().print_err(p) {
p.field("Index", index);
}
// TODO: print attributes
});
}
});
}
}
});
}
}

fn print_version<Elf: FileHeader>(
p: &mut Printer<'_>,
versions: Option<&VersionTable<Elf>>,
Expand Down Expand Up @@ -3303,3 +3337,4 @@ static FLAGS_DF_1: &[Flag<u32>] = &flags!(
static FLAGS_VER_FLG: &[Flag<u16>] = &flags!(VER_FLG_BASE, VER_FLG_WEAK);
static FLAGS_VER_NDX: &[Flag<u16>] = &flags!(VER_NDX_LOCAL, VER_NDX_GLOBAL);
static FLAGS_VERSYM: &[Flag<u16>] = &flags!(VERSYM_HIDDEN);
static FLAGS_TAG: &[Flag<u8>] = &flags!(Tag_File, Tag_Section, Tag_Symbol);
9 changes: 9 additions & 0 deletions crates/examples/testfiles/elf/base-mips64el.o.readobj
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,15 @@ SectionHeader {
Info: 0
AddressAlign: 0x1
EntrySize: 0x0
Attributes {
Version: 65
Subsection {
Vendor: "gnu"
Subsubsection {
Tag: Tag_File (0x1)
}
}
}
}
SectionHeader {
Index: 13
Expand Down
9 changes: 9 additions & 0 deletions crates/examples/testfiles/elf/base-mips64el.readobj
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,15 @@ SectionHeader {
Info: 0
AddressAlign: 0x1
EntrySize: 0x0
Attributes {
Version: 65
Subsection {
Vendor: "gnu"
Subsubsection {
Tag: Tag_File (0x1)
}
}
}
}
SectionHeader {
Index: 28
Expand Down
7 changes: 7 additions & 0 deletions src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6724,6 +6724,13 @@ pub const R_XTENSA_NDIFF16: u32 = 61;
#[allow(missing_docs)]
pub const R_XTENSA_NDIFF32: u32 = 62;

#[allow(missing_docs, non_upper_case_globals)]
pub const Tag_File: u8 = 1;
#[allow(missing_docs, non_upper_case_globals)]
pub const Tag_Section: u8 = 2;
#[allow(missing_docs, non_upper_case_globals)]
pub const Tag_Symbol: u8 = 3;

unsafe_impl_endian_pod!(
FileHeader32,
FileHeader64,
Expand Down
Loading

0 comments on commit 7a256e1

Please sign in to comment.