Skip to content

Commit

Permalink
Wired up the relocation iterator into the parsing.
Browse files Browse the repository at this point in the history
  • Loading branch information
ibabushkin committed Sep 28, 2018
1 parent 4f55bd7 commit d4f3818
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 24 deletions.
25 changes: 13 additions & 12 deletions src/elf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ if_sylvan! {
pub type Dyn = dyn::Dyn;
pub type Dynamic = dyn::Dynamic;
pub type Reloc = reloc::Reloc;
pub type RelocSection<'a> = reloc::RelocSection<'a>;

pub type ProgramHeaders = Vec<ProgramHeader>;
pub type SectionHeaders = Vec<SectionHeader>;
Expand Down Expand Up @@ -106,13 +107,13 @@ if_sylvan! {
/// Contains dynamic linking information, with the _DYNAMIC array + a preprocessed DynamicInfo for that array
pub dynamic: Option<Dynamic>,
/// The dynamic relocation entries (strings, copy-data, etc.) with an addend
pub dynrelas: Vec<Reloc>,
pub dynrelas: RelocSection<'a>,
/// The dynamic relocation entries without an addend
pub dynrels: Vec<Reloc>,
pub dynrels: RelocSection<'a>,
/// The plt relocation entries (procedure linkage table). For 32-bit binaries these are usually Rel (no addend)
pub pltrelocs: Vec<Reloc>,
pub pltrelocs: RelocSection<'a>,
/// Section relocations by section index (only present if this is a relocatable object file)
pub shdr_relocs: Vec<(ShdrIdx, Vec<Reloc>)>,
pub shdr_relocs: Vec<(ShdrIdx, RelocSection<'a>)>,
/// The binary's soname, if it has one
pub soname: Option<&'a str>,
/// The binary's program interpreter (e.g., dynamic linker), if it has one
Expand Down Expand Up @@ -279,9 +280,9 @@ if_sylvan! {
let mut soname = None;
let mut libraries = vec![];
let mut dynsyms = Symtab::default();
let mut dynrelas = vec![];
let mut dynrels = vec![];
let mut pltrelocs = vec![];
let mut dynrelas = RelocSection::default();
let mut dynrels = RelocSection::default();
let mut pltrelocs = RelocSection::default();
let mut dynstrtab = Strtab::default();
let dynamic = Dynamic::parse(bytes, &program_headers, bias, ctx)?;
if let Some(ref dynamic) = dynamic {
Expand All @@ -301,10 +302,10 @@ if_sylvan! {
let num_syms = if dyn_info.syment == 0 { 0 } else { if dyn_info.strtab <= dyn_info.symtab { 0 } else { (dyn_info.strtab - dyn_info.symtab) / dyn_info.syment }};
dynsyms = Symtab::parse(bytes, dyn_info.symtab, num_syms, ctx)?;
// parse the dynamic relocations
dynrelas = Reloc::parse(bytes, dyn_info.rela, dyn_info.relasz, true, ctx)?;
dynrels = Reloc::parse(bytes, dyn_info.rel, dyn_info.relsz, false, ctx)?;
dynrelas = RelocSection::parse(bytes, dyn_info.rela, dyn_info.relasz, true, ctx)?;
dynrels = RelocSection::parse(bytes, dyn_info.rel, dyn_info.relsz, false, ctx)?;
let is_rela = dyn_info.pltrel as u64 == dyn::DT_RELA;
pltrelocs = Reloc::parse(bytes, dyn_info.jmprel, dyn_info.pltrelsz, is_rela, ctx)?;
pltrelocs = RelocSection::parse(bytes, dyn_info.jmprel, dyn_info.pltrelsz, is_rela, ctx)?;
}

// iterate through shdrs again iff we're an ET_REL
Expand All @@ -314,12 +315,12 @@ if_sylvan! {
for (idx, section) in section_headers.iter().enumerate() {
if section.sh_type == section_header::SHT_REL {
section.check_size(bytes.len())?;
let sh_relocs = Reloc::parse(bytes, section.sh_offset as usize, section.sh_size as usize, false, ctx)?;
let sh_relocs = RelocSection::parse(bytes, section.sh_offset as usize, section.sh_size as usize, false, ctx)?;
relocs.push((idx, sh_relocs));
}
if section.sh_type == section_header::SHT_RELA {
section.check_size(bytes.len())?;
let sh_relocs = Reloc::parse(bytes, section.sh_offset as usize, section.sh_size as usize, true, ctx)?;
let sh_relocs = RelocSection::parse(bytes, section.sh_offset as usize, section.sh_size as usize, true, ctx)?;
relocs.push((idx, sh_relocs));
}
}
Expand Down
91 changes: 79 additions & 12 deletions src/elf/reloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ pub mod reloc64 {
/////////////////////////////
if_alloc! {
use scroll::{ctx, Pread};
use scroll::ctx::SizeWith;
use core::fmt;
use core::result;
use container::{Ctx, Container};
Expand All @@ -278,18 +279,6 @@ if_alloc! {
use scroll::ctx::SizeWith;
Reloc::size_with(&(is_rela, ctx))
}
#[cfg(feature = "endian_fd")]
pub fn parse(bytes: &[u8], mut offset: usize, filesz: usize, is_rela: bool, ctx: Ctx) -> ::error::Result<Vec<Reloc>> {
use scroll::Pread;
let count = filesz / Reloc::size(is_rela, ctx);
let mut relocs = Vec::with_capacity(count);
let offset = &mut offset;
for _ in 0..count {
let reloc = bytes.gread_with::<Reloc>(offset, (is_rela, ctx))?;
relocs.push(reloc);
}
Ok(relocs)
}
}

type RelocCtx = (bool, Ctx);
Expand Down Expand Up @@ -392,6 +381,84 @@ if_alloc! {
}
}

#[derive(Default)]
pub struct RelocSection<'a> {
bytes: &'a [u8],
count: usize,
ctx: RelocCtx,
start: usize,
end: usize,
}

impl<'a> fmt::Debug for RelocSection<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let len = self.bytes.len();
fmt.debug_struct("RelocSection")
.field("bytes", &len)
.field("range", &format!("{:#x}..{:#x}", self.start, self.end))
.field("count", &self.count)
.field("Relocations", &self.to_vec())
.finish()
}
}

impl<'a> RelocSection<'a> {
#[cfg(feature = "endian_fd")]
pub fn parse(bytes: &'a [u8], offset: usize, filesz: usize, is_rela: bool, ctx: Ctx) -> ::error::Result<RelocSection<'a>> {
// TODO: better error message when too large (see symtab implementation)
let bytes = bytes.pread_with(offset, filesz)?;

Ok(RelocSection {
bytes: bytes,
count: filesz / Reloc::size(is_rela, ctx),
ctx: (is_rela, ctx),
start: offset,
end: offset + filesz,
})
}

/// Try to parse a single relocation from the binary, at `index`.
#[inline]
pub fn get(&self, index: usize) -> Option<Reloc> {
if index >= self.count {
None
} else {
Some(self.bytes.pread_with(index * Reloc::size_with(&self.ctx), self.ctx).unwrap())
}
}

/// The number of relocations in the section.
pub fn len(&self) -> usize {
self.count
}

/// Iterate over all relocations.
pub fn iter(&self) -> RelocIterator<'a> {
self.into_iter()
}

/// Parse all relocations into a vector.
pub fn to_vec(&self) -> Vec<Reloc> {
self.iter().collect()
}
}

impl<'a, 'b> IntoIterator for &'b RelocSection<'a> {
type Item = <RelocIterator<'a> as Iterator>::Item;
type IntoIter = RelocIterator<'a>;

#[inline]
fn into_iter(self) -> Self::IntoIter {
RelocIterator {
bytes: self.bytes,
offset: 0,
index: 0,
count: self.count,
ctx: self.ctx,
}
}
}

pub struct RelocIterator<'a> {
bytes: &'a [u8],
offset: usize,
Expand Down

0 comments on commit d4f3818

Please sign in to comment.