Skip to main content

goblin/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/// Represents a PE base relocation directory data.
313#[derive(Debug, PartialEq, Clone, Default)]
314pub struct RelocationData<'a> {
315    /// Raw bytes covering the entire bytes of the base relocation directory.
316    bytes: &'a [u8],
317}
318
319impl<'a> RelocationData<'a> {
320    pub fn parse(
321        bytes: &'a [u8],
322        dd: data_directories::DataDirectory,
323        sections: &[section_table::SectionTable],
324        file_alignment: u32,
325    ) -> error::Result<Self> {
326        Self::parse_with_opts(
327            bytes,
328            dd,
329            sections,
330            file_alignment,
331            &options::ParseOptions::default(),
332        )
333    }
334
335    pub fn parse_with_opts(
336        bytes: &'a [u8],
337        dd: data_directories::DataDirectory,
338        sections: &[section_table::SectionTable],
339        file_alignment: u32,
340        opts: &options::ParseOptions,
341    ) -> error::Result<Self> {
342        let offset =
343            match utils::find_offset(dd.virtual_address as usize, sections, file_alignment, opts) {
344                Some(offset) => offset,
345                None => {
346                    return Err(error::Error::Malformed(format!(
347                        "Cannot map base reloc rva {:#x} into offset",
348                        dd.virtual_address
349                    )));
350                }
351            };
352
353        let available_size = if offset + (dd.size as usize) <= bytes.len() {
354            dd.size as usize
355        } else {
356            return Err(error::Error::Malformed(format!(
357                "base reloc offset {:#x} and size {:#x} exceeds the bounds of the bytes size {:#x}",
358                offset,
359                dd.size,
360                bytes.len()
361            )));
362        };
363
364        if offset >= bytes.len() {
365            return Err(error::Error::Malformed(format!(
366                "Relocation offset {:#x} is beyond file bounds (file size: {:#x})",
367                offset,
368                bytes.len()
369            )));
370        }
371
372        // Ensure we don't try to read more bytes than are actually available
373        let remaining_bytes = bytes.len() - offset;
374        let safe_available_size = available_size.min(remaining_bytes);
375
376        if safe_available_size != available_size {
377            return Err(error::Error::Malformed(format!(
378                "Relocation size {:#x} at offset {:#x} exceeds remaining file data ({:#x} bytes)",
379                available_size, offset, remaining_bytes
380            )));
381        }
382
383        let bytes = bytes
384            .pread_with::<&[u8]>(offset, safe_available_size)
385            .map_err(|_| {
386                error::Error::Malformed(format!(
387                    "base reloc offset {:#x} and size {:#x} exceeds the bounds of the bytes size {:#x}",
388                    offset,
389                    safe_available_size,
390                    bytes.len()
391                ))
392            })?;
393
394        Ok(Self { bytes })
395    }
396
397    /// Returns iterator for [`RelocationBlock`]
398    pub fn blocks(&self) -> RelocationBlockIterator<'a> {
399        RelocationBlockIterator {
400            bytes: &self.bytes,
401            offset: 0,
402        }
403    }
404}
405
406/// Represents a PE (Portable Executable) base relocation block.
407///
408/// In the PE format, base relocations are organized into blocks, where each block corresponds
409/// to a contiguous range of memory that needs to be relocated. The relocations within a block
410/// specify offsets relative to the block's starting address.
411///
412/// Unlike COFF (Common Object File Format), PE base relocations are separated by blocks.
413/// Each block begins with a [`RelocationBlock`] structure that provides information about the
414/// relocation block, including its starting RVA (Relative Virtual Address) and size in bytes.
415///
416/// Each block ends with an "absolute" relocation entry, which acts as a marker to indicate
417/// the end of the block. This entry has no actual relocation effect.
418#[derive(Debug, Copy, Clone, PartialEq, Default)]
419pub struct RelocationBlock<'a> {
420    /// The starting RVA for the relocation block.
421    pub rva: u32,
422    /// The total size of the relocation block, in bytes.
423    pub size: u32,
424    /// The bytes of [`RelocationWord`] data within this block.
425    pub bytes: &'a [u8],
426}
427
428impl RelocationBlock<'_> {
429    /// Returns iterator for [`RelocationWord`]
430    pub fn words(&self) -> RelocationWordIterator<'_> {
431        RelocationWordIterator {
432            bytes: &self.bytes,
433            offset: 0,
434        }
435    }
436}
437
438/// Raw size of [`RelocationBlock`]
439pub const RELOCATION_BLOCK_SIZE: usize = 8;
440
441impl<'a> scroll::ctx::TryFromCtx<'a, scroll::Endian> for RelocationBlock<'a> {
442    type Error = crate::error::Error;
443
444    fn try_from_ctx(bytes: &'a [u8], ctx: scroll::Endian) -> Result<(Self, usize), Self::Error> {
445        let mut offset = 0;
446        let rva = bytes.gread_with::<u32>(&mut offset, ctx)?;
447        let size = bytes.gread_with::<u32>(&mut offset, ctx)?;
448        if (size as usize) < RELOCATION_BLOCK_SIZE {
449            return Err(error::Error::Malformed(format!(
450                "base reloc size {size} is less than a block {RELOCATION_BLOCK_SIZE}"
451            )));
452        }
453        let word_size = size as usize - RELOCATION_BLOCK_SIZE;
454        let word_data = bytes.gread_with::<&[u8]>(&mut offset, word_size).map_err(|_| error::Error::Malformed(format!(
455                "base reloc block offset {:#x} and size {:#x} exceeds the bounds of the bytes size {:#x}",
456                offset,
457                word_size,
458                bytes.len()
459            )))?;
460        Ok((
461            Self {
462                rva,
463                size,
464                bytes: word_data,
465            },
466            offset,
467        ))
468    }
469}
470
471#[derive(Clone, Copy, Debug)]
472pub struct RelocationBlockIterator<'a> {
473    bytes: &'a [u8],
474    offset: usize,
475}
476
477impl<'a> Iterator for RelocationBlockIterator<'a> {
478    type Item = error::Result<RelocationBlock<'a>>;
479
480    fn next(&mut self) -> Option<Self::Item> {
481        if self.offset >= self.bytes.len() {
482            return None;
483        }
484
485        Some(
486            match self
487                .bytes
488                .gread_with::<RelocationBlock>(&mut self.offset, scroll::LE)
489            {
490                Ok(block) => Ok(block),
491                Err(error) => {
492                    self.bytes = &[];
493                    Err(error.into())
494                }
495            },
496        )
497    }
498}
499
500impl FusedIterator for RelocationBlockIterator<'_> {}
501
502/// Represents a single relocation entry within a PE base relocation block.
503///
504/// Each relocation entry is stored as a 16-bit value ([`u16`]), referred to as a "relocation word."
505/// The value is divided into two components:
506///
507/// * The upper 4 bits specify the relocation type, which determines how the relocation
508///   should be applied.
509/// * The remaining 12 bits specify the offset from the block's starting RVA where the
510///   relocation should be applied.
511#[derive(Debug, Copy, Clone, PartialEq, Default, Pread, Pwrite, IOread, IOwrite, SizeWith)]
512pub struct RelocationWord {
513    /// A 16-bit value encoding the relocation type and offset.
514    ///
515    /// - Upper 4 bits: relocation type.
516    /// - Lower 12 bits: offset from the base RVA.
517    pub value: u16,
518}
519
520impl RelocationWord {
521    /// Returns the relocation type from the upper 4 bits of [Self::value].
522    pub fn reloc_type(&self) -> u8 {
523        (self.value >> 12) as u8
524    }
525
526    /// Returns the relocation offset from the lower 16 bits of [Self::value].
527    pub fn offset(&self) -> u16 {
528        (self.value & 0xFFF) as u16
529    }
530}
531
532#[derive(Clone, Copy, Debug)]
533pub struct RelocationWordIterator<'a> {
534    bytes: &'a [u8],
535    offset: usize,
536}
537
538impl Iterator for RelocationWordIterator<'_> {
539    type Item = error::Result<RelocationWord>;
540
541    fn next(&mut self) -> Option<Self::Item> {
542        if self.offset >= self.bytes.len() {
543            return None;
544        }
545
546        Some(match self.bytes.gread_with(&mut self.offset, scroll::LE) {
547            Ok(word) => Ok(word),
548            Err(error) => {
549                self.bytes = &[];
550                Err(error.into())
551            }
552        })
553    }
554
555    fn size_hint(&self) -> (usize, Option<usize>) {
556        let count = self.bytes.len() / core::mem::size_of::<RelocationWord>();
557        (count, Some(count))
558    }
559}
560
561impl FusedIterator for RelocationWordIterator<'_> {}
562
563#[cfg(test)]
564mod tests {
565    use super::*;
566
567    static BASERELOC_DATA1: &[u8; 1360] = &[
568        0x00, 0xD0, 0x11, 0x00, 0x34, 0x02, 0x00, 0x00, 0x08, 0xA0, 0x18, 0xA0, 0x28, 0xA0, 0x38,
569        0xA0, 0x48, 0xA0, 0x58, 0xA0, 0x68, 0xA0, 0x78, 0xA0, 0x88, 0xA0, 0x98, 0xA0, 0xA8, 0xA0,
570        0xB8, 0xA0, 0xC8, 0xA0, 0xD8, 0xA0, 0xE0, 0xA0, 0xE8, 0xA0, 0xF0, 0xA0, 0xF8, 0xA0, 0x00,
571        0xA1, 0x08, 0xA1, 0x10, 0xA1, 0x18, 0xA1, 0x20, 0xA1, 0x28, 0xA1, 0x30, 0xA1, 0x38, 0xA1,
572        0x48, 0xA1, 0x50, 0xA1, 0x58, 0xA1, 0x60, 0xA1, 0x68, 0xA1, 0x70, 0xA1, 0x78, 0xA1, 0x80,
573        0xA1, 0x88, 0xA1, 0x98, 0xA1, 0xA0, 0xA1, 0xA8, 0xA1, 0xB8, 0xA1, 0xC0, 0xA1, 0xC8, 0xA1,
574        0xD0, 0xA1, 0xD8, 0xA1, 0xE8, 0xA1, 0xF8, 0xA1, 0x08, 0xA2, 0x18, 0xA2, 0x28, 0xA2, 0x38,
575        0xA2, 0x48, 0xA2, 0x58, 0xA2, 0x68, 0xA2, 0x78, 0xA2, 0x88, 0xA2, 0x98, 0xA2, 0xA8, 0xA2,
576        0xB8, 0xA2, 0xC8, 0xA2, 0xD8, 0xA2, 0xE8, 0xA2, 0x08, 0xA3, 0x28, 0xA3, 0x48, 0xA3, 0x68,
577        0xA3, 0x88, 0xA3, 0x98, 0xA3, 0xA8, 0xA3, 0xB8, 0xA3, 0xC8, 0xA3, 0xD8, 0xA3, 0xE8, 0xA3,
578        0xF8, 0xA3, 0x08, 0xA4, 0x18, 0xA4, 0x28, 0xA4, 0x38, 0xA4, 0x48, 0xA4, 0x58, 0xA4, 0x70,
579        0xA4, 0xA0, 0xA4, 0xA8, 0xA6, 0xB8, 0xA6, 0xC8, 0xA6, 0xD8, 0xA6, 0xE8, 0xA6, 0xF8, 0xA6,
580        0x00, 0xA7, 0x08, 0xA7, 0x30, 0xA7, 0x60, 0xA7, 0x88, 0xA7, 0x98, 0xA7, 0xA8, 0xA7, 0xB8,
581        0xA7, 0xC8, 0xA7, 0xD0, 0xA7, 0xD8, 0xA7, 0xE0, 0xA7, 0xF8, 0xA7, 0x00, 0xA8, 0x08, 0xA8,
582        0x10, 0xA8, 0x28, 0xA8, 0x38, 0xA8, 0x50, 0xA8, 0x70, 0xA8, 0x78, 0xA8, 0x80, 0xA8, 0x88,
583        0xA8, 0x90, 0xA8, 0x98, 0xA8, 0xA0, 0xA8, 0xA8, 0xA8, 0xB0, 0xA8, 0xB8, 0xA8, 0xC0, 0xA8,
584        0xC8, 0xA8, 0xD0, 0xA8, 0xD8, 0xA8, 0xE0, 0xA8, 0xE8, 0xA8, 0xF0, 0xA8, 0xF8, 0xA8, 0x00,
585        0xA9, 0x08, 0xA9, 0x10, 0xA9, 0x18, 0xA9, 0x20, 0xA9, 0x28, 0xA9, 0x30, 0xA9, 0x38, 0xA9,
586        0x40, 0xA9, 0x48, 0xA9, 0x50, 0xA9, 0x58, 0xA9, 0x60, 0xA9, 0x68, 0xA9, 0x70, 0xA9, 0x78,
587        0xA9, 0x80, 0xA9, 0x88, 0xA9, 0x90, 0xA9, 0x98, 0xA9, 0xA0, 0xA9, 0xA8, 0xA9, 0xB0, 0xA9,
588        0xB8, 0xA9, 0xC0, 0xA9, 0xC8, 0xA9, 0xD0, 0xA9, 0xD8, 0xA9, 0xE0, 0xA9, 0xE8, 0xA9, 0xF0,
589        0xA9, 0xF8, 0xA9, 0x00, 0xAA, 0x08, 0xAA, 0x10, 0xAA, 0x18, 0xAA, 0x20, 0xAA, 0x28, 0xAA,
590        0x30, 0xAA, 0x38, 0xAA, 0x40, 0xAA, 0x48, 0xAA, 0x50, 0xAA, 0x58, 0xAA, 0x70, 0xAA, 0x80,
591        0xAA, 0x88, 0xAA, 0x98, 0xAA, 0xB0, 0xAA, 0xC8, 0xAA, 0xE0, 0xAA, 0xF8, 0xAA, 0x08, 0xAB,
592        0x18, 0xAB, 0x28, 0xAB, 0x38, 0xAB, 0x48, 0xAB, 0x58, 0xAB, 0x68, 0xAB, 0x78, 0xAB, 0xD8,
593        0xAB, 0xF0, 0xAB, 0xF8, 0xAB, 0x00, 0xAC, 0x88, 0xAC, 0xA0, 0xAC, 0xA8, 0xAC, 0xB0, 0xAC,
594        0xB8, 0xAC, 0xC0, 0xAC, 0xC8, 0xAC, 0xD0, 0xAC, 0xD8, 0xAC, 0xE0, 0xAC, 0xE8, 0xAC, 0xF8,
595        0xAC, 0x00, 0xAD, 0x08, 0xAD, 0x10, 0xAD, 0x18, 0xAD, 0x20, 0xAD, 0x28, 0xAD, 0x30, 0xAD,
596        0x38, 0xAD, 0x48, 0xAD, 0x50, 0xAD, 0x58, 0xAD, 0x60, 0xAD, 0x70, 0xAD, 0x78, 0xAD, 0x80,
597        0xAD, 0x88, 0xAD, 0x98, 0xAD, 0xA0, 0xAD, 0xA8, 0xAD, 0xB0, 0xAD, 0xC8, 0xAD, 0xD0, 0xAD,
598        0xD8, 0xAD, 0xF0, 0xAD, 0xF8, 0xAD, 0x00, 0xAE, 0x18, 0xAE, 0x20, 0xAE, 0x28, 0xAE, 0x30,
599        0xAE, 0x38, 0xAE, 0x40, 0xAE, 0x48, 0xAE, 0x50, 0xAE, 0x58, 0xAE, 0x60, 0xAE, 0x68, 0xAE,
600        0x70, 0xAE, 0x78, 0xAE, 0x80, 0xAE, 0x88, 0xAE, 0x98, 0xAE, 0xA8, 0xAE, 0xB8, 0xAE, 0xC8,
601        0xAE, 0xD8, 0xAE, 0xE8, 0xAE, 0xF8, 0xAE, 0x08, 0xAF, 0x18, 0xAF, 0x20, 0xAF, 0x28, 0xAF,
602        0x30, 0xAF, 0x38, 0xAF, 0x40, 0xAF, 0x48, 0xAF, 0x50, 0xAF, 0x58, 0xAF, 0x60, 0xAF, 0x68,
603        0xAF, 0x70, 0xAF, 0x78, 0xAF, 0x80, 0xAF, 0x88, 0xAF, 0x90, 0xAF, 0x98, 0xAF, 0xA0, 0xAF,
604        0xA8, 0xAF, 0xB0, 0xAF, 0xB8, 0xAF, 0xC0, 0xAF, 0xC8, 0xAF, 0xD0, 0xAF, 0xD8, 0xAF, 0xE0,
605        0xAF, 0xE8, 0xAF, 0xF0, 0xAF, 0xF8, 0xAF, 0x00, 0x00, 0x00, 0xE0, 0x11, 0x00, 0x58, 0x01,
606        0x00, 0x00, 0x00, 0xA0, 0x08, 0xA0, 0x10, 0xA0, 0x18, 0xA0, 0x20, 0xA0, 0x30, 0xA0, 0x40,
607        0xA0, 0x48, 0xA0, 0x50, 0xA0, 0x58, 0xA0, 0x60, 0xA0, 0x68, 0xA0, 0x70, 0xA0, 0x78, 0xA0,
608        0x80, 0xA0, 0x88, 0xA0, 0x90, 0xA0, 0x98, 0xA0, 0xA0, 0xA0, 0xA8, 0xA0, 0xB0, 0xA0, 0xB8,
609        0xA0, 0xC0, 0xA0, 0xC8, 0xA0, 0xD0, 0xA0, 0xD8, 0xA0, 0xE0, 0xA0, 0xE8, 0xA0, 0xF0, 0xA0,
610        0xF8, 0xA0, 0x00, 0xA1, 0x08, 0xA1, 0x10, 0xA1, 0x18, 0xA1, 0x20, 0xA1, 0x28, 0xA1, 0x30,
611        0xA1, 0x38, 0xA1, 0x40, 0xA1, 0x48, 0xA1, 0x50, 0xA1, 0x58, 0xA1, 0x60, 0xA1, 0x68, 0xA1,
612        0x70, 0xA1, 0x78, 0xA1, 0x80, 0xA1, 0x88, 0xA1, 0x90, 0xA1, 0x98, 0xA1, 0xA0, 0xA1, 0xA8,
613        0xA1, 0xB0, 0xA1, 0xB8, 0xA1, 0xC0, 0xA1, 0xC8, 0xA1, 0xD0, 0xA1, 0xD8, 0xA1, 0xE0, 0xA1,
614        0xF0, 0xA1, 0x08, 0xA2, 0x10, 0xA2, 0x20, 0xA2, 0x30, 0xA2, 0x48, 0xA2, 0x50, 0xA2, 0x58,
615        0xA2, 0x60, 0xA2, 0x68, 0xA2, 0x70, 0xA2, 0x78, 0xA2, 0x88, 0xA2, 0x90, 0xA2, 0xA0, 0xA2,
616        0xA8, 0xA2, 0xB8, 0xA2, 0xC0, 0xA2, 0xD0, 0xA2, 0xD8, 0xA2, 0xE8, 0xA2, 0xF0, 0xA2, 0x08,
617        0xA3, 0x18, 0xA3, 0x28, 0xA3, 0x38, 0xA3, 0x48, 0xA3, 0x58, 0xA3, 0x68, 0xA3, 0x78, 0xA3,
618        0x80, 0xA3, 0x88, 0xA3, 0x90, 0xA3, 0x98, 0xA3, 0xA0, 0xA3, 0xA8, 0xA3, 0xB8, 0xA3, 0xC8,
619        0xA3, 0xD8, 0xA3, 0xF0, 0xA3, 0x18, 0xA4, 0x20, 0xA4, 0x30, 0xA4, 0x40, 0xA4, 0x50, 0xA4,
620        0x60, 0xA4, 0x70, 0xA4, 0x80, 0xA4, 0x90, 0xA4, 0xA0, 0xA4, 0xB0, 0xA4, 0xC0, 0xA4, 0xD0,
621        0xA4, 0xE0, 0xA4, 0xF0, 0xA4, 0x00, 0xA5, 0x10, 0xA5, 0x28, 0xA5, 0x50, 0xA5, 0x60, 0xA5,
622        0x70, 0xA5, 0x80, 0xA5, 0x90, 0xA5, 0xA0, 0xA5, 0xB0, 0xA5, 0xC0, 0xA5, 0xD0, 0xA5, 0xE0,
623        0xA5, 0xF0, 0xA5, 0x00, 0xA6, 0x10, 0xA6, 0x20, 0xA6, 0x28, 0xA6, 0x30, 0xA6, 0x38, 0xA6,
624        0x50, 0xA6, 0x68, 0xA6, 0x78, 0xA6, 0x88, 0xA6, 0x98, 0xA6, 0xA8, 0xA6, 0xB8, 0xA6, 0xC8,
625        0xA6, 0xD8, 0xA6, 0xE8, 0xA6, 0xF8, 0xA6, 0x08, 0xA7, 0x18, 0xA7, 0x28, 0xA7, 0x38, 0xA7,
626        0x48, 0xA7, 0x58, 0xA7, 0x68, 0xA7, 0x78, 0xA7, 0x88, 0xA7, 0x98, 0xA7, 0xA8, 0xA7, 0xB8,
627        0xA7, 0xC8, 0xA7, 0xD8, 0xA7, 0xE8, 0xA7, 0xF8, 0xA7, 0x08, 0xA8, 0x18, 0xA8, 0x28, 0xA8,
628        0x38, 0xA8, 0x58, 0xA8, 0x68, 0xA8, 0x80, 0xA8, 0x00, 0x60, 0x12, 0x00, 0x1C, 0x00, 0x00,
629        0x00, 0xA0, 0xA9, 0xA8, 0xA9, 0xB0, 0xA9, 0xB8, 0xA9, 0xC0, 0xA9, 0xC8, 0xA9, 0xD0, 0xA9,
630        0xD8, 0xA9, 0xE0, 0xA9, 0x00, 0x00, 0x00, 0x20, 0x15, 0x00, 0x28, 0x00, 0x00, 0x00, 0xE8,
631        0xA0, 0xF0, 0xA0, 0xF8, 0xA0, 0x08, 0xA1, 0x10, 0xA1, 0x18, 0xA1, 0x20, 0xA1, 0x38, 0xA1,
632        0x40, 0xA1, 0x48, 0xA1, 0x58, 0xA1, 0x60, 0xA1, 0x68, 0xA1, 0x70, 0xA1, 0x90, 0xA1, 0x00,
633        0x00, 0x00, 0x60, 0x16, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x08, 0xA0, 0x78, 0xA0,
634        0x98, 0xA0, 0xB8, 0xA0, 0xD8, 0xA0, 0xF8, 0xA0, 0x38, 0xA1, 0x50, 0xA1, 0x58, 0xA1, 0x60,
635        0xA1, 0x78, 0xA1, 0x88, 0xA1, 0x98, 0xA1, 0xA8, 0xA1, 0xB8, 0xA1, 0xC8, 0xA1, 0xD8, 0xA1,
636        0xE8, 0xA1, 0xF8, 0xA1, 0x08, 0xA2, 0x18, 0xA2, 0x28, 0xA2, 0x38, 0xA2, 0x48, 0xA2, 0x58,
637        0xA2, 0x68, 0xA2, 0x78, 0xA2, 0x88, 0xA2, 0x98, 0xA2, 0xA8, 0xA2, 0xB8, 0xA2, 0xC8, 0xA2,
638        0xD8, 0xA2, 0xE8, 0xA2, 0xF8, 0xA2, 0x08, 0xA3, 0x18, 0xA3, 0x28, 0xA3, 0x38, 0xA3, 0x40,
639        0xA3, 0x48, 0xA3, 0x50, 0xA3, 0x58, 0xA3, 0x60, 0xA3, 0x68, 0xA3, 0x70, 0xA3, 0x78, 0xA3,
640        0x80, 0xA3, 0x88, 0xA3, 0x98, 0xA3, 0xA0, 0xA3, 0xA8, 0xA3, 0xB0, 0xA3, 0xB8, 0xA3, 0xC0,
641        0xA3, 0xC8, 0xA3, 0xD0, 0xA3, 0xE0, 0xA3, 0xA8, 0xA4, 0xB0, 0xA4, 0xC0, 0xA4, 0xF0, 0xA4,
642        0x28, 0xA5, 0x60, 0xA5, 0x98, 0xA5, 0xC8, 0xA5, 0xF0, 0xA5, 0xF8, 0xA5, 0x10, 0xA6, 0x30,
643        0xA6, 0x38, 0xA6, 0x40, 0xA6, 0x48, 0xA6, 0x50, 0xA6, 0x58, 0xA6, 0x68, 0xA6, 0xA0, 0xA6,
644        0xD0, 0xA6, 0xD8, 0xA6, 0xE0, 0xA6, 0xE8, 0xA6, 0xF8, 0xA6, 0x00, 0xA7, 0x08, 0xA7, 0x10,
645        0xA7, 0x48, 0xA7, 0x50, 0xA7, 0x60, 0xA7, 0xC8, 0xA7, 0xD0, 0xA7, 0xE0, 0xA7, 0x48, 0xA8,
646        0x50, 0xA8, 0x60, 0xA8, 0xD0, 0xA8, 0xD8, 0xA8, 0xE0, 0xA8, 0x18, 0xA9, 0x20, 0xA9, 0x30,
647        0xA9, 0x98, 0xA9, 0xA0, 0xA9, 0xB0, 0xA9, 0x20, 0xAA, 0x50, 0xAA, 0x78, 0xAA, 0x80, 0xAA,
648        0x88, 0xAA, 0x98, 0xAA, 0xA0, 0xAA, 0xA8, 0xAA, 0x00, 0x10, 0x18, 0x00, 0x8C, 0x00, 0x00,
649        0x00, 0x00, 0xA0, 0x08, 0xA0, 0x10, 0xA0, 0x18, 0xA0, 0x20, 0xA0, 0x28, 0xA0, 0x30, 0xA0,
650        0x38, 0xA0, 0x40, 0xA0, 0x48, 0xA0, 0x50, 0xA0, 0x58, 0xA0, 0x60, 0xA0, 0x68, 0xA0, 0x70,
651        0xA0, 0x78, 0xA0, 0x80, 0xA0, 0x88, 0xA0, 0x90, 0xA0, 0x98, 0xA0, 0xA0, 0xA0, 0xA8, 0xA0,
652        0xB0, 0xA0, 0xB8, 0xA0, 0xC0, 0xA0, 0xC8, 0xA0, 0xD0, 0xA0, 0xD8, 0xA0, 0xE0, 0xA0, 0xE8,
653        0xA0, 0xF0, 0xA0, 0xF8, 0xA0, 0x00, 0xA1, 0x08, 0xA1, 0x10, 0xA1, 0x18, 0xA1, 0x20, 0xA1,
654        0x28, 0xA1, 0x30, 0xA1, 0x38, 0xA1, 0x40, 0xA1, 0x48, 0xA1, 0x50, 0xA1, 0x58, 0xA1, 0x60,
655        0xA1, 0x68, 0xA1, 0x70, 0xA1, 0x78, 0xA1, 0x80, 0xA1, 0x88, 0xA1, 0x90, 0xA1, 0x98, 0xA1,
656        0xA0, 0xA1, 0xA8, 0xA1, 0xB0, 0xA1, 0xB8, 0xA1, 0xC0, 0xA1, 0xC8, 0xA1, 0xD0, 0xA1, 0xE0,
657        0xA1, 0xF0, 0xA3, 0xF8, 0xA3, 0x00, 0xA4, 0x08, 0xA4, 0x10, 0xA4, 0x18, 0xA4, 0x00, 0x50,
658        0x18, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00,
659    ];
660
661    #[test]
662    fn parse_baserelocs() {
663        let it = RelocationBlockIterator {
664            bytes: BASERELOC_DATA1,
665            offset: 0,
666        };
667        let blocks = it
668            .collect::<crate::error::Result<Vec<RelocationBlock>>>()
669            .unwrap();
670        assert_eq!(blocks.len(), 7);
671
672        const RELOC_ANY_ABSOLUTE: u8 = 0;
673        let ends_with_absrel = |block: &RelocationBlock| {
674            block
675                .words()
676                .last()
677                .transpose()
678                .unwrap()
679                .map(|x| x.reloc_type() == RELOC_ANY_ABSOLUTE)
680                .unwrap_or(false)
681        };
682
683        assert_eq!(blocks[0].rva, 0x0011D000);
684        assert_eq!(blocks[0].size, 0x234);
685        assert_eq!(ends_with_absrel(&blocks[0]), true);
686        assert_eq!(blocks[1].rva, 0x0011E000);
687        assert_eq!(blocks[1].size, 0x158);
688        assert_eq!(ends_with_absrel(&blocks[1]), false);
689        assert_eq!(blocks[2].rva, 0x00126000);
690        assert_eq!(blocks[2].size, 0x1C);
691        assert_eq!(ends_with_absrel(&blocks[2]), true);
692        assert_eq!(blocks[3].rva, 0x00152000);
693        assert_eq!(blocks[3].size, 0x28);
694        assert_eq!(ends_with_absrel(&blocks[3]), true);
695        assert_eq!(blocks[4].rva, 0x00166000);
696        assert_eq!(blocks[4].size, 0xE8);
697        assert_eq!(ends_with_absrel(&blocks[4]), false);
698        assert_eq!(blocks[5].rva, 0x00181000);
699        assert_eq!(blocks[5].size, 0x8C);
700        assert_eq!(ends_with_absrel(&blocks[5]), false);
701        assert_eq!(blocks[6].rva, 0x00185000);
702        assert_eq!(blocks[6].size, 0xC);
703        assert_eq!(ends_with_absrel(&blocks[6]), true);
704
705        let words = blocks
706            .iter()
707            .flat_map(|b| b.words())
708            .collect::<crate::error::Result<Vec<RelocationWord>>>()
709            .unwrap();
710        assert_eq!(words.len(), 652);
711    }
712}