use crate::errors::FileParseError;
use crate::field::Field;
use crate::pe::section::PeSection;
use crate::utils::{extract_u16, extract_u32};
pub const IMAGE_REL_I386_DIR32: u16 = 0x0006;
pub const IMAGE_REL_AMD64_ADDR64: u16 = 0x0001;
#[derive(Debug, Clone)]
pub struct SectionRelocation {
pub virtual_address: Field<u32>,
pub symbol_table_index: Field<u32>,
pub reloc_type: Field<u16>,
}
pub struct SectionRelocationBlock {
pub section_index: usize,
pub offset: usize,
pub entries: Vec<SectionRelocation>,
}
impl SectionRelocation {
pub const SIZE: usize = 10;
pub fn parse(buffer: &[u8], offset: usize) -> Result<Self, FileParseError> {
if buffer.len() < offset + Self::SIZE {
return Err(FileParseError::BufferOverflow);
}
Ok(SectionRelocation {
virtual_address: Field::new(extract_u32(buffer, offset)?, offset, 4),
symbol_table_index: Field::new(extract_u32(buffer, offset + 4)?, offset + 4, 4),
reloc_type: Field::new(extract_u16(buffer, offset + 8)?, offset + 8, 2),
})
}
}
impl SectionRelocationBlock {
pub fn parse(
buffer: &[u8],
section_index: usize,
section: &PeSection,
) -> Result<Self, FileParseError> {
let count = section.number_of_relocations.value as usize;
let offset = section.pointer_to_relocations.value as usize;
if count == 0 || offset == 0 {
return Ok(SectionRelocationBlock {
section_index,
offset,
entries: Vec::new(),
});
}
let end = offset
.checked_add(count * SectionRelocation::SIZE)
.ok_or(FileParseError::BufferOverflow)?;
if buffer.len() < end {
return Err(FileParseError::BufferOverflow);
}
let mut entries = Vec::with_capacity(count);
for i in 0..count {
entries.push(SectionRelocation::parse(
buffer,
offset + i * SectionRelocation::SIZE,
)?);
}
Ok(SectionRelocationBlock {
section_index,
offset,
entries,
})
}
}