diff options
Diffstat (limited to 'vendor/object/src/read/pe/relocation.rs')
-rw-r--r-- | vendor/object/src/read/pe/relocation.rs | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/vendor/object/src/read/pe/relocation.rs b/vendor/object/src/read/pe/relocation.rs new file mode 100644 index 0000000..77421b7 --- /dev/null +++ b/vendor/object/src/read/pe/relocation.rs @@ -0,0 +1,92 @@ +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. +/// +/// Returned by [`DataDirectories::relocation_blocks`](super::DataDirectories::relocation_blocks). +#[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<Option<RelocationIterator<'data>>> { + if self.data.is_empty() { + return Ok(None); + } + let header = self + .data + .read::<pe::ImageBaseRelocation>() + .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::<U16<LE>>(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<LE>>, +} + +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<Relocation> { + 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, +} |