object/read/elf/
relocation.rs

1use alloc::fmt;
2use alloc::vec::Vec;
3use core::fmt::Debug;
4use core::slice;
5
6use crate::elf;
7use crate::endian::{self, Endianness};
8use crate::pod::Pod;
9use crate::read::{
10    self, Error, ReadRef, Relocation, RelocationEncoding, RelocationFlags, RelocationKind,
11    RelocationTarget, SectionIndex, SymbolIndex,
12};
13
14use super::{ElfFile, FileHeader, SectionHeader, SectionTable};
15
16/// A mapping from section index to associated relocation sections.
17#[derive(Debug, Default)]
18pub struct RelocationSections {
19    relocations: Vec<usize>,
20}
21
22impl RelocationSections {
23    /// Create a new mapping using the section table.
24    ///
25    /// Skips relocation sections that do not use the given symbol table section.
26    pub fn parse<'data, Elf: FileHeader, R: ReadRef<'data>>(
27        endian: Elf::Endian,
28        sections: &SectionTable<'data, Elf, R>,
29        symbol_section: SectionIndex,
30    ) -> read::Result<Self> {
31        let mut relocations = vec![0; sections.len()];
32        for (index, section) in sections.iter().enumerate().rev() {
33            let sh_type = section.sh_type(endian);
34            if sh_type == elf::SHT_REL || sh_type == elf::SHT_RELA {
35                // The symbol indices used in relocations must be for the symbol table
36                // we are expecting to use.
37                let sh_link = section.link(endian);
38                if sh_link != symbol_section {
39                    continue;
40                }
41
42                let sh_info = section.info_link(endian);
43                if sh_info == SectionIndex(0) {
44                    // Skip dynamic relocations.
45                    continue;
46                }
47                if sh_info.0 >= relocations.len() {
48                    return Err(Error("Invalid ELF sh_info for relocation section"));
49                }
50
51                // We don't support relocations that apply to other relocation sections
52                // because it interferes with the chaining of relocation sections below.
53                let sh_info_type = sections.section(sh_info)?.sh_type(endian);
54                if sh_info_type == elf::SHT_REL || sh_info_type == elf::SHT_RELA {
55                    return Err(Error("Unsupported ELF sh_info for relocation section"));
56                }
57
58                // Handle multiple relocation sections by chaining them.
59                let next = relocations[sh_info.0];
60                relocations[sh_info.0] = index;
61                relocations[index] = next;
62            }
63        }
64        Ok(Self { relocations })
65    }
66
67    /// Given a section index, return the section index of the associated relocation section.
68    ///
69    /// This may also be called with a relocation section index, and it will return the
70    /// next associated relocation section.
71    pub fn get(&self, index: SectionIndex) -> Option<SectionIndex> {
72        self.relocations
73            .get(index.0)
74            .cloned()
75            .filter(|x| *x != 0)
76            .map(SectionIndex)
77    }
78}
79
80pub(super) enum ElfRelaIterator<'data, Elf: FileHeader> {
81    Rel(slice::Iter<'data, Elf::Rel>),
82    Rela(slice::Iter<'data, Elf::Rela>),
83}
84
85impl<'data, Elf: FileHeader> ElfRelaIterator<'data, Elf> {
86    fn is_rel(&self) -> bool {
87        match self {
88            ElfRelaIterator::Rel(_) => true,
89            ElfRelaIterator::Rela(_) => false,
90        }
91    }
92}
93
94impl<'data, Elf: FileHeader> Iterator for ElfRelaIterator<'data, Elf> {
95    type Item = Elf::Rela;
96
97    fn next(&mut self) -> Option<Self::Item> {
98        match self {
99            ElfRelaIterator::Rel(ref mut i) => i.next().cloned().map(Self::Item::from),
100            ElfRelaIterator::Rela(ref mut i) => i.next().cloned(),
101        }
102    }
103}
104
105/// An iterator for the dynamic relocations in an [`ElfFile32`](super::ElfFile32).
106pub type ElfDynamicRelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
107    ElfDynamicRelocationIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
108/// An iterator for the dynamic relocations in an [`ElfFile64`](super::ElfFile64).
109pub type ElfDynamicRelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
110    ElfDynamicRelocationIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
111
112/// An iterator for the dynamic relocations in an [`ElfFile`].
113pub struct ElfDynamicRelocationIterator<'data, 'file, Elf, R = &'data [u8]>
114where
115    Elf: FileHeader,
116    R: ReadRef<'data>,
117{
118    /// The current relocation section index.
119    pub(super) section_index: SectionIndex,
120    pub(super) file: &'file ElfFile<'data, Elf, R>,
121    pub(super) relocations: Option<ElfRelaIterator<'data, Elf>>,
122}
123
124impl<'data, 'file, Elf, R> Iterator for ElfDynamicRelocationIterator<'data, 'file, Elf, R>
125where
126    Elf: FileHeader,
127    R: ReadRef<'data>,
128{
129    type Item = (u64, Relocation);
130
131    fn next(&mut self) -> Option<Self::Item> {
132        let endian = self.file.endian;
133        loop {
134            if let Some(ref mut relocations) = self.relocations {
135                if let Some(reloc) = relocations.next() {
136                    let relocation =
137                        parse_relocation(self.file.header, endian, reloc, relocations.is_rel());
138                    return Some((reloc.r_offset(endian).into(), relocation));
139                }
140                self.relocations = None;
141            }
142
143            let section = self.file.sections.section(self.section_index).ok()?;
144            self.section_index.0 += 1;
145
146            if section.link(endian) != self.file.dynamic_symbols.section() {
147                continue;
148            }
149
150            match section.sh_type(endian) {
151                elf::SHT_REL => {
152                    if let Ok(relocations) = section.data_as_array(endian, self.file.data) {
153                        self.relocations = Some(ElfRelaIterator::Rel(relocations.iter()));
154                    }
155                }
156                elf::SHT_RELA => {
157                    if let Ok(relocations) = section.data_as_array(endian, self.file.data) {
158                        self.relocations = Some(ElfRelaIterator::Rela(relocations.iter()));
159                    }
160                }
161                _ => {}
162            }
163        }
164    }
165}
166
167impl<'data, 'file, Elf, R> fmt::Debug for ElfDynamicRelocationIterator<'data, 'file, Elf, R>
168where
169    Elf: FileHeader,
170    R: ReadRef<'data>,
171{
172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173        f.debug_struct("ElfDynamicRelocationIterator").finish()
174    }
175}
176
177/// An iterator for the relocations for an [`ElfSection32`](super::ElfSection32).
178pub type ElfSectionRelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
179    ElfSectionRelocationIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
180/// An iterator for the relocations for an [`ElfSection64`](super::ElfSection64).
181pub type ElfSectionRelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
182    ElfSectionRelocationIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
183
184/// An iterator for the relocations for an [`ElfSection`](super::ElfSection).
185pub struct ElfSectionRelocationIterator<'data, 'file, Elf, R = &'data [u8]>
186where
187    Elf: FileHeader,
188    R: ReadRef<'data>,
189{
190    /// The current pointer in the chain of relocation sections.
191    pub(super) section_index: SectionIndex,
192    pub(super) file: &'file ElfFile<'data, Elf, R>,
193    pub(super) relocations: Option<ElfRelaIterator<'data, Elf>>,
194}
195
196impl<'data, 'file, Elf, R> Iterator for ElfSectionRelocationIterator<'data, 'file, Elf, R>
197where
198    Elf: FileHeader,
199    R: ReadRef<'data>,
200{
201    type Item = (u64, Relocation);
202
203    fn next(&mut self) -> Option<Self::Item> {
204        let endian = self.file.endian;
205        loop {
206            if let Some(ref mut relocations) = self.relocations {
207                if let Some(reloc) = relocations.next() {
208                    let relocation =
209                        parse_relocation(self.file.header, endian, reloc, relocations.is_rel());
210                    return Some((reloc.r_offset(endian).into(), relocation));
211                }
212                self.relocations = None;
213            }
214            self.section_index = self.file.relocations.get(self.section_index)?;
215            // The construction of RelocationSections ensures section_index is valid.
216            let section = self.file.sections.section(self.section_index).unwrap();
217            match section.sh_type(endian) {
218                elf::SHT_REL => {
219                    if let Ok(relocations) = section.data_as_array(endian, self.file.data) {
220                        self.relocations = Some(ElfRelaIterator::Rel(relocations.iter()));
221                    }
222                }
223                elf::SHT_RELA => {
224                    if let Ok(relocations) = section.data_as_array(endian, self.file.data) {
225                        self.relocations = Some(ElfRelaIterator::Rela(relocations.iter()));
226                    }
227                }
228                _ => {}
229            }
230        }
231    }
232}
233
234impl<'data, 'file, Elf, R> fmt::Debug for ElfSectionRelocationIterator<'data, 'file, Elf, R>
235where
236    Elf: FileHeader,
237    R: ReadRef<'data>,
238{
239    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240        f.debug_struct("ElfSectionRelocationIterator").finish()
241    }
242}
243
244fn parse_relocation<Elf: FileHeader>(
245    header: &Elf,
246    endian: Elf::Endian,
247    reloc: Elf::Rela,
248    implicit_addend: bool,
249) -> Relocation {
250    use RelocationEncoding as E;
251    use RelocationKind as K;
252
253    let is_mips64el = header.is_mips64el(endian);
254    let r_type = reloc.r_type(endian, is_mips64el);
255    let flags = RelocationFlags::Elf { r_type };
256    let g = E::Generic;
257    let unknown = (K::Unknown, E::Generic, 0);
258    let (kind, encoding, size) = match header.e_machine(endian) {
259        elf::EM_AARCH64 => {
260            if header.is_type_64() {
261                match r_type {
262                    elf::R_AARCH64_ABS64 => (K::Absolute, g, 64),
263                    elf::R_AARCH64_ABS32 => (K::Absolute, g, 32),
264                    elf::R_AARCH64_ABS16 => (K::Absolute, g, 16),
265                    elf::R_AARCH64_PREL64 => (K::Relative, g, 64),
266                    elf::R_AARCH64_PREL32 => (K::Relative, g, 32),
267                    elf::R_AARCH64_PREL16 => (K::Relative, g, 16),
268                    elf::R_AARCH64_CALL26 => (K::PltRelative, E::AArch64Call, 26),
269                    _ => unknown,
270                }
271            } else {
272                match r_type {
273                    elf::R_AARCH64_P32_ABS32 => (K::Absolute, g, 32),
274                    _ => unknown,
275                }
276            }
277        }
278        elf::EM_ARM => match r_type {
279            elf::R_ARM_ABS32 => (K::Absolute, g, 32),
280            _ => unknown,
281        },
282        elf::EM_AVR => match r_type {
283            elf::R_AVR_32 => (K::Absolute, g, 32),
284            elf::R_AVR_16 => (K::Absolute, g, 16),
285            _ => unknown,
286        },
287        elf::EM_BPF => match r_type {
288            elf::R_BPF_64_64 => (K::Absolute, g, 64),
289            elf::R_BPF_64_32 => (K::Absolute, g, 32),
290            _ => unknown,
291        },
292        elf::EM_CSKY => match r_type {
293            elf::R_CKCORE_ADDR32 => (K::Absolute, g, 32),
294            elf::R_CKCORE_PCREL32 => (K::Relative, g, 32),
295            _ => unknown,
296        },
297        elf::EM_MCST_ELBRUS => match r_type {
298            elf::R_E2K_32_ABS => (K::Absolute, g, 32),
299            elf::R_E2K_64_ABS => (K::Absolute, g, 64),
300            elf::R_E2K_64_ABS_LIT => (K::Absolute, E::E2KLit, 64),
301            elf::R_E2K_DISP => (K::Relative, E::E2KDisp, 28),
302            elf::R_E2K_GOT => (K::Got, g, 32),
303            _ => unknown,
304        },
305        elf::EM_386 => match r_type {
306            elf::R_386_32 => (K::Absolute, g, 32),
307            elf::R_386_PC32 => (K::Relative, g, 32),
308            elf::R_386_GOT32 => (K::Got, g, 32),
309            elf::R_386_PLT32 => (K::PltRelative, g, 32),
310            elf::R_386_GOTOFF => (K::GotBaseOffset, g, 32),
311            elf::R_386_GOTPC => (K::GotBaseRelative, g, 32),
312            elf::R_386_16 => (K::Absolute, g, 16),
313            elf::R_386_PC16 => (K::Relative, g, 16),
314            elf::R_386_8 => (K::Absolute, g, 8),
315            elf::R_386_PC8 => (K::Relative, g, 8),
316            _ => unknown,
317        },
318        elf::EM_X86_64 => match r_type {
319            elf::R_X86_64_64 => (K::Absolute, g, 64),
320            elf::R_X86_64_PC32 => (K::Relative, g, 32),
321            elf::R_X86_64_GOT32 => (K::Got, g, 32),
322            elf::R_X86_64_PLT32 => (K::PltRelative, g, 32),
323            elf::R_X86_64_GOTPCREL => (K::GotRelative, g, 32),
324            elf::R_X86_64_32 => (K::Absolute, g, 32),
325            elf::R_X86_64_32S => (K::Absolute, E::X86Signed, 32),
326            elf::R_X86_64_16 => (K::Absolute, g, 16),
327            elf::R_X86_64_PC16 => (K::Relative, g, 16),
328            elf::R_X86_64_8 => (K::Absolute, g, 8),
329            elf::R_X86_64_PC8 => (K::Relative, g, 8),
330            _ => unknown,
331        },
332        elf::EM_HEXAGON => match r_type {
333            elf::R_HEX_32 => (K::Absolute, g, 32),
334            _ => unknown,
335        },
336        elf::EM_LOONGARCH => match r_type {
337            elf::R_LARCH_32 => (K::Absolute, g, 32),
338            elf::R_LARCH_64 => (K::Absolute, g, 64),
339            elf::R_LARCH_32_PCREL => (K::Relative, g, 32),
340            elf::R_LARCH_64_PCREL => (K::Relative, g, 64),
341            elf::R_LARCH_B16 => (K::Relative, E::LoongArchBranch, 16),
342            elf::R_LARCH_B21 => (K::Relative, E::LoongArchBranch, 21),
343            elf::R_LARCH_B26 => (K::Relative, E::LoongArchBranch, 26),
344            _ => unknown,
345        },
346        elf::EM_68K => match r_type {
347            elf::R_68K_32 => (K::Absolute, g, 32),
348            elf::R_68K_16 => (K::Absolute, g, 16),
349            elf::R_68K_8 => (K::Absolute, g, 8),
350            elf::R_68K_PC32 => (K::Relative, g, 32),
351            elf::R_68K_PC16 => (K::Relative, g, 16),
352            elf::R_68K_PC8 => (K::Relative, g, 8),
353            elf::R_68K_GOT32O => (K::Got, g, 32),
354            elf::R_68K_GOT16O => (K::Got, g, 16),
355            elf::R_68K_GOT8O => (K::Got, g, 8),
356            elf::R_68K_GOT32 => (K::GotRelative, g, 32),
357            elf::R_68K_GOT16 => (K::GotRelative, g, 16),
358            elf::R_68K_GOT8 => (K::GotRelative, g, 8),
359            elf::R_68K_PLT32 => (K::PltRelative, g, 32),
360            elf::R_68K_PLT16 => (K::PltRelative, g, 16),
361            elf::R_68K_PLT8 => (K::PltRelative, g, 8),
362            _ => unknown,
363        },
364        elf::EM_MIPS => match r_type {
365            elf::R_MIPS_16 => (K::Absolute, g, 16),
366            elf::R_MIPS_32 => (K::Absolute, g, 32),
367            elf::R_MIPS_64 => (K::Absolute, g, 64),
368            _ => unknown,
369        },
370        elf::EM_MSP430 => match r_type {
371            elf::R_MSP430_32 => (K::Absolute, g, 32),
372            elf::R_MSP430_16_BYTE => (K::Absolute, g, 16),
373            _ => unknown,
374        },
375        elf::EM_PPC => match r_type {
376            elf::R_PPC_ADDR32 => (K::Absolute, g, 32),
377            _ => unknown,
378        },
379        elf::EM_PPC64 => match r_type {
380            elf::R_PPC64_ADDR32 => (K::Absolute, g, 32),
381            elf::R_PPC64_ADDR64 => (K::Absolute, g, 64),
382            _ => unknown,
383        },
384        elf::EM_RISCV => match r_type {
385            elf::R_RISCV_32 => (K::Absolute, g, 32),
386            elf::R_RISCV_64 => (K::Absolute, g, 64),
387            _ => unknown,
388        },
389        elf::EM_S390 => match r_type {
390            elf::R_390_8 => (K::Absolute, g, 8),
391            elf::R_390_16 => (K::Absolute, g, 16),
392            elf::R_390_32 => (K::Absolute, g, 32),
393            elf::R_390_64 => (K::Absolute, g, 64),
394            elf::R_390_PC16 => (K::Relative, g, 16),
395            elf::R_390_PC32 => (K::Relative, g, 32),
396            elf::R_390_PC64 => (K::Relative, g, 64),
397            elf::R_390_PC16DBL => (K::Relative, E::S390xDbl, 16),
398            elf::R_390_PC32DBL => (K::Relative, E::S390xDbl, 32),
399            elf::R_390_PLT16DBL => (K::PltRelative, E::S390xDbl, 16),
400            elf::R_390_PLT32DBL => (K::PltRelative, E::S390xDbl, 32),
401            elf::R_390_GOT16 => (K::Got, g, 16),
402            elf::R_390_GOT32 => (K::Got, g, 32),
403            elf::R_390_GOT64 => (K::Got, g, 64),
404            elf::R_390_GOTENT => (K::GotRelative, E::S390xDbl, 32),
405            elf::R_390_GOTOFF16 => (K::GotBaseOffset, g, 16),
406            elf::R_390_GOTOFF32 => (K::GotBaseOffset, g, 32),
407            elf::R_390_GOTOFF64 => (K::GotBaseOffset, g, 64),
408            elf::R_390_GOTPC => (K::GotBaseRelative, g, 64),
409            elf::R_390_GOTPCDBL => (K::GotBaseRelative, E::S390xDbl, 32),
410            _ => unknown,
411        },
412        elf::EM_SBF => match r_type {
413            elf::R_SBF_64_64 => (K::Absolute, g, 64),
414            elf::R_SBF_64_32 => (K::Absolute, g, 32),
415            _ => unknown,
416        },
417        elf::EM_SHARC => match r_type {
418            elf::R_SHARC_ADDR24_V3 => (K::Absolute, E::SharcTypeA, 24),
419            elf::R_SHARC_ADDR32_V3 => (K::Absolute, E::SharcTypeA, 32),
420            elf::R_SHARC_ADDR_VAR_V3 => (K::Absolute, E::Generic, 32),
421            elf::R_SHARC_PCRSHORT_V3 => (K::Relative, E::SharcTypeA, 6),
422            elf::R_SHARC_PCRLONG_V3 => (K::Relative, E::SharcTypeA, 24),
423            elf::R_SHARC_DATA6_V3 => (K::Absolute, E::SharcTypeA, 6),
424            elf::R_SHARC_DATA16_V3 => (K::Absolute, E::SharcTypeA, 16),
425            elf::R_SHARC_DATA6_VISA_V3 => (K::Absolute, E::SharcTypeB, 6),
426            elf::R_SHARC_DATA7_VISA_V3 => (K::Absolute, E::SharcTypeB, 7),
427            elf::R_SHARC_DATA16_VISA_V3 => (K::Absolute, E::SharcTypeB, 16),
428            elf::R_SHARC_PCR6_VISA_V3 => (K::Relative, E::SharcTypeB, 16),
429            elf::R_SHARC_ADDR_VAR16_V3 => (K::Absolute, E::Generic, 16),
430            _ => unknown,
431        },
432        elf::EM_SPARC | elf::EM_SPARC32PLUS | elf::EM_SPARCV9 => match r_type {
433            elf::R_SPARC_32 | elf::R_SPARC_UA32 => (K::Absolute, g, 32),
434            elf::R_SPARC_64 | elf::R_SPARC_UA64 => (K::Absolute, g, 64),
435            _ => unknown,
436        },
437        elf::EM_XTENSA => match r_type {
438            elf::R_XTENSA_32 => (K::Absolute, g, 32),
439            elf::R_XTENSA_32_PCREL => (K::Relative, g, 32),
440            _ => unknown,
441        },
442        _ => unknown,
443    };
444    let target = match reloc.symbol(endian, is_mips64el) {
445        None => RelocationTarget::Absolute,
446        Some(symbol) => RelocationTarget::Symbol(symbol),
447    };
448    Relocation {
449        kind,
450        encoding,
451        size,
452        target,
453        addend: reloc.r_addend(endian).into(),
454        implicit_addend,
455        flags,
456    }
457}
458
459/// A trait for generic access to [`elf::Rel32`] and [`elf::Rel64`].
460#[allow(missing_docs)]
461pub trait Rel: Debug + Pod + Clone {
462    type Word: Into<u64>;
463    type Sword: Into<i64>;
464    type Endian: endian::Endian;
465
466    fn r_offset(&self, endian: Self::Endian) -> Self::Word;
467    fn r_info(&self, endian: Self::Endian) -> Self::Word;
468    fn r_sym(&self, endian: Self::Endian) -> u32;
469    fn r_type(&self, endian: Self::Endian) -> u32;
470
471    /// Get the symbol index referenced by the relocation.
472    ///
473    /// Returns `None` for the null symbol index.
474    fn symbol(&self, endian: Self::Endian) -> Option<SymbolIndex> {
475        let sym = self.r_sym(endian);
476        if sym == 0 {
477            None
478        } else {
479            Some(SymbolIndex(sym as usize))
480        }
481    }
482}
483
484impl<Endian: endian::Endian> Rel for elf::Rel32<Endian> {
485    type Word = u32;
486    type Sword = i32;
487    type Endian = Endian;
488
489    #[inline]
490    fn r_offset(&self, endian: Self::Endian) -> Self::Word {
491        self.r_offset.get(endian)
492    }
493
494    #[inline]
495    fn r_info(&self, endian: Self::Endian) -> Self::Word {
496        self.r_info.get(endian)
497    }
498
499    #[inline]
500    fn r_sym(&self, endian: Self::Endian) -> u32 {
501        self.r_sym(endian)
502    }
503
504    #[inline]
505    fn r_type(&self, endian: Self::Endian) -> u32 {
506        self.r_type(endian)
507    }
508}
509
510impl<Endian: endian::Endian> Rel for elf::Rel64<Endian> {
511    type Word = u64;
512    type Sword = i64;
513    type Endian = Endian;
514
515    #[inline]
516    fn r_offset(&self, endian: Self::Endian) -> Self::Word {
517        self.r_offset.get(endian)
518    }
519
520    #[inline]
521    fn r_info(&self, endian: Self::Endian) -> Self::Word {
522        self.r_info.get(endian)
523    }
524
525    #[inline]
526    fn r_sym(&self, endian: Self::Endian) -> u32 {
527        self.r_sym(endian)
528    }
529
530    #[inline]
531    fn r_type(&self, endian: Self::Endian) -> u32 {
532        self.r_type(endian)
533    }
534}
535
536/// A trait for generic access to [`elf::Rela32`] and [`elf::Rela64`].
537#[allow(missing_docs)]
538pub trait Rela: Debug + Pod + Clone {
539    type Word: Into<u64>;
540    type Sword: Into<i64>;
541    type Endian: endian::Endian;
542
543    fn r_offset(&self, endian: Self::Endian) -> Self::Word;
544    fn r_info(&self, endian: Self::Endian, is_mips64el: bool) -> Self::Word;
545    fn r_addend(&self, endian: Self::Endian) -> Self::Sword;
546    fn r_sym(&self, endian: Self::Endian, is_mips64el: bool) -> u32;
547    fn r_type(&self, endian: Self::Endian, is_mips64el: bool) -> u32;
548
549    /// Get the symbol index referenced by the relocation.
550    ///
551    /// Returns `None` for the null symbol index.
552    fn symbol(&self, endian: Self::Endian, is_mips64el: bool) -> Option<SymbolIndex> {
553        let sym = self.r_sym(endian, is_mips64el);
554        if sym == 0 {
555            None
556        } else {
557            Some(SymbolIndex(sym as usize))
558        }
559    }
560}
561
562impl<Endian: endian::Endian> Rela for elf::Rela32<Endian> {
563    type Word = u32;
564    type Sword = i32;
565    type Endian = Endian;
566
567    #[inline]
568    fn r_offset(&self, endian: Self::Endian) -> Self::Word {
569        self.r_offset.get(endian)
570    }
571
572    #[inline]
573    fn r_info(&self, endian: Self::Endian, _is_mips64el: bool) -> Self::Word {
574        self.r_info.get(endian)
575    }
576
577    #[inline]
578    fn r_addend(&self, endian: Self::Endian) -> Self::Sword {
579        self.r_addend.get(endian)
580    }
581
582    #[inline]
583    fn r_sym(&self, endian: Self::Endian, _is_mips64el: bool) -> u32 {
584        self.r_sym(endian)
585    }
586
587    #[inline]
588    fn r_type(&self, endian: Self::Endian, _is_mips64el: bool) -> u32 {
589        self.r_type(endian)
590    }
591}
592
593impl<Endian: endian::Endian> Rela for elf::Rela64<Endian> {
594    type Word = u64;
595    type Sword = i64;
596    type Endian = Endian;
597
598    #[inline]
599    fn r_offset(&self, endian: Self::Endian) -> Self::Word {
600        self.r_offset.get(endian)
601    }
602
603    #[inline]
604    fn r_info(&self, endian: Self::Endian, is_mips64el: bool) -> Self::Word {
605        self.get_r_info(endian, is_mips64el)
606    }
607
608    #[inline]
609    fn r_addend(&self, endian: Self::Endian) -> Self::Sword {
610        self.r_addend.get(endian)
611    }
612
613    #[inline]
614    fn r_sym(&self, endian: Self::Endian, is_mips64el: bool) -> u32 {
615        self.r_sym(endian, is_mips64el)
616    }
617
618    #[inline]
619    fn r_type(&self, endian: Self::Endian, is_mips64el: bool) -> u32 {
620        self.r_type(endian, is_mips64el)
621    }
622}
623
624/// An iterator over the relative relocations in an ELF `SHT_RELR` section.
625///
626/// Returned by [`SectionHeader::relr`](super::SectionHeader::relr).
627#[derive(Debug)]
628pub struct RelrIterator<'data, Elf: FileHeader> {
629    offset: Elf::Word,
630    bits: Elf::Word,
631    count: u8,
632    iter: slice::Iter<'data, Elf::Relr>,
633    endian: Elf::Endian,
634}
635
636impl<'data, Elf: FileHeader> RelrIterator<'data, Elf> {
637    /// Create a new iterator given the `SHT_RELR` section data.
638    pub fn new(endian: Elf::Endian, data: &'data [Elf::Relr]) -> Self {
639        RelrIterator {
640            offset: Elf::Word::default(),
641            bits: Elf::Word::default(),
642            count: 0,
643            iter: data.iter(),
644            endian,
645        }
646    }
647}
648
649impl<'data, Elf: FileHeader> Iterator for RelrIterator<'data, Elf> {
650    type Item = Elf::Word;
651
652    fn next(&mut self) -> Option<Self::Item> {
653        loop {
654            while self.count > 0 {
655                self.count -= 1;
656                let offset = Elf::Relr::next(&mut self.offset, &mut self.bits);
657                if offset.is_some() {
658                    return offset;
659                }
660            }
661            let next = self.iter.next()?.get(self.endian);
662            if next.into() & 1 == 0 {
663                self.offset = next;
664                return Some(next);
665            }
666            self.bits = next;
667            self.count = Elf::Relr::COUNT;
668        }
669    }
670}
671
672/// A trait for generic access to [`elf::Relr32`] and [`elf::Relr64`].
673#[allow(missing_docs)]
674pub trait Relr: Debug + Pod + Clone {
675    type Word: Into<u64>;
676    type Endian: endian::Endian;
677
678    /// The number of bits in the bit mask, excluding the lowest bit.
679    const COUNT: u8;
680
681    /// Get the relocation entry.
682    ///
683    /// This value is an offset if the lowest bit is clear, or a bit mask if the lowest bit is set.
684    fn get(&self, endian: Self::Endian) -> Self::Word;
685
686    /// Return the offset corresponding to the next bit in the bit mask.
687    ///
688    /// Updates the offset and bit mask. This method should be called 31 times
689    /// for Relr32 and 63 times for Relr64 to iterate over all the bits.
690    ///
691    /// Returns `None` if the bit is not set.
692    fn next(offset: &mut Self::Word, bits: &mut Self::Word) -> Option<Self::Word>;
693}
694
695impl<Endian: endian::Endian> Relr for elf::Relr32<Endian> {
696    type Word = u32;
697    type Endian = Endian;
698    const COUNT: u8 = 31;
699
700    fn get(&self, endian: Self::Endian) -> Self::Word {
701        self.0.get(endian)
702    }
703
704    fn next(offset: &mut Self::Word, bits: &mut Self::Word) -> Option<Self::Word> {
705        *offset += 4;
706        *bits >>= 1;
707        if *bits & 1 != 0 {
708            Some(*offset)
709        } else {
710            None
711        }
712    }
713}
714
715impl<Endian: endian::Endian> Relr for elf::Relr64<Endian> {
716    type Word = u64;
717    type Endian = Endian;
718    const COUNT: u8 = 63;
719
720    fn get(&self, endian: Self::Endian) -> Self::Word {
721        self.0.get(endian)
722    }
723
724    fn next(offset: &mut Self::Word, bits: &mut Self::Word) -> Option<Self::Word> {
725        *offset += 8;
726        *bits >>= 1;
727        if *bits & 1 != 0 {
728            Some(*offset)
729        } else {
730            None
731        }
732    }
733}