use crate::{
ByteRepr, Result,
arch::NativeArch,
memory::{ImageMemory, ImageMemoryExt, VmAddr, VmOffset},
relocation::RelocationArch,
};
use super::{
layout::{ElfLayout, NativeElfLayout},
raw::{ElfRelRaw, ElfRelaRaw, ElfWord},
types::{ElfRelocationType, ElfSectionType},
};
#[repr(transparent)]
pub struct ElfRelr<L: ElfLayout = NativeElfLayout> {
relr: L::Relr,
}
impl<L: ElfLayout> ElfRelr<L> {
#[inline]
pub fn value(&self) -> usize {
self.relr.to_usize()
}
}
#[repr(transparent)]
pub struct ElfRela<L: ElfLayout = NativeElfLayout> {
rela: L::Rela,
}
impl<L: ElfLayout> ElfRela<L> {
#[inline]
pub fn r_type(&self) -> ElfRelocationType {
ElfRelocationType::new((self.rela.r_info() & L::REL_MASK) as u32)
}
#[inline]
pub fn r_symbol(&self) -> usize {
self.rela.r_info() >> L::REL_BIT
}
#[inline]
pub fn r_offset(&self) -> VmOffset {
VmOffset::new(self.rela.r_offset())
}
#[inline]
pub fn r_addend(&self) -> isize {
self.rela.r_addend()
}
}
#[repr(transparent)]
pub struct ElfRel<L: ElfLayout = NativeElfLayout> {
rel: L::Rel,
}
impl<L: ElfLayout> ElfRel<L> {
#[inline]
pub fn r_type(&self) -> ElfRelocationType {
ElfRelocationType::new((self.rel.r_info() & L::REL_MASK) as u32)
}
#[inline]
pub fn r_symbol(&self) -> usize {
self.rel.r_info() >> L::REL_BIT
}
#[inline]
pub fn r_offset(&self) -> VmOffset {
VmOffset::new(self.rel.r_offset())
}
}
pub trait ElfRelEntry<L: ElfLayout = NativeElfLayout> {
const SECTION_TYPE: ElfSectionType;
fn r_type(&self) -> ElfRelocationType;
fn r_symbol(&self) -> usize;
fn r_offset(&self) -> VmOffset;
fn read_addend<Memory>(&self, memory: &Memory, place: VmAddr) -> Result<isize>
where
Memory: ImageMemory,
L::Word: ByteRepr;
fn as_rela(&self) -> Option<&ElfRela<L>>;
fn as_rel(&self) -> Option<&ElfRel<L>>;
fn set_offset(&mut self, offset: VmOffset);
fn write_addend<Memory>(&mut self, memory: &Memory, place: VmAddr, addend: isize) -> Result<()>
where
Memory: ImageMemory,
L::Word: ByteRepr;
}
impl<L: ElfLayout> ElfRelEntry<L> for ElfRela<L> {
const SECTION_TYPE: ElfSectionType = ElfSectionType::RELA;
#[inline]
fn r_type(&self) -> ElfRelocationType {
self.r_type()
}
#[inline]
fn r_symbol(&self) -> usize {
self.r_symbol()
}
#[inline]
fn r_offset(&self) -> VmOffset {
self.r_offset()
}
#[inline]
fn read_addend<Memory>(&self, _memory: &Memory, _place: VmAddr) -> Result<isize>
where
Memory: ImageMemory,
L::Word: ByteRepr,
{
Ok(ElfRela::r_addend(self))
}
#[inline]
fn as_rela(&self) -> Option<&ElfRela<L>> {
Some(self)
}
#[inline]
fn as_rel(&self) -> Option<&ElfRel<L>> {
None
}
#[inline]
fn set_offset(&mut self, offset: VmOffset) {
self.rela.set_r_offset(offset.get());
}
#[inline]
fn write_addend<Memory>(
&mut self,
_memory: &Memory,
_place: VmAddr,
addend: isize,
) -> Result<()>
where
Memory: ImageMemory,
L::Word: ByteRepr,
{
self.rela.set_r_addend(addend);
Ok(())
}
}
impl<L: ElfLayout> ElfRelEntry<L> for ElfRel<L> {
const SECTION_TYPE: ElfSectionType = ElfSectionType::REL;
#[inline]
fn r_type(&self) -> ElfRelocationType {
self.r_type()
}
#[inline]
fn r_symbol(&self) -> usize {
self.r_symbol()
}
#[inline]
fn r_offset(&self) -> VmOffset {
self.r_offset()
}
#[inline]
fn read_addend<Memory>(&self, memory: &Memory, place: VmAddr) -> Result<isize>
where
Memory: ImageMemory,
L::Word: ByteRepr,
{
let word = unsafe { memory.read_value::<L::Word>(place)? };
Ok(word.to_usize() as isize)
}
#[inline]
fn as_rela(&self) -> Option<&ElfRela<L>> {
None
}
#[inline]
fn as_rel(&self) -> Option<&ElfRel<L>> {
Some(self)
}
#[inline]
fn set_offset(&mut self, offset: VmOffset) {
self.rel.set_r_offset(offset.get());
}
#[inline]
fn write_addend<Memory>(&mut self, memory: &Memory, place: VmAddr, addend: isize) -> Result<()>
where
Memory: ImageMemory,
L::Word: ByteRepr,
{
let word = L::Word::from_usize(addend as usize);
unsafe { memory.write_value(place, word) }
}
}
pub type ElfRelType<Arch = NativeArch> = <Arch as RelocationArch>::Relocation;