use super::utils::Convert;
use super::*;
use std::convert::TryFrom;
#[derive(Debug, Default)]
pub struct Relocation {
pub offset: Elf64Addr,
pub symbol: ElfWord,
pub rtype: ElfWord,
pub addend: Option<ElfSxword>,
}
#[repr(C)]
#[derive(Default)]
struct Elf32Rel {
r_offset: Elf32Addr,
r_info: ElfWord,
}
#[repr(C)]
#[derive(Default)]
struct Elf32Rela {
r_offset: Elf32Addr,
r_info: ElfWord,
r_addend: ElfSword,
}
#[repr(C)]
#[derive(Default)]
struct Elf64Rel {
r_offset: Elf64Addr,
r_info: ElfXword,
}
#[repr(C)]
#[derive(Default)]
struct Elf64Rela {
r_offset: Elf64Addr,
r_info: ElfXword,
r_addend: ElfSxword,
}
pub struct RelocationSectionAccessor<'a> {
elfio: &'a Elfio,
section: &'a dyn ElfSectionTrait,
}
impl<'a> RelocationSectionAccessor<'a> {
pub fn new(
elfio: &'a Elfio,
section: &'a dyn ElfSectionTrait,
) -> RelocationSectionAccessor<'a> {
RelocationSectionAccessor { elfio, section }
}
pub fn get_entries_num(&self) -> ElfXword {
if self.section.get_entry_size() != 0 {
return self.section.get_size() / self.section.get_entry_size();
}
0
}
pub fn get_entry(&self, index: ElfXword) -> Option<Relocation> {
let entries_num = self.get_entries_num();
if entries_num == 0 || index > entries_num - 1 {
return None;
}
let offset: usize = (index * self.section.get_entry_size()) as usize;
let end: usize = offset + self.section.get_entry_size() as usize;
let entry_area = &self.section.get_data()[offset..end];
let converter = self.elfio.get_converter();
if self.elfio.get_class() == constant::ELFCLASS64 {
let mut entry = Elf64Rela {
r_offset: converter.convert(u64::from_ne_bytes(
<[u8; 8]>::try_from(&entry_area[0..8])
.unwrap_or([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]),
)),
r_info: converter.convert(u64::from_ne_bytes(
<[u8; 8]>::try_from(&entry_area[8..16])
.unwrap_or([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]),
)),
..Default::default()
};
if self.section.get_type() == constant::SHT_RELA {
entry.r_addend = converter.convert(i64::from_ne_bytes(
<[u8; 8]>::try_from(&entry_area[16..24])
.unwrap_or([0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8]),
));
}
Some(Relocation {
offset: entry.r_offset as Elf64Addr,
symbol: (entry.r_info >> 32) as ElfWord,
rtype: (entry.r_info & 0xFFFFFFFFu64) as ElfWord,
addend: if self.section.get_type() == constant::SHT_RELA {
Some(entry.r_addend as ElfSxword)
} else {
None
},
})
} else {
let mut entry = Elf32Rela {
r_offset: converter.convert(u32::from_ne_bytes(
<[u8; 4]>::try_from(&entry_area[0..4]).unwrap_or([0u8, 0u8, 0u8, 0u8]),
)),
r_info: converter.convert(u32::from_ne_bytes(
<[u8; 4]>::try_from(&entry_area[4..8]).unwrap_or([0u8, 0u8, 0u8, 0u8]),
)),
..Default::default()
};
if self.section.get_type() == constant::SHT_RELA {
entry.r_addend = converter.convert(i32::from_ne_bytes(
<[u8; 4]>::try_from(&entry_area[8..12]).unwrap_or([0u8, 0u8, 0u8, 0u8]),
));
}
Some(Relocation {
offset: entry.r_offset as Elf64Addr,
symbol: (entry.r_info >> 8) as ElfWord,
rtype: (entry.r_info & 0xFFu32) as ElfWord,
addend: if self.section.get_type() == constant::SHT_RELA {
Some(entry.r_addend as ElfSxword)
} else {
None
},
})
}
}
}