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 let header = self
27 .data
28 .read::<pe::ImageBaseRelocation>()
29 .read_error("Invalid PE reloc section size")?;
30 let virtual_address = header.virtual_address.get(LE);
31 let size = header.size_of_block.get(LE);
32 if size <= 8 || size & 3 != 0 {
33 return Err(Error("Invalid PE reloc block size"));
34 }
35 let count = (size - 8) / 2;
36 let relocs = self
37 .data
38 .read_slice::<U16<LE>>(count as usize)
39 .read_error("Invalid PE reloc block size")?
40 .iter();
41 Ok(Some(RelocationIterator {
42 virtual_address,
43 size,
44 relocs,
45 }))
46 }
47}
48
49/// An iterator of the relocations in a block in the `.reloc` section of a PE file.
50#[derive(Debug, Clone)]
51pub struct RelocationIterator<'data> {
52 virtual_address: u32,
53 size: u32,
54 relocs: slice::Iter<'data, U16<LE>>,
55}
56
57impl<'data> RelocationIterator<'data> {
58 /// Return the virtual address of the page that this block of relocations applies to.
59 pub fn virtual_address(&self) -> u32 {
60 self.virtual_address
61 }
62
63 /// Return the size in bytes of this block of relocations.
64 pub fn size(&self) -> u32 {
65 self.size
66 }
67}
68
69impl<'data> Iterator for RelocationIterator<'data> {
70 type Item = Relocation;
71
72 fn next(&mut self) -> Option<Relocation> {
73 loop {
74 let reloc: u16 = self.relocs.next()?.get(LE);
75 if reloc != 0 {
76 return Some(Relocation {
77 virtual_address: self.virtual_address.wrapping_add((reloc & 0xfff) as u32),
78 typ: reloc >> 12,
79 });
80 }
81 }
82 }
83}
84
85/// A relocation in the `.reloc` section of a PE file.
86#[derive(Debug, Default, Clone, Copy)]
87pub struct Relocation {
88 /// The virtual address of the relocation.
89 pub virtual_address: u32,
90 /// One of the `pe::IMAGE_REL_BASED_*` constants.
91 pub typ: u16,
92}
93