Skip to content

Commit

Permalink
read/elf: add SHT_RELR support
Browse files Browse the repository at this point in the history
  • Loading branch information
philipc committed Dec 1, 2024
1 parent 90ef466 commit ab8f993
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 9 deletions.
19 changes: 19 additions & 0 deletions crates/examples/src/readobj/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ fn print_section_headers<Elf: FileHeader>(
}
SHT_REL => print_section_rel(p, endian, data, elf, sections, section),
SHT_RELA => print_section_rela(p, endian, data, elf, sections, section),
SHT_RELR => print_section_relr(p, endian, data, elf, section),
SHT_NOTE => print_section_notes(p, endian, data, elf, section),
SHT_DYNAMIC => print_section_dynamic(p, endian, data, elf, sections, section),
SHT_GROUP => print_section_group(p, endian, data, elf, sections, section),
Expand Down Expand Up @@ -560,6 +561,23 @@ fn rel_flag_type<Elf: FileHeader>(endian: Elf::Endian, elf: &Elf) -> &'static [F
}
}

fn print_section_relr<Elf: FileHeader>(
p: &mut Printer<'_>,
endian: Elf::Endian,
data: &[u8],
_elf: &Elf,
section: &Elf::SectionHeader,
) {
if !p.options.relocations {
return;
}
if let Some(Some(relocations)) = section.relr(endian, data).print_err(p) {
for relocation in relocations {
p.field_hex("Offset", relocation.into());
}
}
}

fn print_section_notes<Elf: FileHeader>(
p: &mut Printer<'_>,
endian: Elf::Endian,
Expand Down Expand Up @@ -1373,6 +1391,7 @@ const FLAGS_SHT: &[Flag<u32>] = &flags!(
SHT_PREINIT_ARRAY,
SHT_GROUP,
SHT_SYMTAB_SHNDX,
SHT_RELR,
SHT_LLVM_DEPENDENT_LIBRARIES,
SHT_GNU_ATTRIBUTES,
SHT_GNU_HASH,
Expand Down
2 changes: 1 addition & 1 deletion crates/examples/testfiles/elf/base-relr-i686.objdump
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Segment { address: 3ec0, size: 14c }
8: Section { name: ".gnu.version_r", address: 358, size: 50, align: 4, kind: Elf(6ffffffe), flags: Elf { sh_flags: 2 } }
9: Section { name: ".rel.dyn", address: 3a8, size: 20, align: 4, kind: Metadata, flags: Elf { sh_flags: 2 } }
10: Section { name: ".rel.plt", address: 3c8, size: 10, align: 4, kind: Metadata, flags: Elf { sh_flags: 42 } }
11: Section { name: ".relr.dyn", address: 3d8, size: 10, align: 4, kind: Elf(13), flags: Elf { sh_flags: 2 } }
11: Section { name: ".relr.dyn", address: 3d8, size: 10, align: 4, kind: Metadata, flags: Elf { sh_flags: 2 } }
12: Section { name: ".init", address: 1000, size: 20, align: 4, kind: Text, flags: Elf { sh_flags: 6 } }
13: Section { name: ".plt", address: 1020, size: 30, align: 10, kind: Text, flags: Elf { sh_flags: 6 } }
14: Section { name: ".plt.got", address: 1050, size: 8, align: 8, kind: Text, flags: Elf { sh_flags: 6 } }
Expand Down
6 changes: 5 additions & 1 deletion crates/examples/testfiles/elf/base-relr-i686.readobj
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ SectionHeader {
SectionHeader {
Index: 11
Name: ".relr.dyn" (0x8C)
Type: 0x13
Type: SHT_RELR (0x13)
Flags: 0x2
SHF_ALLOC (0x2)
Address: 0x3D8
Expand All @@ -646,6 +646,10 @@ SectionHeader {
Info: 0
AddressAlign: 0x4
EntrySize: 0x4
Offset: 0x3EC0
Offset: 0x3EC4
Offset: 0x3FF8
Offset: 0x4004
}
SectionHeader {
Index: 12
Expand Down
2 changes: 1 addition & 1 deletion crates/examples/testfiles/elf/base-relr-x86_64.objdump
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Segment { address: 3d88, size: 290 }
9: Section { name: ".gnu.version_r", address: 530, size: 40, align: 8, kind: Elf(6ffffffe), flags: Elf { sh_flags: 2 } }
10: Section { name: ".rela.dyn", address: 570, size: 78, align: 8, kind: Metadata, flags: Elf { sh_flags: 2 } }
11: Section { name: ".rela.plt", address: 5e8, size: 18, align: 8, kind: Metadata, flags: Elf { sh_flags: 42 } }
12: Section { name: ".relr.dyn", address: 600, size: 18, align: 8, kind: Elf(13), flags: Elf { sh_flags: 2 } }
12: Section { name: ".relr.dyn", address: 600, size: 18, align: 8, kind: Metadata, flags: Elf { sh_flags: 2 } }
13: Section { name: ".init", address: 1000, size: 1b, align: 4, kind: Text, flags: Elf { sh_flags: 6 } }
14: Section { name: ".plt", address: 1020, size: 20, align: 10, kind: Text, flags: Elf { sh_flags: 6 } }
15: Section { name: ".plt.got", address: 1040, size: 10, align: 10, kind: Text, flags: Elf { sh_flags: 6 } }
Expand Down
5 changes: 4 additions & 1 deletion crates/examples/testfiles/elf/base-relr-x86_64.readobj
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ SectionHeader {
SectionHeader {
Index: 12
Name: ".relr.dyn" (0xA1)
Type: 0x13
Type: SHT_RELR (0x13)
Flags: 0x2
SHF_ALLOC (0x2)
Address: 0x600
Expand All @@ -690,6 +690,9 @@ SectionHeader {
Info: 0
AddressAlign: 0x8
EntrySize: 0x8
Offset: 0x3D88
Offset: 0x3D90
Offset: 0x4008
}
SectionHeader {
Index: 13
Expand Down
14 changes: 14 additions & 0 deletions src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,8 @@ pub const SHT_PREINIT_ARRAY: u32 = 16;
pub const SHT_GROUP: u32 = 17;
/// Extended section indices for a symbol table.
pub const SHT_SYMTAB_SHNDX: u32 = 18;
/// Relocation entries; only offsets.
pub const SHT_RELR: u32 = 19;
/// Start of OS-specific section types.
pub const SHT_LOOS: u32 = 0x6000_0000;
/// LLVM-style dependent libraries.
Expand Down Expand Up @@ -1217,6 +1219,16 @@ impl<E: Endian> Rela64<E> {
}
}

/// 32-bit relative relocation table entry.
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Relr32<E: Endian>(pub U32<E>);

/// 64-bit relative relocation table entry.
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Relr64<E: Endian>(pub U64<E>);

/// Program segment header.
#[derive(Debug, Clone, Copy)]
#[repr(C)]
Expand Down Expand Up @@ -6460,6 +6472,8 @@ unsafe_impl_endian_pod!(
Rel64,
Rela32,
Rela64,
Relr32,
Relr64,
ProgramHeader32,
ProgramHeader64,
Dyn32,
Expand Down
7 changes: 5 additions & 2 deletions src/read/elf/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::read::{
use super::{
CompressionHeader, Dyn, ElfComdat, ElfComdatIterator, ElfDynamicRelocationIterator, ElfSection,
ElfSectionIterator, ElfSegment, ElfSegmentIterator, ElfSymbol, ElfSymbolIterator,
ElfSymbolTable, NoteHeader, ProgramHeader, Rel, Rela, RelocationSections, SectionHeader,
ElfSymbolTable, NoteHeader, ProgramHeader, Rel, Rela, RelocationSections, Relr, SectionHeader,
SectionTable, Sym, SymbolTable,
};

Expand Down Expand Up @@ -485,7 +485,7 @@ where
#[allow(missing_docs)]
pub trait FileHeader: Debug + Pod {
// Ideally this would be a `u64: From<Word>`, but can't express that.
type Word: Into<u64>;
type Word: Into<u64> + Default + Copy;
type Sword: Into<i64>;
type Endian: endian::Endian;
type ProgramHeader: ProgramHeader<Elf = Self, Endian = Self::Endian, Word = Self::Word>;
Expand All @@ -496,6 +496,7 @@ pub trait FileHeader: Debug + Pod {
type Sym: Sym<Endian = Self::Endian, Word = Self::Word>;
type Rel: Rel<Endian = Self::Endian, Word = Self::Word>;
type Rela: Rela<Endian = Self::Endian, Word = Self::Word> + From<Self::Rel>;
type Relr: Relr<Endian = Self::Endian, Word = Self::Word>;

/// Return true if this type is a 64-bit header.
///
Expand Down Expand Up @@ -785,6 +786,7 @@ impl<Endian: endian::Endian> FileHeader for elf::FileHeader32<Endian> {
type Sym = elf::Sym32<Endian>;
type Rel = elf::Rel32<Endian>;
type Rela = elf::Rela32<Endian>;
type Relr = elf::Relr32<Endian>;

#[inline]
fn is_type_64(&self) -> bool {
Expand Down Expand Up @@ -882,6 +884,7 @@ impl<Endian: endian::Endian> FileHeader for elf::FileHeader64<Endian> {
type Sym = elf::Sym64<Endian>;
type Rel = elf::Rel64<Endian>;
type Rela = elf::Rela64<Endian>;
type Relr = elf::Relr64<Endian>;

#[inline]
fn is_type_64(&self) -> bool {
Expand Down
111 changes: 111 additions & 0 deletions src/read/elf/relocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -617,3 +617,114 @@ impl<Endian: endian::Endian> Rela for elf::Rela64<Endian> {
self.r_type(endian, is_mips64el)
}
}

/// An iterator over the relative relocations in an ELF `SHT_RELR` section.
///
/// Returned by [`SectionHeader::relr`](super::SectionHeader::relr).
#[derive(Debug)]
pub struct RelrIterator<'data, Elf: FileHeader> {
offset: Elf::Word,
bits: Elf::Word,
count: u8,
iter: slice::Iter<'data, Elf::Relr>,
endian: Elf::Endian,
}

impl<'data, Elf: FileHeader> RelrIterator<'data, Elf> {
/// Create a new iterator given the `SHT_RELR` section data.
pub fn new(endian: Elf::Endian, data: &'data [Elf::Relr]) -> Self {
RelrIterator {
offset: Elf::Word::default(),
bits: Elf::Word::default(),
count: 0,
iter: data.iter(),
endian,
}
}
}

impl<'data, Elf: FileHeader> Iterator for RelrIterator<'data, Elf> {
type Item = Elf::Word;

fn next(&mut self) -> Option<Self::Item> {
loop {
while self.count > 0 {
self.count -= 1;
let offset = Elf::Relr::next(&mut self.offset, &mut self.bits);
if offset.is_some() {
return offset;
}
}
let next = self.iter.next()?.get(self.endian);
if next.into() & 1 == 0 {
self.offset = next;
return Some(next);
}
self.bits = next;
self.count = Elf::Relr::COUNT;
}
}
}

/// A trait for generic access to [`elf::Relr32`] and [`elf::Relr64`].
#[allow(missing_docs)]
pub trait Relr: Debug + Pod + Clone {
type Word: Into<u64>;
type Endian: endian::Endian;

/// The number of bits in the bit mask, excluding the lowest bit.
const COUNT: u8;

/// Get the relocation entry.
///
/// This value is an offset if the lowest bit is clear, or a bit mask if the lowest bit is set.
fn get(&self, endian: Self::Endian) -> Self::Word;

/// Return the offset corresponding to the next bit in the bit mask.
///
/// Updates the offset and bit mask. This method should be called 31 times
/// for Relr32 and 63 times for Relr64 to iterate over all the bits.
///
/// Returns `None` if the bit is not set.
fn next(offset: &mut Self::Word, bits: &mut Self::Word) -> Option<Self::Word>;
}

impl<Endian: endian::Endian> Relr for elf::Relr32<Endian> {
type Word = u32;
type Endian = Endian;
const COUNT: u8 = 31;

fn get(&self, endian: Self::Endian) -> Self::Word {
self.0.get(endian)
}

fn next(offset: &mut Self::Word, bits: &mut Self::Word) -> Option<Self::Word> {
*offset += 4;
*bits >>= 1;
if *bits & 1 != 0 {
Some(*offset)
} else {
None
}
}
}

impl<Endian: endian::Endian> Relr for elf::Relr64<Endian> {
type Word = u64;
type Endian = Endian;
const COUNT: u8 = 63;

fn get(&self, endian: Self::Endian) -> Self::Word {
self.0.get(endian)
}

fn next(offset: &mut Self::Word, bits: &mut Self::Word) -> Option<Self::Word> {
*offset += 8;
*bits >>= 1;
if *bits & 1 != 0 {
Some(*offset)
} else {
None
}
}
}
27 changes: 24 additions & 3 deletions src/read/elf/section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use crate::read::{

use super::{
AttributesSection, CompressionHeader, ElfFile, ElfSectionRelocationIterator, FileHeader,
GnuHashTable, HashTable, NoteIterator, RelocationSections, SymbolTable, VerdefIterator,
VerneedIterator, VersionTable,
GnuHashTable, HashTable, NoteIterator, RelocationSections, RelrIterator, SymbolTable,
VerdefIterator, VerneedIterator, VersionTable,
};

/// The table of section headers in an ELF file.
Expand Down Expand Up @@ -654,7 +654,9 @@ where
| elf::SHT_DYNAMIC
| elf::SHT_REL
| elf::SHT_DYNSYM
| elf::SHT_GROUP => SectionKind::Metadata,
| elf::SHT_GROUP
| elf::SHT_SYMTAB_SHNDX
| elf::SHT_RELR => SectionKind::Metadata,
_ => SectionKind::Elf(sh_type),
}
}
Expand Down Expand Up @@ -852,6 +854,25 @@ pub trait SectionHeader: Debug + Pod {
Ok(Some((rela, self.link(endian))))
}

/// Return the `Elf::Relr` entries in the section.
///
/// Returns `Ok(None)` if the section does not contain relative relocations.
/// Returns `Err` for invalid values.
fn relr<'data, R: ReadRef<'data>>(
&self,
endian: Self::Endian,
data: R,
) -> read::Result<Option<RelrIterator<'data, Self::Elf>>> {
if self.sh_type(endian) != elf::SHT_RELR {
return Ok(None);
}
let data = self
.data_as_array(endian, data)
.read_error("Invalid ELF relocation section offset or size")?;
let relrs = RelrIterator::new(endian, data);
Ok(Some(relrs))
}

/// Return entries in a dynamic section.
///
/// Also returns the linked string table index.
Expand Down

0 comments on commit ab8f993

Please sign in to comment.