Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented a solution for #67 #102

Merged
merged 3 commits into from
Sep 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
124 changes: 111 additions & 13 deletions src/elf/reloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,10 @@ pub mod reloc64 {
// Generic Reloc
/////////////////////////////
if_alloc! {
use scroll::{ctx, Pread};
use scroll::ctx::SizeWith;
use core::fmt;
use core::result;
use scroll::ctx;
use container::{Ctx, Container};
#[cfg(feature = "endian_fd")]
use alloc::vec::Vec;
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 @@ -391,4 +380,113 @@ if_alloc! {
}
}
}

#[derive(Default)]
/// An ELF section containing relocations, allowing lazy iteration over symbols.
pub struct RelocSection<'a> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doc comments please :)

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")]
/// Parse a REL or RELA section of size `filesz` from `offset`.
pub fn parse(bytes: &'a [u8], offset: usize, filesz: usize, is_rela: bool, ctx: Ctx) -> ::error::Result<RelocSection<'a>> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doc comment

// 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())
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because constructor checks the size, we're safe to unwrap here and in the iterator, correct?

Copy link
Contributor Author

@ibabushkin ibabushkin Sep 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, pretty much. The Symtab iterator is constructed in the same way.

}
}

/// 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,
index: usize,
count: usize,
ctx: RelocCtx,
}

impl<'a> Iterator for RelocIterator<'a> {
type Item = Reloc;

#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.count {
None
} else {
self.index += 1;
Some(self.bytes.gread_with(&mut self.offset, self.ctx).unwrap())
}
}
}

impl<'a> ExactSizeIterator for RelocIterator<'a> {
#[inline]
fn len(&self) -> usize {
self.count - self.index
}
}
} // end if_alloc