use crate::{
containers::Table,
error::{PewterError, Result},
io::{ReadData, WriteData},
};
use super::ParseSectionData;
#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct BaseRelocationDataDitectory {
pub relocations: Table<BaseRelocationBlockHeader>,
}
impl ParseSectionData for BaseRelocationDataDitectory {
fn parse(
section_data: &[u8],
_: &super::Sections,
_: &crate::pe::optional_header::OptionalHeader,
_: &crate::pe::coff::CoffFileHeader,
) -> Result<Self> {
let mut data_ptr = section_data;
let mut relocations = Table::new();
while !data_ptr.is_empty() {
relocations.push(BaseRelocationBlockHeader::read(&mut data_ptr)?);
}
Ok(Self { relocations })
}
}
#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct BaseRelocationBlockHeader {
pub base_rva: u32,
pub block_size: u32,
pub table: Table<BaseRelocationBlockOffsets>,
}
impl ReadData for BaseRelocationBlockHeader {
fn read(reader: &mut impl crate::io::Reader) -> crate::error::Result<Self> {
let base_rva = reader.read()?;
let block_size = reader.read()?;
let relocation_block_size = block_size as usize
- (core::mem::size_of_val(&base_rva) + core::mem::size_of_val(&block_size));
let mut relocation_data = reader.read_slice(relocation_block_size)?;
let mut table = Table::new();
while !relocation_data.is_empty() {
table.push(BaseRelocationBlockOffsets::read(&mut relocation_data)?);
}
Ok(Self {
base_rva,
block_size,
table,
})
}
}
impl WriteData for BaseRelocationBlockHeader {
fn write_to(self, writer: &mut impl crate::io::Writer) -> crate::error::Result<()> {
writer.write(self.base_rva)?;
writer.write(self.block_size)?;
Ok(())
}
}
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum BaseRelocationType {
#[default]
Absolute = 0,
High = 1,
Low = 2,
HighLow = 3,
HighAdj = 4,
MipsJmpAddrOrArmMove32OrRscvHigh20 = 5,
Reserved = 6,
ThumbMov32OrRiscVLow121 = 7,
RiscVLow125OtLoongArch32or64MarkLa = 8,
MipsJmpAddr16 = 9,
Dir64 = 10,
}
impl BaseRelocationType {
pub fn from_u8(value: u8) -> Result<Self> {
let reloc_type = match value {
0 => Self::Absolute,
1 => Self::High,
2 => Self::Low,
3 => Self::HighLow,
4 => Self::HighAdj,
5 => Self::MipsJmpAddrOrArmMove32OrRscvHigh20,
6 => Self::Reserved,
7 => Self::ThumbMov32OrRiscVLow121,
8 => Self::RiscVLow125OtLoongArch32or64MarkLa,
9 => Self::MipsJmpAddr16,
10 => Self::Dir64,
_ => {
return Err(PewterError::invalid_image_format(
"Invalid base relcation type..",
))
}
};
Ok(reloc_type)
}
pub fn to_u8(&self) -> u8 {
*self as u8
}
}
#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct BaseRelocationBlockOffsets {
pub relocation_type: BaseRelocationType,
pub offset: u16,
}
impl ReadData for BaseRelocationBlockOffsets {
fn read(reader: &mut impl crate::io::Reader) -> Result<Self> {
const OFFSET_MASK: u16 = 0xFFFF >> 4;
let value = u16::read(reader)?;
let reloc_type = value >> 12;
let offset = value & OFFSET_MASK;
Ok(Self {
relocation_type: BaseRelocationType::from_u8(reloc_type as u8)?,
offset,
})
}
}