object/read/coff/
relocation.rs

1use alloc::fmt;
2use core::slice;
3
4use crate::endian::LittleEndian as LE;
5use crate::pe;
6use crate::read::{
7    ReadRef, Relocation, RelocationEncoding, RelocationFlags, RelocationKind, RelocationTarget,
8    SymbolIndex,
9};
10
11use super::{CoffFile, CoffHeader};
12
13/// An iterator for the relocations in a [`CoffBigSection`](super::CoffBigSection).
14pub type CoffBigRelocationIterator<'data, 'file, R = &'data [u8]> =
15    CoffRelocationIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>;
16
17/// An iterator for the relocations in a [`CoffSection`](super::CoffSection).
18pub struct CoffRelocationIterator<
19    'data,
20    'file,
21    R: ReadRef<'data> = &'data [u8],
22    Coff: CoffHeader = pe::ImageFileHeader,
23> {
24    pub(super) file: &'file CoffFile<'data, R, Coff>,
25    pub(super) iter: slice::Iter<'data, pe::ImageRelocation>,
26}
27
28impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator
29    for CoffRelocationIterator<'data, 'file, R, Coff>
30{
31    type Item = (u64, Relocation);
32
33    fn next(&mut self) -> Option<Self::Item> {
34        self.iter.next().map(|relocation| {
35            let typ = relocation.typ.get(LE);
36            let flags = RelocationFlags::Coff { typ };
37            let (kind, size, addend) = match self.file.header.machine() {
38                pe::IMAGE_FILE_MACHINE_ARMNT => match typ {
39                    pe::IMAGE_REL_ARM_ADDR32 => (RelocationKind::Absolute, 32, 0),
40                    pe::IMAGE_REL_ARM_ADDR32NB => (RelocationKind::ImageOffset, 32, 0),
41                    pe::IMAGE_REL_ARM_REL32 => (RelocationKind::Relative, 32, -4),
42                    pe::IMAGE_REL_ARM_SECTION => (RelocationKind::SectionIndex, 16, 0),
43                    pe::IMAGE_REL_ARM_SECREL => (RelocationKind::SectionOffset, 32, 0),
44                    _ => (RelocationKind::Unknown, 0, 0),
45                },
46                pe::IMAGE_FILE_MACHINE_ARM64 | pe::IMAGE_FILE_MACHINE_ARM64EC => match typ {
47                    pe::IMAGE_REL_ARM64_ADDR32 => (RelocationKind::Absolute, 32, 0),
48                    pe::IMAGE_REL_ARM64_ADDR32NB => (RelocationKind::ImageOffset, 32, 0),
49                    pe::IMAGE_REL_ARM64_SECREL => (RelocationKind::SectionOffset, 32, 0),
50                    pe::IMAGE_REL_ARM64_SECTION => (RelocationKind::SectionIndex, 16, 0),
51                    pe::IMAGE_REL_ARM64_ADDR64 => (RelocationKind::Absolute, 64, 0),
52                    pe::IMAGE_REL_ARM64_REL32 => (RelocationKind::Relative, 32, -4),
53                    _ => (RelocationKind::Unknown, 0, 0),
54                },
55                pe::IMAGE_FILE_MACHINE_I386 => match typ {
56                    pe::IMAGE_REL_I386_DIR16 => (RelocationKind::Absolute, 16, 0),
57                    pe::IMAGE_REL_I386_REL16 => (RelocationKind::Relative, 16, 0),
58                    pe::IMAGE_REL_I386_DIR32 => (RelocationKind::Absolute, 32, 0),
59                    pe::IMAGE_REL_I386_DIR32NB => (RelocationKind::ImageOffset, 32, 0),
60                    pe::IMAGE_REL_I386_SECTION => (RelocationKind::SectionIndex, 16, 0),
61                    pe::IMAGE_REL_I386_SECREL => (RelocationKind::SectionOffset, 32, 0),
62                    pe::IMAGE_REL_I386_SECREL7 => (RelocationKind::SectionOffset, 7, 0),
63                    pe::IMAGE_REL_I386_REL32 => (RelocationKind::Relative, 32, -4),
64                    _ => (RelocationKind::Unknown, 0, 0),
65                },
66                pe::IMAGE_FILE_MACHINE_AMD64 => match typ {
67                    pe::IMAGE_REL_AMD64_ADDR64 => (RelocationKind::Absolute, 64, 0),
68                    pe::IMAGE_REL_AMD64_ADDR32 => (RelocationKind::Absolute, 32, 0),
69                    pe::IMAGE_REL_AMD64_ADDR32NB => (RelocationKind::ImageOffset, 32, 0),
70                    pe::IMAGE_REL_AMD64_REL32 => (RelocationKind::Relative, 32, -4),
71                    pe::IMAGE_REL_AMD64_REL32_1 => (RelocationKind::Relative, 32, -5),
72                    pe::IMAGE_REL_AMD64_REL32_2 => (RelocationKind::Relative, 32, -6),
73                    pe::IMAGE_REL_AMD64_REL32_3 => (RelocationKind::Relative, 32, -7),
74                    pe::IMAGE_REL_AMD64_REL32_4 => (RelocationKind::Relative, 32, -8),
75                    pe::IMAGE_REL_AMD64_REL32_5 => (RelocationKind::Relative, 32, -9),
76                    pe::IMAGE_REL_AMD64_SECTION => (RelocationKind::SectionIndex, 16, 0),
77                    pe::IMAGE_REL_AMD64_SECREL => (RelocationKind::SectionOffset, 32, 0),
78                    pe::IMAGE_REL_AMD64_SECREL7 => (RelocationKind::SectionOffset, 7, 0),
79                    _ => (RelocationKind::Unknown, 0, 0),
80                },
81                _ => (RelocationKind::Unknown, 0, 0),
82            };
83            let target = RelocationTarget::Symbol(relocation.symbol());
84            (
85                u64::from(relocation.virtual_address.get(LE)),
86                Relocation {
87                    kind,
88                    encoding: RelocationEncoding::Generic,
89                    size,
90                    target,
91                    addend,
92                    implicit_addend: true,
93                    flags,
94                },
95            )
96        })
97    }
98}
99
100impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> fmt::Debug
101    for CoffRelocationIterator<'data, 'file, R, Coff>
102{
103    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104        f.debug_struct("CoffRelocationIterator").finish()
105    }
106}
107
108impl pe::ImageRelocation {
109    /// Get the index of the symbol referenced by this relocation.
110    pub fn symbol(&self) -> SymbolIndex {
111        SymbolIndex(self.symbol_table_index.get(LE) as usize)
112    }
113}