Skip to main content

goblin_experimental/pe/
relocation.rs

1use core::iter::FusedIterator;
2
3use scroll::{IOread, IOwrite, Pread, Pwrite, SizeWith};
4
5use crate::error;
6use crate::pe::data_directories;
7use crate::pe::options;
8use crate::pe::section_table;
9use crate::pe::utils;
10
11/// Size of a single COFF relocation.
12pub const COFF_RELOCATION_SIZE: usize = 10;
13
14// x86 relocations.
15
16/// The relocation is ignored.
17pub const IMAGE_REL_I386_ABSOLUTE: u16 = 0x0000;
18/// Not supported.
19pub const IMAGE_REL_I386_DIR16: u16 = 0x0001;
20/// Not supported.
21pub const IMAGE_REL_I386_REL16: u16 = 0x0002;
22/// The target's 32-bit VA.
23pub const IMAGE_REL_I386_DIR32: u16 = 0x0006;
24/// The target's 32-bit RVA.
25pub const IMAGE_REL_I386_DIR32NB: u16 = 0x0007;
26/// Not supported.
27pub const IMAGE_REL_I386_SEG12: u16 = 0x0009;
28/// The 16-bit section index of the section that contains the target.
29///
30/// This is used to support debugging information.
31pub const IMAGE_REL_I386_SECTION: u16 = 0x000A;
32/// The 32-bit offset of the target from the beginning of its section.
33///
34/// This is used to support debugging information and static thread local storage.
35pub const IMAGE_REL_I386_SECREL: u16 = 0x000B;
36/// The CLR token.
37pub const IMAGE_REL_I386_TOKEN: u16 = 0x000C;
38/// A 7-bit offset from the base of the section that contains the target.
39pub const IMAGE_REL_I386_SECREL7: u16 = 0x000D;
40/// The 32-bit relative displacement to the target.
41///
42/// This supports the x86 relative branch and call instructions.
43pub const IMAGE_REL_I386_REL32: u16 = 0x0014;
44
45// x86-64 relocations.
46
47/// The relocation is ignored.
48pub const IMAGE_REL_AMD64_ABSOLUTE: u16 = 0x0000;
49/// The 64-bit VA of the relocation target.
50pub const IMAGE_REL_AMD64_ADDR64: u16 = 0x0001;
51/// The 32-bit VA of the relocation target.
52pub const IMAGE_REL_AMD64_ADDR32: u16 = 0x0002;
53/// The 32-bit address without an image base (RVA).
54pub const IMAGE_REL_AMD64_ADDR32NB: u16 = 0x0003;
55/// The 32-bit relative address from the byte following the relocation.
56pub const IMAGE_REL_AMD64_REL32: u16 = 0x0004;
57/// The 32-bit address relative to byte distance 1 from the relocation.
58pub const IMAGE_REL_AMD64_REL32_1: u16 = 0x0005;
59/// The 32-bit address relative to byte distance 2 from the relocation.
60pub const IMAGE_REL_AMD64_REL32_2: u16 = 0x0006;
61/// The 32-bit address relative to byte distance 3 from the relocation.
62pub const IMAGE_REL_AMD64_REL32_3: u16 = 0x0007;
63/// The 32-bit address relative to byte distance 4 from the relocation.
64pub const IMAGE_REL_AMD64_REL32_4: u16 = 0x0008;
65/// The 32-bit address relative to byte distance 5 from the relocation.
66pub const IMAGE_REL_AMD64_REL32_5: u16 = 0x0009;
67/// The 16-bit section index of the section that contains the target.
68///
69/// This is used to support debugging information.
70pub const IMAGE_REL_AMD64_SECTION: u16 = 0x000A;
71/// The 32-bit offset of the target from the beginning of its section.
72///
73/// This is used to support debugging information and static thread local storage.
74pub const IMAGE_REL_AMD64_SECREL: u16 = 0x000B;
75/// A 7-bit unsigned offset from the base of the section that contains the target.
76pub const IMAGE_REL_AMD64_SECREL7: u16 = 0x000C;
77/// CLR tokens.
78pub const IMAGE_REL_AMD64_TOKEN: u16 = 0x000D;
79/// A 32-bit signed span-dependent value emitted into the object.
80pub const IMAGE_REL_AMD64_SREL32: u16 = 0x000E;
81/// A pair that must immediately follow every span-dependent value.
82pub const IMAGE_REL_AMD64_PAIR: u16 = 0x000F;
83/// A 32-bit signed span-dependent value that is applied at link time.
84pub const IMAGE_REL_AMD64_SSPAN32: u16 = 0x0010;
85
86// ARM relocation.
87
88/// The relocation is ignored.
89pub const IMAGE_REL_ARM_ABSOLUTE: u16 = 0x0000;
90/// 32-bit address
91pub const IMAGE_REL_ARM_ADDR: u16 = 0x0001;
92/// 32-bit address without an image base
93pub const IMAGE_REL_ARM_ADDR32NB: u16 = 0x0002;
94/// 24-bit branch
95pub const IMAGE_REL_ARM_BRANCH24: u16 = 0x0003;
96/// 11-bit branch
97pub const IMAGE_REL_ARM_BRANCH11: u16 = 0x0004;
98/// CLR token
99pub const IMAGE_REL_ARM_TOKEN: u16 = 0x0005;
100/// 12-bit GP-relative addressing
101pub const IMAGE_REL_ARM_GPREL12: u16 = 0x0006;
102/// 7-bit GP-relative addressing
103pub const IMAGE_REL_ARM_GPREL7: u16 = 0x0007;
104/// 24-bit BLX (branch with link and exchange)
105pub const IMAGE_REL_ARM_BLX24: u16 = 0x0008;
106/// 11-bit BLX
107pub const IMAGE_REL_ARM_BLX11: u16 = 0x0009;
108/// Section index
109pub const IMAGE_REL_ARM_SECTION: u16 = 0x000E;
110/// 32-bit offset from section base
111pub const IMAGE_REL_ARM_SECREL: u16 = 0x000F;
112/// MOVW/MOVT (immediate load for addresses)
113pub const IMAGE_REL_ARM_MOV32A: u16 = 0x0010;
114/// MOVW/MOVT (thumb mode immediate load)
115pub const IMAGE_REL_ARM_MOV32T: u16 = 0x0011;
116/// Thumb mode 20-bit branch
117pub const IMAGE_REL_ARM_BRANCH20T: u16 = 0x0012;
118/// Thumb mode 24-bit branch
119pub const IMAGE_REL_ARM_BRANCH24T: u16 = 0x0014;
120/// Thumb mode 23-bit BLX
121pub const IMAGE_REL_ARM_BLX23T: u16 = 0x0015;
122
123// ARM64 relocation.
124
125/// The relocation is ignored.
126pub const IMAGE_REL_ARM64_ABSOLUTE: u16 = 0x0000;
127/// 32-bit address
128pub const IMAGE_REL_ARM64_ADDR32: u16 = 0x0001;
129/// 32-bit address without an image base
130pub const IMAGE_REL_ARM64_ADDR32NB: u16 = 0x0002;
131/// 26-bit branch
132pub const IMAGE_REL_ARM64_BRANCH26: u16 = 0x0003;
133/// Page-relative 21-bit offset
134pub const IMAGE_REL_ARM64_PAGEBASE_REL21: u16 = 0x0004;
135/// 21-bit offset from page base
136pub const IMAGE_REL_ARM64_REL21: u16 = 0x0005;
137/// 12-bit absolute page offset (addend)
138pub const IMAGE_REL_ARM64_PAGEOFFSET_12A: u16 = 0x0006;
139/// 12-bit absolute page offset (logical)
140pub const IMAGE_REL_ARM64_PAGEOFFSET_12L: u16 = 0x0007;
141/// 32-bit offset from section base
142pub const IMAGE_REL_ARM64_SECREL: u16 = 0x0008;
143/// Low 12 bits of section-relative address (addend)
144pub const IMAGE_REL_ARM64_SECREL_LOW12A: u16 = 0x0009;
145/// High 12 bits of section-relative address (addend)
146pub const IMAGE_REL_ARM64_SECREL_HIGH12A: u16 = 0x000A;
147/// Low 12 bits of section-relative address (logical)
148pub const IMAGE_REL_ARM64_SECREL_LOW12L: u16 = 0x000B;
149/// CLR token
150pub const IMAGE_REL_ARM64_TOKEN: u16 = 0x000C;
151/// Section index
152pub const IMAGE_REL_ARM64_SECTION: u16 = 0x000D;
153/// 64-bit address
154pub const IMAGE_REL_ARM64_ADDR64: u16 = 0x000E;
155/// 19-bit branch
156pub const IMAGE_REL_ARM64_BRANCH19: u16 = 0x000F;
157
158// IA64 relocation.
159
160/// The relocation is ignored.
161pub const IMAGE_REL_IA64_ABSOLUTE: u16 = 0x0000;
162/// Immediate 14-bit offset
163pub const IMAGE_REL_IA64_IMM14: u16 = 0x0001;
164/// Immediate 22-bit offset
165pub const IMAGE_REL_IA64_IMM22: u16 = 0x0002;
166/// Immediate 64-bit offset
167pub const IMAGE_REL_IA64_IMM64: u16 = 0x0003;
168/// Direct 32-bit address
169pub const IMAGE_REL_IA64_DIR: u16 = 0x0004;
170/// Direct 64-bit address
171pub const IMAGE_REL_IA64_DIR64: u16 = 0x0005;
172/// PC-relative 21-bit branch (bundle format)
173pub const IMAGE_REL_IA64_PCREL21B: u16 = 0x0006;
174/// PC-relative 21-bit branch (mixed format)
175pub const IMAGE_REL_IA64_PCREL21M: u16 = 0x0007;
176/// PC-relative 21-bit branch (full format)
177pub const IMAGE_REL_IA64_PCREL21F: u16 = 0x0008;
178/// GP-relative 22-bit offset
179pub const IMAGE_REL_IA64_GPREL22: u16 = 0x0009;
180/// 22-bit offset from GP-relative label
181pub const IMAGE_REL_IA64_LTOFF22: u16 = 0x000A;
182/// Section index
183pub const IMAGE_REL_IA64_SECTION: u16 = 0x000B;
184/// Section-relative 22-bit offset
185pub const IMAGE_REL_IA64_SECREL22: u16 = 0x000C;
186/// Section-relative 64-bit offset with immediate
187pub const IMAGE_REL_IA64_SECREL64I: u16 = 0x000D;
188/// Section-relative offset
189pub const IMAGE_REL_IA64_SECREL: u16 = 0x000E;
190/// GP-relative 64-bit offset
191pub const IMAGE_REL_IA64_LTOFF64: u16 = 0x000F;
192/// 32-bit address without an image base
193pub const IMAGE_REL_IA64_DIR32NB: u16 = 0x0010;
194/// 14-bit section-relative offset
195pub const IMAGE_REL_IA64_SREL14: u16 = 0x0011;
196/// 22-bit section-relative offset
197pub const IMAGE_REL_IA64_SREL22: u16 = 0x0012;
198/// 32-bit section-relative offset
199pub const IMAGE_REL_IA64_SREL32: u16 = 0x0013;
200/// 32-bit user-defined offset
201pub const IMAGE_REL_IA64_UREL32: u16 = 0x0014;
202/// PC-relative 60-bit offset (extension format)
203pub const IMAGE_REL_IA64_PCREL60X: u16 = 0x0015;
204/// PC-relative 60-bit offset (bundle format)
205pub const IMAGE_REL_IA64_PCREL60B: u16 = 0x0016;
206/// PC-relative 60-bit offset (full format)
207pub const IMAGE_REL_IA64_PCREL60F: u16 = 0x0017;
208/// PC-relative 60-bit offset (immediate format)
209pub const IMAGE_REL_IA64_PCREL60I: u16 = 0x0018;
210/// PC-relative 60-bit offset (mixed format)
211pub const IMAGE_REL_IA64_PCREL60M: u16 = 0x0019;
212/// GP-relative 64-bit immediate offset
213pub const IMAGE_REL_IA64_IMMGPREL64: u16 = 0x001A;
214/// CLR token
215pub const IMAGE_REL_IA64_TOKEN: u16 = 0x001B;
216/// 32-bit GP-relative offset
217pub const IMAGE_REL_IA64_GPREL32: u16 = 0x001C;
218/// Offset with an addend
219pub const IMAGE_REL_IA64_ADDEND: u16 = 0x001F;
220
221// base relocation.
222
223/// Absolute relocation. No modification is necessary.
224pub const IMAGE_REL_BASED_ABSOLUTE: u16 = 0;
225/// Relocation based on the high 16 bits of the address.
226pub const IMAGE_REL_BASED_HIGH: u16 = 1;
227/// Relocation based on the low 16 bits of the address.
228pub const IMAGE_REL_BASED_LOW: u16 = 2;
229/// Relocation based on the entire 32-bit address.
230pub const IMAGE_REL_BASED_HIGHLOW: u16 = 3;
231/// Relocation based on the adjusted high 16 bits of the address.
232pub const IMAGE_REL_BASED_HIGHADJ: u16 = 4;
233/// MIPS jump address relocation.
234pub const IMAGE_REL_BASED_MIPS_JMPADDR: u16 = 5;
235/// ARM MOV32A relocation (shares the same value as MIPS_JMPADDR).
236pub const IMAGE_REL_BASED_ARM_MOV32A: u16 = 5;
237/// ARM MOV32 relocation (shares the same value as MIPS_JMPADDR).
238pub const IMAGE_REL_BASED_ARM_MOV32: u16 = 5;
239/// Relocation based on the section.
240pub const IMAGE_REL_BASED_SECTION: u16 = 6;
241/// Relocation relative to the base.
242pub const IMAGE_REL_BASED_REL: u16 = 7;
243/// ARM MOV32T relocation (shares the same value as REL).
244pub const IMAGE_REL_BASED_ARM_MOV32T: u16 = 7;
245/// Thumb MOV32 relocation (shares the same value as REL).
246pub const IMAGE_REL_BASED_THUMB_MOV32: u16 = 7;
247/// MIPS 16-bit jump address relocation.
248pub const IMAGE_REL_BASED_MIPS_JMPADDR16: u16 = 9;
249/// IA64 immediate 64-bit relocation (shares the same value as MIPS_JMPADDR16).
250pub const IMAGE_REL_BASED_IA64_IMM64: u16 = 9;
251/// Relocation based on a 64-bit address.
252pub const IMAGE_REL_BASED_DIR64: u16 = 10;
253/// Relocation based on the top 16 bits of a 48-bit address.
254pub const IMAGE_REL_BASED_HIGH3ADJ: u16 = 11;
255
256/// A COFF relocation.
257#[repr(C)]
258#[derive(Debug, Copy, Clone, PartialEq, Default, Pread, Pwrite, IOread, IOwrite, SizeWith)]
259pub struct Relocation {
260    /// The address of the item to which relocation is applied.
261    ///
262    /// This is the offset from the beginning of the section, plus the
263    /// value of the section's `virtual_address` field.
264    pub virtual_address: u32,
265    /// A zero-based index into the symbol table.
266    ///
267    /// This symbol gives the address that is to be used for the relocation. If the specified
268    /// symbol has section storage class, then the symbol's address is the address with the
269    /// first section of the same name.
270    pub symbol_table_index: u32,
271    /// A value that indicates the kind of relocation that should be performed.
272    ///
273    /// Valid relocation types depend on machine type.
274    pub typ: u16,
275}
276
277/// An iterator for COFF relocations.
278#[derive(Default)]
279pub struct Relocations<'a> {
280    offset: usize,
281    relocations: &'a [u8],
282}
283
284impl<'a> Relocations<'a> {
285    /// Parse a COFF relocation table at the given offset.
286    ///
287    /// The offset and number of relocations should be from the COFF section header.
288    pub fn parse(bytes: &'a [u8], offset: usize, number: usize) -> error::Result<Relocations<'a>> {
289        let relocations = bytes.pread_with(offset, number * COFF_RELOCATION_SIZE)?;
290        Ok(Relocations {
291            offset: 0,
292            relocations,
293        })
294    }
295}
296
297impl<'a> Iterator for Relocations<'a> {
298    type Item = Relocation;
299    fn next(&mut self) -> Option<Self::Item> {
300        if self.offset >= self.relocations.len() {
301            None
302        } else {
303            Some(
304                self.relocations
305                    .gread_with(&mut self.offset, scroll::LE)
306                    .unwrap(),
307            )
308        }
309    }
310}
311
312#[derive(Debug, PartialEq, Clone, Default)]
313pub struct RelocationData<'a> {
314    bytes: &'a [u8],
315}
316
317impl<'a> RelocationData<'a> {
318    pub fn parse(
319        bytes: &'a [u8],
320        dd: data_directories::DataDirectory,
321        sections: &[section_table::SectionTable],
322        file_alignment: u32,
323    ) -> error::Result<Self> {
324        Self::parse_with_opts(
325            bytes,
326            dd,
327            sections,
328            file_alignment,
329            &options::ParseOptions::default(),
330        )
331    }
332
333    pub fn parse_with_opts(
334        bytes: &'a [u8],
335        dd: data_directories::DataDirectory,
336        sections: &[section_table::SectionTable],
337        file_alignment: u32,
338        opts: &options::ParseOptions,
339    ) -> error::Result<Self> {
340        let offset =
341            utils::find_offset(dd.virtual_address as usize, sections, file_alignment, opts)
342                .ok_or_else(|| {
343                    error::Error::Malformed(format!(
344                        "Cannot map base reloc rva {:#x} into offset",
345                        dd.virtual_address
346                    ))
347                })?;
348
349        // Ensure that the offset and size do not exceed the length of the bytes slice
350        if offset + dd.size as usize > bytes.len() {
351            return Err(error::Error::Malformed(format!(
352                "base reloc offset {:#x} and size {:#x} exceeds the bounds of the bytes size {:#x}",
353                offset,
354                dd.size,
355                bytes.len()
356            )));
357        }
358
359        let bytes = &bytes[offset..offset + dd.size as usize];
360
361        Ok(Self { bytes })
362    }
363
364    /// Returns iterator for [`RelocationBlock`]
365    pub fn blocks(&self) -> RelocationBlockIterator<'a> {
366        RelocationBlockIterator {
367            bytes: &self.bytes,
368            offset: 0,
369        }
370    }
371}
372
373/// Represents a PE (Portable Executable) base relocation block.
374///
375/// In the PE format, base relocations are organized into blocks, where each block corresponds
376/// to a contiguous range of memory that needs to be relocated. The relocations within a block
377/// specify offsets relative to the block's starting address.
378///
379/// Unlike COFF (Common Object File Format), PE base relocations are separated by blocks.
380/// Each block begins with a [`RelocationBlock`] structure that provides information about the
381/// relocation block, including its starting RVA (Relative Virtual Address) and size in bytes.
382///
383/// Each block ends with an "absolute" relocation entry, which acts as a marker to indicate
384/// the end of the block. This entry has no actual relocation effect.
385#[derive(Debug, Copy, Clone, PartialEq, Default)]
386pub struct RelocationBlock<'a> {
387    /// The starting RVA for the relocation block.
388    pub rva: u32,
389    /// The total size of the relocation block, in bytes.
390    pub size: u32,
391    /// The bytes of [`RelocationWord`] data within this block.
392    pub bytes: &'a [u8],
393}
394
395impl RelocationBlock<'_> {
396    /// Returns iterator for [`RelocationWord`]
397    pub fn words(&self) -> RelocationWordIterator {
398        RelocationWordIterator {
399            bytes: &self.bytes,
400            offset: 0,
401        }
402    }
403}
404
405/// Raw size of [`RelocationBlock`]
406pub const RELOCATION_BLOCK_SIZE: usize = 8;
407
408impl<'a> scroll::ctx::TryFromCtx<'a, scroll::Endian> for RelocationBlock<'a> {
409    type Error = crate::error::Error;
410
411    fn try_from_ctx(bytes: &'a [u8], ctx: scroll::Endian) -> Result<(Self, usize), Self::Error> {
412        let mut offset = 0;
413        let rva = bytes.gread_with::<u32>(&mut offset, ctx)?;
414        let size = bytes.gread_with::<u32>(&mut offset, ctx)?;
415        let bytes = &[];
416        Ok((Self { rva, size, bytes }, offset))
417    }
418}
419
420#[derive(Clone, Copy, Debug)]
421pub struct RelocationBlockIterator<'a> {
422    bytes: &'a [u8],
423    offset: usize,
424}
425
426impl<'a> Iterator for RelocationBlockIterator<'a> {
427    type Item = error::Result<RelocationBlock<'a>>;
428
429    fn next(&mut self) -> Option<Self::Item> {
430        if self.offset >= self.bytes.len() {
431            return None;
432        }
433
434        Some(
435            match self
436                .bytes
437                .gread_with::<RelocationBlock>(&mut self.offset, scroll::LE)
438            {
439                Ok(block) => {
440                    let word_size = block.size as usize - RELOCATION_BLOCK_SIZE;
441                    let word_bytes = &self.bytes[self.offset..self.offset + word_size];
442                    // "Block"s and "Word"s are entirely contiguous
443                    self.offset += word_size;
444                    Ok(RelocationBlock {
445                        bytes: word_bytes,
446                        ..block
447                    })
448                }
449                Err(error) => {
450                    self.bytes = &[];
451                    Err(error.into())
452                }
453            },
454        )
455    }
456}
457
458impl FusedIterator for RelocationBlockIterator<'_> {}
459
460/// Represents a single relocation entry within a PE base relocation block.
461///
462/// Each relocation entry is stored as a 16-bit value ([`u16`]), referred to as a "relocation word."
463/// The value is divided into two components:
464///
465/// * The upper 4 bits specify the relocation type, which determines how the relocation
466///   should be applied.
467/// * The remaining 12 bits specify the offset from the block's starting RVA where the
468///   relocation should be applied.
469#[repr(C)]
470#[derive(Debug, Copy, Clone, PartialEq, Default, Pread, Pwrite, IOread, IOwrite, SizeWith)]
471pub struct RelocationWord {
472    /// A 16-bit value encoding the relocation type and offset.
473    ///
474    /// - Upper 4 bits: relocation type.
475    /// - Lower 12 bits: offset from the base RVA.
476    pub value: u16,
477}
478
479impl RelocationWord {
480    /// Returns the relocation type from the upper 4 bits of [Self::value].
481    pub fn reloc_type(&self) -> u8 {
482        (self.value >> 12) as u8
483    }
484
485    /// Returns the relocation offset from the lower 16 bits of [Self::value].
486    pub fn offset(&self) -> u16 {
487        (self.value & 0xFFF) as u16
488    }
489}
490
491#[derive(Clone, Copy, Debug)]
492pub struct RelocationWordIterator<'a> {
493    bytes: &'a [u8],
494    offset: usize,
495}
496
497impl Iterator for RelocationWordIterator<'_> {
498    type Item = error::Result<RelocationWord>;
499
500    fn next(&mut self) -> Option<Self::Item> {
501        if self.offset >= self.bytes.len() {
502            return None;
503        }
504
505        Some(match self.bytes.gread_with(&mut self.offset, scroll::LE) {
506            Ok(word) => Ok(word),
507            Err(error) => {
508                self.bytes = &[];
509                Err(error.into())
510            }
511        })
512    }
513
514    fn size_hint(&self) -> (usize, Option<usize>) {
515        let count = self.bytes.len() / core::mem::size_of::<RelocationWord>();
516        (count, Some(count))
517    }
518}
519
520impl FusedIterator for RelocationWordIterator<'_> {}
521
522#[cfg(test)]
523mod tests {
524    use super::*;
525
526    static BASERELOC_DATA1: &[u8; 1360] = &[
527        0x00, 0xD0, 0x11, 0x00, 0x34, 0x02, 0x00, 0x00, 0x08, 0xA0, 0x18, 0xA0, 0x28, 0xA0, 0x38,
528        0xA0, 0x48, 0xA0, 0x58, 0xA0, 0x68, 0xA0, 0x78, 0xA0, 0x88, 0xA0, 0x98, 0xA0, 0xA8, 0xA0,
529        0xB8, 0xA0, 0xC8, 0xA0, 0xD8, 0xA0, 0xE0, 0xA0, 0xE8, 0xA0, 0xF0, 0xA0, 0xF8, 0xA0, 0x00,
530        0xA1, 0x08, 0xA1, 0x10, 0xA1, 0x18, 0xA1, 0x20, 0xA1, 0x28, 0xA1, 0x30, 0xA1, 0x38, 0xA1,
531        0x48, 0xA1, 0x50, 0xA1, 0x58, 0xA1, 0x60, 0xA1, 0x68, 0xA1, 0x70, 0xA1, 0x78, 0xA1, 0x80,
532        0xA1, 0x88, 0xA1, 0x98, 0xA1, 0xA0, 0xA1, 0xA8, 0xA1, 0xB8, 0xA1, 0xC0, 0xA1, 0xC8, 0xA1,
533        0xD0, 0xA1, 0xD8, 0xA1, 0xE8, 0xA1, 0xF8, 0xA1, 0x08, 0xA2, 0x18, 0xA2, 0x28, 0xA2, 0x38,
534        0xA2, 0x48, 0xA2, 0x58, 0xA2, 0x68, 0xA2, 0x78, 0xA2, 0x88, 0xA2, 0x98, 0xA2, 0xA8, 0xA2,
535        0xB8, 0xA2, 0xC8, 0xA2, 0xD8, 0xA2, 0xE8, 0xA2, 0x08, 0xA3, 0x28, 0xA3, 0x48, 0xA3, 0x68,
536        0xA3, 0x88, 0xA3, 0x98, 0xA3, 0xA8, 0xA3, 0xB8, 0xA3, 0xC8, 0xA3, 0xD8, 0xA3, 0xE8, 0xA3,
537        0xF8, 0xA3, 0x08, 0xA4, 0x18, 0xA4, 0x28, 0xA4, 0x38, 0xA4, 0x48, 0xA4, 0x58, 0xA4, 0x70,
538        0xA4, 0xA0, 0xA4, 0xA8, 0xA6, 0xB8, 0xA6, 0xC8, 0xA6, 0xD8, 0xA6, 0xE8, 0xA6, 0xF8, 0xA6,
539        0x00, 0xA7, 0x08, 0xA7, 0x30, 0xA7, 0x60, 0xA7, 0x88, 0xA7, 0x98, 0xA7, 0xA8, 0xA7, 0xB8,
540        0xA7, 0xC8, 0xA7, 0xD0, 0xA7, 0xD8, 0xA7, 0xE0, 0xA7, 0xF8, 0xA7, 0x00, 0xA8, 0x08, 0xA8,
541        0x10, 0xA8, 0x28, 0xA8, 0x38, 0xA8, 0x50, 0xA8, 0x70, 0xA8, 0x78, 0xA8, 0x80, 0xA8, 0x88,
542        0xA8, 0x90, 0xA8, 0x98, 0xA8, 0xA0, 0xA8, 0xA8, 0xA8, 0xB0, 0xA8, 0xB8, 0xA8, 0xC0, 0xA8,
543        0xC8, 0xA8, 0xD0, 0xA8, 0xD8, 0xA8, 0xE0, 0xA8, 0xE8, 0xA8, 0xF0, 0xA8, 0xF8, 0xA8, 0x00,
544        0xA9, 0x08, 0xA9, 0x10, 0xA9, 0x18, 0xA9, 0x20, 0xA9, 0x28, 0xA9, 0x30, 0xA9, 0x38, 0xA9,
545        0x40, 0xA9, 0x48, 0xA9, 0x50, 0xA9, 0x58, 0xA9, 0x60, 0xA9, 0x68, 0xA9, 0x70, 0xA9, 0x78,
546        0xA9, 0x80, 0xA9, 0x88, 0xA9, 0x90, 0xA9, 0x98, 0xA9, 0xA0, 0xA9, 0xA8, 0xA9, 0xB0, 0xA9,
547        0xB8, 0xA9, 0xC0, 0xA9, 0xC8, 0xA9, 0xD0, 0xA9, 0xD8, 0xA9, 0xE0, 0xA9, 0xE8, 0xA9, 0xF0,
548        0xA9, 0xF8, 0xA9, 0x00, 0xAA, 0x08, 0xAA, 0x10, 0xAA, 0x18, 0xAA, 0x20, 0xAA, 0x28, 0xAA,
549        0x30, 0xAA, 0x38, 0xAA, 0x40, 0xAA, 0x48, 0xAA, 0x50, 0xAA, 0x58, 0xAA, 0x70, 0xAA, 0x80,
550        0xAA, 0x88, 0xAA, 0x98, 0xAA, 0xB0, 0xAA, 0xC8, 0xAA, 0xE0, 0xAA, 0xF8, 0xAA, 0x08, 0xAB,
551        0x18, 0xAB, 0x28, 0xAB, 0x38, 0xAB, 0x48, 0xAB, 0x58, 0xAB, 0x68, 0xAB, 0x78, 0xAB, 0xD8,
552        0xAB, 0xF0, 0xAB, 0xF8, 0xAB, 0x00, 0xAC, 0x88, 0xAC, 0xA0, 0xAC, 0xA8, 0xAC, 0xB0, 0xAC,
553        0xB8, 0xAC, 0xC0, 0xAC, 0xC8, 0xAC, 0xD0, 0xAC, 0xD8, 0xAC, 0xE0, 0xAC, 0xE8, 0xAC, 0xF8,
554        0xAC, 0x00, 0xAD, 0x08, 0xAD, 0x10, 0xAD, 0x18, 0xAD, 0x20, 0xAD, 0x28, 0xAD, 0x30, 0xAD,
555        0x38, 0xAD, 0x48, 0xAD, 0x50, 0xAD, 0x58, 0xAD, 0x60, 0xAD, 0x70, 0xAD, 0x78, 0xAD, 0x80,
556        0xAD, 0x88, 0xAD, 0x98, 0xAD, 0xA0, 0xAD, 0xA8, 0xAD, 0xB0, 0xAD, 0xC8, 0xAD, 0xD0, 0xAD,
557        0xD8, 0xAD, 0xF0, 0xAD, 0xF8, 0xAD, 0x00, 0xAE, 0x18, 0xAE, 0x20, 0xAE, 0x28, 0xAE, 0x30,
558        0xAE, 0x38, 0xAE, 0x40, 0xAE, 0x48, 0xAE, 0x50, 0xAE, 0x58, 0xAE, 0x60, 0xAE, 0x68, 0xAE,
559        0x70, 0xAE, 0x78, 0xAE, 0x80, 0xAE, 0x88, 0xAE, 0x98, 0xAE, 0xA8, 0xAE, 0xB8, 0xAE, 0xC8,
560        0xAE, 0xD8, 0xAE, 0xE8, 0xAE, 0xF8, 0xAE, 0x08, 0xAF, 0x18, 0xAF, 0x20, 0xAF, 0x28, 0xAF,
561        0x30, 0xAF, 0x38, 0xAF, 0x40, 0xAF, 0x48, 0xAF, 0x50, 0xAF, 0x58, 0xAF, 0x60, 0xAF, 0x68,
562        0xAF, 0x70, 0xAF, 0x78, 0xAF, 0x80, 0xAF, 0x88, 0xAF, 0x90, 0xAF, 0x98, 0xAF, 0xA0, 0xAF,
563        0xA8, 0xAF, 0xB0, 0xAF, 0xB8, 0xAF, 0xC0, 0xAF, 0xC8, 0xAF, 0xD0, 0xAF, 0xD8, 0xAF, 0xE0,
564        0xAF, 0xE8, 0xAF, 0xF0, 0xAF, 0xF8, 0xAF, 0x00, 0x00, 0x00, 0xE0, 0x11, 0x00, 0x58, 0x01,
565        0x00, 0x00, 0x00, 0xA0, 0x08, 0xA0, 0x10, 0xA0, 0x18, 0xA0, 0x20, 0xA0, 0x30, 0xA0, 0x40,
566        0xA0, 0x48, 0xA0, 0x50, 0xA0, 0x58, 0xA0, 0x60, 0xA0, 0x68, 0xA0, 0x70, 0xA0, 0x78, 0xA0,
567        0x80, 0xA0, 0x88, 0xA0, 0x90, 0xA0, 0x98, 0xA0, 0xA0, 0xA0, 0xA8, 0xA0, 0xB0, 0xA0, 0xB8,
568        0xA0, 0xC0, 0xA0, 0xC8, 0xA0, 0xD0, 0xA0, 0xD8, 0xA0, 0xE0, 0xA0, 0xE8, 0xA0, 0xF0, 0xA0,
569        0xF8, 0xA0, 0x00, 0xA1, 0x08, 0xA1, 0x10, 0xA1, 0x18, 0xA1, 0x20, 0xA1, 0x28, 0xA1, 0x30,
570        0xA1, 0x38, 0xA1, 0x40, 0xA1, 0x48, 0xA1, 0x50, 0xA1, 0x58, 0xA1, 0x60, 0xA1, 0x68, 0xA1,
571        0x70, 0xA1, 0x78, 0xA1, 0x80, 0xA1, 0x88, 0xA1, 0x90, 0xA1, 0x98, 0xA1, 0xA0, 0xA1, 0xA8,
572        0xA1, 0xB0, 0xA1, 0xB8, 0xA1, 0xC0, 0xA1, 0xC8, 0xA1, 0xD0, 0xA1, 0xD8, 0xA1, 0xE0, 0xA1,
573        0xF0, 0xA1, 0x08, 0xA2, 0x10, 0xA2, 0x20, 0xA2, 0x30, 0xA2, 0x48, 0xA2, 0x50, 0xA2, 0x58,
574        0xA2, 0x60, 0xA2, 0x68, 0xA2, 0x70, 0xA2, 0x78, 0xA2, 0x88, 0xA2, 0x90, 0xA2, 0xA0, 0xA2,
575        0xA8, 0xA2, 0xB8, 0xA2, 0xC0, 0xA2, 0xD0, 0xA2, 0xD8, 0xA2, 0xE8, 0xA2, 0xF0, 0xA2, 0x08,
576        0xA3, 0x18, 0xA3, 0x28, 0xA3, 0x38, 0xA3, 0x48, 0xA3, 0x58, 0xA3, 0x68, 0xA3, 0x78, 0xA3,
577        0x80, 0xA3, 0x88, 0xA3, 0x90, 0xA3, 0x98, 0xA3, 0xA0, 0xA3, 0xA8, 0xA3, 0xB8, 0xA3, 0xC8,
578        0xA3, 0xD8, 0xA3, 0xF0, 0xA3, 0x18, 0xA4, 0x20, 0xA4, 0x30, 0xA4, 0x40, 0xA4, 0x50, 0xA4,
579        0x60, 0xA4, 0x70, 0xA4, 0x80, 0xA4, 0x90, 0xA4, 0xA0, 0xA4, 0xB0, 0xA4, 0xC0, 0xA4, 0xD0,
580        0xA4, 0xE0, 0xA4, 0xF0, 0xA4, 0x00, 0xA5, 0x10, 0xA5, 0x28, 0xA5, 0x50, 0xA5, 0x60, 0xA5,
581        0x70, 0xA5, 0x80, 0xA5, 0x90, 0xA5, 0xA0, 0xA5, 0xB0, 0xA5, 0xC0, 0xA5, 0xD0, 0xA5, 0xE0,
582        0xA5, 0xF0, 0xA5, 0x00, 0xA6, 0x10, 0xA6, 0x20, 0xA6, 0x28, 0xA6, 0x30, 0xA6, 0x38, 0xA6,
583        0x50, 0xA6, 0x68, 0xA6, 0x78, 0xA6, 0x88, 0xA6, 0x98, 0xA6, 0xA8, 0xA6, 0xB8, 0xA6, 0xC8,
584        0xA6, 0xD8, 0xA6, 0xE8, 0xA6, 0xF8, 0xA6, 0x08, 0xA7, 0x18, 0xA7, 0x28, 0xA7, 0x38, 0xA7,
585        0x48, 0xA7, 0x58, 0xA7, 0x68, 0xA7, 0x78, 0xA7, 0x88, 0xA7, 0x98, 0xA7, 0xA8, 0xA7, 0xB8,
586        0xA7, 0xC8, 0xA7, 0xD8, 0xA7, 0xE8, 0xA7, 0xF8, 0xA7, 0x08, 0xA8, 0x18, 0xA8, 0x28, 0xA8,
587        0x38, 0xA8, 0x58, 0xA8, 0x68, 0xA8, 0x80, 0xA8, 0x00, 0x60, 0x12, 0x00, 0x1C, 0x00, 0x00,
588        0x00, 0xA0, 0xA9, 0xA8, 0xA9, 0xB0, 0xA9, 0xB8, 0xA9, 0xC0, 0xA9, 0xC8, 0xA9, 0xD0, 0xA9,
589        0xD8, 0xA9, 0xE0, 0xA9, 0x00, 0x00, 0x00, 0x20, 0x15, 0x00, 0x28, 0x00, 0x00, 0x00, 0xE8,
590        0xA0, 0xF0, 0xA0, 0xF8, 0xA0, 0x08, 0xA1, 0x10, 0xA1, 0x18, 0xA1, 0x20, 0xA1, 0x38, 0xA1,
591        0x40, 0xA1, 0x48, 0xA1, 0x58, 0xA1, 0x60, 0xA1, 0x68, 0xA1, 0x70, 0xA1, 0x90, 0xA1, 0x00,
592        0x00, 0x00, 0x60, 0x16, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x08, 0xA0, 0x78, 0xA0,
593        0x98, 0xA0, 0xB8, 0xA0, 0xD8, 0xA0, 0xF8, 0xA0, 0x38, 0xA1, 0x50, 0xA1, 0x58, 0xA1, 0x60,
594        0xA1, 0x78, 0xA1, 0x88, 0xA1, 0x98, 0xA1, 0xA8, 0xA1, 0xB8, 0xA1, 0xC8, 0xA1, 0xD8, 0xA1,
595        0xE8, 0xA1, 0xF8, 0xA1, 0x08, 0xA2, 0x18, 0xA2, 0x28, 0xA2, 0x38, 0xA2, 0x48, 0xA2, 0x58,
596        0xA2, 0x68, 0xA2, 0x78, 0xA2, 0x88, 0xA2, 0x98, 0xA2, 0xA8, 0xA2, 0xB8, 0xA2, 0xC8, 0xA2,
597        0xD8, 0xA2, 0xE8, 0xA2, 0xF8, 0xA2, 0x08, 0xA3, 0x18, 0xA3, 0x28, 0xA3, 0x38, 0xA3, 0x40,
598        0xA3, 0x48, 0xA3, 0x50, 0xA3, 0x58, 0xA3, 0x60, 0xA3, 0x68, 0xA3, 0x70, 0xA3, 0x78, 0xA3,
599        0x80, 0xA3, 0x88, 0xA3, 0x98, 0xA3, 0xA0, 0xA3, 0xA8, 0xA3, 0xB0, 0xA3, 0xB8, 0xA3, 0xC0,
600        0xA3, 0xC8, 0xA3, 0xD0, 0xA3, 0xE0, 0xA3, 0xA8, 0xA4, 0xB0, 0xA4, 0xC0, 0xA4, 0xF0, 0xA4,
601        0x28, 0xA5, 0x60, 0xA5, 0x98, 0xA5, 0xC8, 0xA5, 0xF0, 0xA5, 0xF8, 0xA5, 0x10, 0xA6, 0x30,
602        0xA6, 0x38, 0xA6, 0x40, 0xA6, 0x48, 0xA6, 0x50, 0xA6, 0x58, 0xA6, 0x68, 0xA6, 0xA0, 0xA6,
603        0xD0, 0xA6, 0xD8, 0xA6, 0xE0, 0xA6, 0xE8, 0xA6, 0xF8, 0xA6, 0x00, 0xA7, 0x08, 0xA7, 0x10,
604        0xA7, 0x48, 0xA7, 0x50, 0xA7, 0x60, 0xA7, 0xC8, 0xA7, 0xD0, 0xA7, 0xE0, 0xA7, 0x48, 0xA8,
605        0x50, 0xA8, 0x60, 0xA8, 0xD0, 0xA8, 0xD8, 0xA8, 0xE0, 0xA8, 0x18, 0xA9, 0x20, 0xA9, 0x30,
606        0xA9, 0x98, 0xA9, 0xA0, 0xA9, 0xB0, 0xA9, 0x20, 0xAA, 0x50, 0xAA, 0x78, 0xAA, 0x80, 0xAA,
607        0x88, 0xAA, 0x98, 0xAA, 0xA0, 0xAA, 0xA8, 0xAA, 0x00, 0x10, 0x18, 0x00, 0x8C, 0x00, 0x00,
608        0x00, 0x00, 0xA0, 0x08, 0xA0, 0x10, 0xA0, 0x18, 0xA0, 0x20, 0xA0, 0x28, 0xA0, 0x30, 0xA0,
609        0x38, 0xA0, 0x40, 0xA0, 0x48, 0xA0, 0x50, 0xA0, 0x58, 0xA0, 0x60, 0xA0, 0x68, 0xA0, 0x70,
610        0xA0, 0x78, 0xA0, 0x80, 0xA0, 0x88, 0xA0, 0x90, 0xA0, 0x98, 0xA0, 0xA0, 0xA0, 0xA8, 0xA0,
611        0xB0, 0xA0, 0xB8, 0xA0, 0xC0, 0xA0, 0xC8, 0xA0, 0xD0, 0xA0, 0xD8, 0xA0, 0xE0, 0xA0, 0xE8,
612        0xA0, 0xF0, 0xA0, 0xF8, 0xA0, 0x00, 0xA1, 0x08, 0xA1, 0x10, 0xA1, 0x18, 0xA1, 0x20, 0xA1,
613        0x28, 0xA1, 0x30, 0xA1, 0x38, 0xA1, 0x40, 0xA1, 0x48, 0xA1, 0x50, 0xA1, 0x58, 0xA1, 0x60,
614        0xA1, 0x68, 0xA1, 0x70, 0xA1, 0x78, 0xA1, 0x80, 0xA1, 0x88, 0xA1, 0x90, 0xA1, 0x98, 0xA1,
615        0xA0, 0xA1, 0xA8, 0xA1, 0xB0, 0xA1, 0xB8, 0xA1, 0xC0, 0xA1, 0xC8, 0xA1, 0xD0, 0xA1, 0xE0,
616        0xA1, 0xF0, 0xA3, 0xF8, 0xA3, 0x00, 0xA4, 0x08, 0xA4, 0x10, 0xA4, 0x18, 0xA4, 0x00, 0x50,
617        0x18, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00,
618    ];
619
620    #[test]
621    fn parse_baserelocs() {
622        let it = RelocationBlockIterator {
623            bytes: BASERELOC_DATA1,
624            offset: 0,
625        };
626        let blocks = it
627            .collect::<crate::error::Result<Vec<RelocationBlock>>>()
628            .unwrap();
629        assert_eq!(blocks.len(), 7);
630
631        const RELOC_ANY_ABSOLUTE: u8 = 0;
632        let ends_with_absrel = |block: &RelocationBlock| {
633            block
634                .words()
635                .last()
636                .transpose()
637                .unwrap()
638                .map(|x| x.reloc_type() == RELOC_ANY_ABSOLUTE)
639                .unwrap_or(false)
640        };
641
642        assert_eq!(blocks[0].rva, 0x0011D000);
643        assert_eq!(blocks[0].size, 0x234);
644        assert_eq!(ends_with_absrel(&blocks[0]), true);
645        assert_eq!(blocks[1].rva, 0x0011E000);
646        assert_eq!(blocks[1].size, 0x158);
647        assert_eq!(ends_with_absrel(&blocks[1]), false);
648        assert_eq!(blocks[2].rva, 0x00126000);
649        assert_eq!(blocks[2].size, 0x1C);
650        assert_eq!(ends_with_absrel(&blocks[2]), true);
651        assert_eq!(blocks[3].rva, 0x00152000);
652        assert_eq!(blocks[3].size, 0x28);
653        assert_eq!(ends_with_absrel(&blocks[3]), true);
654        assert_eq!(blocks[4].rva, 0x00166000);
655        assert_eq!(blocks[4].size, 0xE8);
656        assert_eq!(ends_with_absrel(&blocks[4]), false);
657        assert_eq!(blocks[5].rva, 0x00181000);
658        assert_eq!(blocks[5].size, 0x8C);
659        assert_eq!(ends_with_absrel(&blocks[5]), false);
660        assert_eq!(blocks[6].rva, 0x00185000);
661        assert_eq!(blocks[6].size, 0xC);
662        assert_eq!(ends_with_absrel(&blocks[6]), true);
663
664        let words = blocks
665            .iter()
666            .flat_map(|b| b.words())
667            .collect::<crate::error::Result<Vec<RelocationWord>>>()
668            .unwrap();
669        assert_eq!(words.len(), 652);
670    }
671}