include!("constants_relocation.rs");
macro_rules! elf_reloc {
($size:ident, $isize:ty) => {
use core::fmt;
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Default)]
#[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))]
pub struct Rela {
pub r_offset: $size,
pub r_info: $size,
pub r_addend: $isize,
}
#[repr(C)]
#[derive(Clone, PartialEq, Default)]
#[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))]
pub struct Rel {
pub r_offset: $size,
pub r_info: $size,
}
use plain;
unsafe impl plain::Plain for Rela {}
unsafe impl plain::Plain for Rel {}
impl fmt::Debug for Rela {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let sym = r_sym(self.r_info);
let typ = r_type(self.r_info);
write!(f,
"r_offset: {:x} r_typ: {} r_sym: {} r_addend: {:x}",
self.r_offset,
typ,
sym,
self.r_addend)
}
}
impl fmt::Debug for Rel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let sym = r_sym(self.r_info);
let typ = r_type(self.r_info);
write!(f,
"r_offset: {:x} r_typ: {} r_sym: {}",
self.r_offset,
typ,
sym
)
}
}
};
}
macro_rules! elf_rela_std_impl { ($size:ident, $isize:ty) => {
if_alloc! {
use elf::reloc::Reloc;
use core::slice;
if_std! {
use error::Result;
use std::fs::File;
use std::io::{Read, Seek};
use std::io::SeekFrom::Start;
}
impl From<Rela> for Reloc {
fn from(rela: Rela) -> Self {
Reloc {
r_offset: rela.r_offset as u64,
r_addend: Some(rela.r_addend as i64),
r_sym: r_sym(rela.r_info) as usize,
r_type: r_type(rela.r_info),
}
}
}
impl From<Rel> for Reloc {
fn from(rel: Rel) -> Self {
Reloc {
r_offset: rel.r_offset as u64,
r_addend: None,
r_sym: r_sym(rel.r_info) as usize,
r_type: r_type(rel.r_info),
}
}
}
impl From<Reloc> for Rela {
fn from(rela: Reloc) -> Self {
let r_info = r_info(rela.r_sym as $size, rela.r_type as $size);
Rela {
r_offset: rela.r_offset as $size,
r_info: r_info,
r_addend: rela.r_addend.unwrap_or(0) as $isize,
}
}
}
impl From<Reloc> for Rel {
fn from(rel: Reloc) -> Self {
let r_info = r_info(rel.r_sym as $size, rel.r_type as $size);
Rel {
r_offset: rel.r_offset as $size,
r_info: r_info,
}
}
}
pub unsafe fn from_raw_rela<'a>(ptr: *const Rela, size: usize) -> &'a [Rela] {
slice::from_raw_parts(ptr, size / SIZEOF_RELA)
}
pub unsafe fn from_raw_rel<'a>(ptr: *const Rel, size: usize) -> &'a [Rel] {
slice::from_raw_parts(ptr, size / SIZEOF_REL)
}
#[cfg(feature = "std")]
pub fn from_fd(fd: &mut File, offset: usize, size: usize) -> Result<Vec<Rela>> {
let count = size / SIZEOF_RELA;
let mut relocs = vec![Rela::default(); count];
fd.seek(Start(offset as u64))?;
unsafe {
fd.read(plain::as_mut_bytes(&mut *relocs))?;
}
Ok(relocs)
}
} };
}
pub mod reloc32 {
pub use elf::reloc::*;
elf_reloc!(u32, i32);
pub const SIZEOF_RELA: usize = 4 + 4 + 4;
pub const SIZEOF_REL: usize = 4 + 4;
#[inline(always)]
pub fn r_sym(info: u32) -> u32 {
info >> 8
}
#[inline(always)]
pub fn r_type(info: u32) -> u32 {
info & 0xff
}
#[inline(always)]
pub fn r_info(sym: u32, typ: u32) -> u32 {
(sym << 8) + (typ & 0xff)
}
elf_rela_std_impl!(u32, i32);
}
pub mod reloc64 {
pub use elf::reloc::*;
elf_reloc!(u64, i64);
pub const SIZEOF_RELA: usize = 8 + 8 + 8;
pub const SIZEOF_REL: usize = 8 + 8;
#[inline(always)]
pub fn r_sym(info: u64) -> u32 {
(info >> 32) as u32
}
#[inline(always)]
pub fn r_type(info: u64) -> u32 {
(info & 0xffffffff) as u32
}
#[inline(always)]
pub fn r_info(sym: u64, typ: u64) -> u64 {
(sym << 32) + typ
}
elf_rela_std_impl!(u64, i64);
}
if_alloc! {
use core::fmt;
use core::result;
use scroll::ctx;
use container::{Ctx, Container};
#[cfg(feature = "endian_fd")]
use alloc::vec::Vec;
#[derive(Clone, Copy, PartialEq, Default)]
pub struct Reloc {
pub r_offset: u64,
pub r_addend: Option<i64>,
pub r_sym: usize,
pub r_type: u32,
}
impl Reloc {
pub fn size(is_rela: bool, ctx: Ctx) -> usize {
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);
impl ctx::SizeWith<RelocCtx> for Reloc {
type Units = usize;
fn size_with( &(is_rela, Ctx { container, .. }): &RelocCtx) -> Self::Units {
match container {
Container::Little => {
if is_rela { reloc32::SIZEOF_RELA } else { reloc32::SIZEOF_REL }
},
Container::Big => {
if is_rela { reloc64::SIZEOF_RELA } else { reloc64::SIZEOF_REL }
}
}
}
}
impl<'a> ctx::TryFromCtx<'a, RelocCtx> for Reloc {
type Error = ::error::Error;
type Size = usize;
fn try_from_ctx(bytes: &'a [u8], (is_rela, Ctx { container, le }): RelocCtx) -> result::Result<(Self, Self::Size), Self::Error> {
use scroll::Pread;
let reloc = match container {
Container::Little => {
if is_rela {
(bytes.pread_with::<reloc32::Rela>(0, le)?.into(), reloc32::SIZEOF_RELA)
} else {
(bytes.pread_with::<reloc32::Rel>(0, le)?.into(), reloc32::SIZEOF_REL)
}
},
Container::Big => {
if is_rela {
(bytes.pread_with::<reloc64::Rela>(0, le)?.into(), reloc64::SIZEOF_RELA)
} else {
(bytes.pread_with::<reloc64::Rel>(0, le)?.into(), reloc64::SIZEOF_REL)
}
}
};
Ok(reloc)
}
}
impl ctx::TryIntoCtx<RelocCtx> for Reloc {
type Error = ::error::Error;
type Size = usize;
fn try_into_ctx(self, bytes: &mut [u8], (is_rela, Ctx {container, le}): RelocCtx) -> result::Result<Self::Size, Self::Error> {
use scroll::Pwrite;
match container {
Container::Little => {
if is_rela {
let rela: reloc32::Rela = self.into();
Ok(bytes.pwrite_with(rela, 0, le)?)
} else {
let rel: reloc32::Rel = self.into();
Ok(bytes.pwrite_with(rel, 0, le)?)
}
},
Container::Big => {
if is_rela {
let rela: reloc64::Rela = self.into();
Ok(bytes.pwrite_with(rela, 0, le)?)
} else {
let rel: reloc64::Rel = self.into();
Ok(bytes.pwrite_with(rel, 0, le)?)
}
},
}
}
}
impl ctx::IntoCtx<(bool, Ctx)> for Reloc {
fn into_ctx(self, bytes: &mut [u8], ctx: RelocCtx) {
use scroll::Pwrite;
bytes.pwrite_with(self, 0, ctx).unwrap();
}
}
impl fmt::Debug for Reloc {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(addend) = self.r_addend {
write!(f,
"r_offset: {:x} r_typ: {} r_sym: {} r_addend: {:x}",
self.r_offset,
self.r_type,
self.r_sym,
addend,
)
} else {
write!(f,
"r_offset: {:x} r_typ: {} r_sym: {}",
self.r_offset,
self.r_type,
self.r_sym,
)
}
}
}
}