object/read/pe/
relocation.rs

1use core::slice;
2
3use crate::endian::{LittleEndian as LE, U16};
4use crate::pe;
5use crate::read::{Bytes, Error, ReadError, Result};
6
7/// An iterator over the relocation blocks in the `.reloc` section of a PE file.
8///
9/// Returned by [`DataDirectories::relocation_blocks`](super::DataDirectories::relocation_blocks).
10#[derive(Debug, Default, Clone, Copy)]
11pub struct RelocationBlockIterator<'data> {
12    data: Bytes<'data>,
13}
14
15impl<'data> RelocationBlockIterator<'data> {
16    /// Construct a new iterator from the data of the `.reloc` section.
17    pub fn new(data: &'data [u8]) -> Self {
18        RelocationBlockIterator { data: Bytes(data) }
19    }
20
21    /// Read the next relocation page.
22    pub fn next(&mut self) -> Result<Option<RelocationIterator<'data>>> {
23        if self.data.is_empty() {
24            return Ok(None);
25        }
26
27        let result = self.parse().map(Some);
28        if result.is_err() {
29            self.data = Bytes(&[]);
30        }
31        result
32    }
33
34    fn parse(&mut self) -> Result<RelocationIterator<'data>> {
35        let header = self
36            .data
37            .read::<pe::ImageBaseRelocation>()
38            .read_error("Invalid PE reloc section size")?;
39        let virtual_address = header.virtual_address.get(LE);
40        let size = header.size_of_block.get(LE);
41        if size <= 8 || size & 3 != 0 {
42            return Err(Error("Invalid PE reloc block size"));
43        }
44        let count = (size - 8) / 2;
45        let relocs = self
46            .data
47            .read_slice::<U16<LE>>(count as usize)
48            .read_error("Invalid PE reloc block size")?
49            .iter();
50        Ok(RelocationIterator {
51            virtual_address,
52            size,
53            relocs,
54        })
55    }
56}
57
58impl<'data> Iterator for RelocationBlockIterator<'data> {
59    type Item = Result<RelocationIterator<'data>>;
60
61    fn next(&mut self) -> Option<Self::Item> {
62        self.next().transpose()
63    }
64}
65
66/// An iterator of the relocations in a block in the `.reloc` section of a PE file.
67#[derive(Debug, Clone)]
68pub struct RelocationIterator<'data> {
69    virtual_address: u32,
70    size: u32,
71    relocs: slice::Iter<'data, U16<LE>>,
72}
73
74impl<'data> RelocationIterator<'data> {
75    /// Return the virtual address of the page that this block of relocations applies to.
76    pub fn virtual_address(&self) -> u32 {
77        self.virtual_address
78    }
79
80    /// Return the size in bytes of this block of relocations.
81    pub fn size(&self) -> u32 {
82        self.size
83    }
84}
85
86impl<'data> Iterator for RelocationIterator<'data> {
87    type Item = Relocation;
88
89    fn next(&mut self) -> Option<Relocation> {
90        loop {
91            let reloc = self.relocs.next()?.get(LE);
92            if reloc != 0 {
93                return Some(Relocation {
94                    virtual_address: self.virtual_address.wrapping_add((reloc & 0xfff) as u32),
95                    typ: reloc >> 12,
96                });
97            }
98        }
99    }
100}
101
102/// A relocation in the `.reloc` section of a PE file.
103#[derive(Debug, Default, Clone, Copy)]
104pub struct Relocation {
105    /// The virtual address of the relocation.
106    pub virtual_address: u32,
107    /// One of the `pe::IMAGE_REL_BASED_*` constants.
108    pub typ: u16,
109}