use core::slice; use crate::endian::{LittleEndian as LE, U16}; use crate::pe; use crate::read::{Bytes, Error, ReadError, Result}; /// An iterator over the relocation blocks in the `.reloc` section of a PE file. #[derive(Debug, Default, Clone, Copy)] pub struct RelocationBlockIterator<'data> { data: Bytes<'data>, } impl<'data> RelocationBlockIterator<'data> { /// Construct a new iterator from the data of the `.reloc` section. pub fn new(data: &'data [u8]) -> Self { RelocationBlockIterator { data: Bytes(data) } } /// Read the next relocation page. pub fn next(&mut self) -> Result>> { if self.data.is_empty() { return Ok(None); } let header = self .data .read::() .read_error("Invalid PE reloc section size")?; let virtual_address = header.virtual_address.get(LE); let size = header.size_of_block.get(LE); if size <= 8 || size & 3 != 0 { return Err(Error("Invalid PE reloc block size")); } let count = (size - 8) / 2; let relocs = self .data .read_slice::>(count as usize) .read_error("Invalid PE reloc block size")? .iter(); Ok(Some(RelocationIterator { virtual_address, size, relocs, })) } } /// An iterator of the relocations in a block in the `.reloc` section of a PE file. #[derive(Debug, Clone)] pub struct RelocationIterator<'data> { virtual_address: u32, size: u32, relocs: slice::Iter<'data, U16>, } impl<'data> RelocationIterator<'data> { /// Return the virtual address of the page that this block of relocations applies to. pub fn virtual_address(&self) -> u32 { self.virtual_address } /// Return the size in bytes of this block of relocations. pub fn size(&self) -> u32 { self.size } } impl<'data> Iterator for RelocationIterator<'data> { type Item = Relocation; fn next(&mut self) -> Option { loop { let reloc = self.relocs.next()?.get(LE); if reloc != 0 { return Some(Relocation { virtual_address: self.virtual_address.wrapping_add((reloc & 0xfff) as u32), typ: reloc >> 12, }); } } } } /// A relocation in the `.reloc` section of a PE file. #[derive(Debug, Default, Clone, Copy)] pub struct Relocation { /// The virtual address of the relocation. pub virtual_address: u32, /// One of the `pe::IMAGE_REL_BASED_*` constants. pub typ: u16, }