Skip to main content

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, Bytes, Error, ReadError, ReadRef, Relocation, RelocationEncoding, RelocationFlags,
11    RelocationKind, 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 || sh_type == elf::SHT_CREL {
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
55                    || sh_info_type == elf::SHT_RELA
56                    || sh_info_type == elf::SHT_CREL
57                {
58                    return Err(Error("Unsupported ELF sh_info for relocation section"));
59                }
60
61                // Handle multiple relocation sections by chaining them.
62                let next = relocations[sh_info.0];
63                relocations[sh_info.0] = index;
64                relocations[index] = next;
65            }
66        }
67        Ok(Self { relocations })
68    }
69
70    /// Given a section index, return the section index of the associated relocation section.
71    ///
72    /// This may also be called with a relocation section index, and it will return the
73    /// next associated relocation section.
74    pub fn get(&self, index: SectionIndex) -> Option<SectionIndex> {
75        self.relocations
76            .get(index.0)
77            .cloned()
78            .filter(|x| *x != 0)
79            .map(SectionIndex)
80    }
81}
82
83pub(super) enum ElfRelocationIterator<'data, Elf: FileHeader> {
84    Rel(slice::Iter<'data, Elf::Rel>, Elf::Endian),
85    Rela(slice::Iter<'data, Elf::Rela>, Elf::Endian, bool),
86    Crel(CrelIterator<'data>),
87}
88
89impl<'data, Elf: FileHeader> ElfRelocationIterator<'data, Elf> {
90    fn is_rel(&self) -> bool {
91        match self {
92            ElfRelocationIterator::Rel(..) => true,
93            ElfRelocationIterator::Rela(..) => false,
94            ElfRelocationIterator::Crel(i) => !i.is_rela(),
95        }
96    }
97}
98
99impl<'data, Elf: FileHeader> Iterator for ElfRelocationIterator<'data, Elf> {
100    type Item = Crel;
101
102    fn next(&mut self) -> Option<Self::Item> {
103        match self {
104            ElfRelocationIterator::Rel(ref mut i, endian) => {
105                i.next().map(|r| Crel::from_rel(r, *endian))
106            }
107            ElfRelocationIterator::Rela(ref mut i, endian, is_mips64el) => {
108                i.next().map(|r| Crel::from_rela(r, *endian, *is_mips64el))
109            }
110            ElfRelocationIterator::Crel(ref mut i) => i.next().and_then(Result::ok),
111        }
112    }
113}
114
115/// An iterator for the dynamic relocations in an [`ElfFile32`](super::ElfFile32).
116pub type ElfDynamicRelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
117    ElfDynamicRelocationIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
118/// An iterator for the dynamic relocations in an [`ElfFile64`](super::ElfFile64).
119pub type ElfDynamicRelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
120    ElfDynamicRelocationIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
121
122/// An iterator for the dynamic relocations in an [`ElfFile`].
123pub struct ElfDynamicRelocationIterator<'data, 'file, Elf, R = &'data [u8]>
124where
125    Elf: FileHeader,
126    R: ReadRef<'data>,
127{
128    /// The current relocation section index.
129    pub(super) section_index: SectionIndex,
130    pub(super) file: &'file ElfFile<'data, Elf, R>,
131    pub(super) relocations: Option<ElfRelocationIterator<'data, Elf>>,
132}
133
134impl<'data, 'file, Elf, R> Iterator for ElfDynamicRelocationIterator<'data, 'file, Elf, R>
135where
136    Elf: FileHeader,
137    R: ReadRef<'data>,
138{
139    type Item = (u64, Relocation);
140
141    fn next(&mut self) -> Option<Self::Item> {
142        let endian = self.file.endian;
143        loop {
144            if let Some(ref mut relocations) = self.relocations {
145                if let Some(reloc) = relocations.next() {
146                    let relocation =
147                        parse_relocation(self.file.header, endian, reloc, relocations.is_rel());
148                    return Some((reloc.r_offset, relocation));
149                }
150                self.relocations = None;
151            }
152
153            let section = self.file.sections.section(self.section_index).ok()?;
154            self.section_index.0 += 1;
155
156            if section.link(endian) != self.file.dynamic_symbols.section() {
157                continue;
158            }
159
160            match section.sh_type(endian) {
161                elf::SHT_REL => {
162                    if let Ok(relocations) = section.data_as_array(endian, self.file.data.0) {
163                        self.relocations =
164                            Some(ElfRelocationIterator::Rel(relocations.iter(), endian));
165                    }
166                }
167                elf::SHT_RELA => {
168                    if let Ok(relocations) = section.data_as_array(endian, self.file.data.0) {
169                        self.relocations = Some(ElfRelocationIterator::Rela(
170                            relocations.iter(),
171                            endian,
172                            self.file.header.is_mips64el(endian),
173                        ));
174                    }
175                }
176                elf::SHT_CREL => {
177                    if let Ok(data) = section.data(endian, self.file.data.0) {
178                        if let Ok(relocations) = CrelIterator::new(data) {
179                            self.relocations = Some(ElfRelocationIterator::Crel(relocations));
180                        }
181                    }
182                }
183                _ => {}
184            }
185        }
186    }
187}
188
189impl<'data, 'file, Elf, R> fmt::Debug for ElfDynamicRelocationIterator<'data, 'file, Elf, R>
190where
191    Elf: FileHeader,
192    R: ReadRef<'data>,
193{
194    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195        f.debug_struct("ElfDynamicRelocationIterator").finish()
196    }
197}
198
199/// An iterator for the relocations for an [`ElfSection32`](super::ElfSection32).
200pub type ElfSectionRelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
201    ElfSectionRelocationIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
202/// An iterator for the relocations for an [`ElfSection64`](super::ElfSection64).
203pub type ElfSectionRelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
204    ElfSectionRelocationIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
205
206/// An iterator for the relocations for an [`ElfSection`](super::ElfSection).
207pub struct ElfSectionRelocationIterator<'data, 'file, Elf, R = &'data [u8]>
208where
209    Elf: FileHeader,
210    R: ReadRef<'data>,
211{
212    /// The current pointer in the chain of relocation sections.
213    pub(super) section_index: SectionIndex,
214    pub(super) file: &'file ElfFile<'data, Elf, R>,
215    pub(super) relocations: Option<ElfRelocationIterator<'data, Elf>>,
216}
217
218impl<'data, 'file, Elf, R> Iterator for ElfSectionRelocationIterator<'data, 'file, Elf, R>
219where
220    Elf: FileHeader,
221    R: ReadRef<'data>,
222{
223    type Item = (u64, Relocation);
224
225    fn next(&mut self) -> Option<Self::Item> {
226        let endian = self.file.endian;
227        loop {
228            if let Some(ref mut relocations) = self.relocations {
229                if let Some(reloc) = relocations.next() {
230                    let relocation =
231                        parse_relocation(self.file.header, endian, reloc, relocations.is_rel());
232                    return Some((reloc.r_offset, relocation));
233                }
234                self.relocations = None;
235            }
236            self.section_index = self.file.relocations.get(self.section_index)?;
237            // The construction of RelocationSections ensures section_index is valid.
238            let section = self.file.sections.section(self.section_index).unwrap();
239            match section.sh_type(endian) {
240                elf::SHT_REL => {
241                    if let Ok(relocations) = section.data_as_array(endian, self.file.data.0) {
242                        self.relocations =
243                            Some(ElfRelocationIterator::Rel(relocations.iter(), endian));
244                    }
245                }
246                elf::SHT_RELA => {
247                    if let Ok(relocations) = section.data_as_array(endian, self.file.data.0) {
248                        self.relocations = Some(ElfRelocationIterator::Rela(
249                            relocations.iter(),
250                            endian,
251                            self.file.header.is_mips64el(endian),
252                        ));
253                    }
254                }
255                elf::SHT_CREL => {
256                    if let Ok(data) = section.data(endian, self.file.data.0) {
257                        if let Ok(relocations) = CrelIterator::new(data) {
258                            self.relocations = Some(ElfRelocationIterator::Crel(relocations));
259                        }
260                    }
261                }
262                _ => {}
263            }
264        }
265    }
266}
267
268impl<'data, 'file, Elf, R> fmt::Debug for ElfSectionRelocationIterator<'data, 'file, Elf, R>
269where
270    Elf: FileHeader,
271    R: ReadRef<'data>,
272{
273    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274        f.debug_struct("ElfSectionRelocationIterator").finish()
275    }
276}
277
278fn parse_relocation<Elf: FileHeader>(
279    header: &Elf,
280    endian: Elf::Endian,
281    reloc: Crel,
282    implicit_addend: bool,
283) -> Relocation {
284    use RelocationEncoding as E;
285    use RelocationKind as K;
286
287    let r_type = reloc.r_type;
288    let flags = RelocationFlags::Elf { r_type };
289    let g = E::Generic;
290    let unknown = (K::Unknown, E::Unknown, 0);
291    let (kind, encoding, size) = match header.e_machine(endian) {
292        elf::EM_AARCH64 => {
293            if header.is_type_64() {
294                match r_type {
295                    elf::R_AARCH64_NONE => (K::None, g, 0),
296                    elf::R_AARCH64_ABS64 => (K::Absolute, g, 64),
297                    elf::R_AARCH64_ABS32 => (K::Absolute, g, 32),
298                    elf::R_AARCH64_ABS16 => (K::Absolute, g, 16),
299                    elf::R_AARCH64_PREL64 => (K::Relative, g, 64),
300                    elf::R_AARCH64_PREL32 => (K::Relative, g, 32),
301                    elf::R_AARCH64_PREL16 => (K::Relative, g, 16),
302                    elf::R_AARCH64_CALL26 => (K::PltRelative, E::AArch64Call, 26),
303                    _ => unknown,
304                }
305            } else {
306                match r_type {
307                    elf::R_AARCH64_NONE => (K::None, g, 0),
308                    elf::R_AARCH64_P32_ABS32 => (K::Absolute, g, 32),
309                    _ => unknown,
310                }
311            }
312        }
313        elf::EM_ALPHA => match r_type {
314            elf::R_ALPHA_NONE => (K::None, g, 0),
315            // Absolute
316            elf::R_ALPHA_REFLONG => (K::Absolute, g, 32),
317            elf::R_ALPHA_REFQUAD => (K::Absolute, g, 64),
318            // Relative to the PC
319            elf::R_ALPHA_SREL16 => (K::Relative, g, 16),
320            elf::R_ALPHA_SREL32 => (K::Relative, g, 32),
321            elf::R_ALPHA_SREL64 => (K::Relative, g, 64),
322            _ => unknown,
323        },
324        elf::EM_ARM => match r_type {
325            elf::R_ARM_NONE => (K::None, g, 0),
326            elf::R_ARM_ABS32 => (K::Absolute, g, 32),
327            _ => unknown,
328        },
329        elf::EM_AVR => match r_type {
330            elf::R_AVR_NONE => (K::None, g, 0),
331            elf::R_AVR_32 => (K::Absolute, g, 32),
332            elf::R_AVR_16 => (K::Absolute, g, 16),
333            _ => unknown,
334        },
335        elf::EM_BPF => match r_type {
336            elf::R_BPF_NONE => (K::None, g, 0),
337            elf::R_BPF_64_64 => (K::Absolute, g, 64),
338            elf::R_BPF_64_32 => (K::Absolute, g, 32),
339            _ => unknown,
340        },
341        elf::EM_CSKY => match r_type {
342            elf::R_CKCORE_NONE => (K::None, g, 0),
343            elf::R_CKCORE_ADDR32 => (K::Absolute, g, 32),
344            elf::R_CKCORE_PCREL32 => (K::Relative, g, 32),
345            _ => unknown,
346        },
347        elf::EM_MCST_ELBRUS => match r_type {
348            elf::R_E2K_NONE => (K::None, g, 0),
349            elf::R_E2K_32_ABS => (K::Absolute, g, 32),
350            elf::R_E2K_64_ABS => (K::Absolute, g, 64),
351            elf::R_E2K_64_ABS_LIT => (K::Absolute, E::E2KLit, 64),
352            elf::R_E2K_DISP => (K::Relative, E::E2KDisp, 28),
353            elf::R_E2K_GOT => (K::Got, g, 32),
354            _ => unknown,
355        },
356        elf::EM_386 => match r_type {
357            elf::R_386_NONE => (K::None, g, 0),
358            elf::R_386_32 => (K::Absolute, g, 32),
359            elf::R_386_PC32 => (K::Relative, g, 32),
360            elf::R_386_GOT32 => (K::Got, g, 32),
361            elf::R_386_PLT32 => (K::PltRelative, g, 32),
362            elf::R_386_GOTOFF => (K::GotBaseOffset, g, 32),
363            elf::R_386_GOTPC => (K::GotBaseRelative, g, 32),
364            elf::R_386_16 => (K::Absolute, g, 16),
365            elf::R_386_PC16 => (K::Relative, g, 16),
366            elf::R_386_8 => (K::Absolute, g, 8),
367            elf::R_386_PC8 => (K::Relative, g, 8),
368            _ => unknown,
369        },
370        elf::EM_X86_64 => match r_type {
371            elf::R_X86_64_NONE => (K::None, g, 0),
372            elf::R_X86_64_64 => (K::Absolute, g, 64),
373            elf::R_X86_64_PC32 => (K::Relative, g, 32),
374            elf::R_X86_64_GOT32 => (K::Got, g, 32),
375            elf::R_X86_64_PLT32 => (K::PltRelative, E::X86Branch, 32),
376            elf::R_X86_64_GOTPCREL => (K::GotRelative, g, 32),
377            elf::R_X86_64_GOTPCRELX => (K::GotRelative, E::Unknown, 32),
378            elf::R_X86_64_REX_GOTPCRELX => (K::GotRelative, E::Unknown, 32),
379            elf::R_X86_64_32 => (K::Absolute, g, 32),
380            elf::R_X86_64_32S => (K::Absolute, E::X86Signed, 32),
381            elf::R_X86_64_16 => (K::Absolute, g, 16),
382            elf::R_X86_64_PC16 => (K::Relative, g, 16),
383            elf::R_X86_64_8 => (K::Absolute, g, 8),
384            elf::R_X86_64_PC8 => (K::Relative, g, 8),
385            _ => unknown,
386        },
387        elf::EM_HEXAGON => match r_type {
388            elf::R_HEX_NONE => (K::None, g, 0),
389            elf::R_HEX_32 => (K::Absolute, g, 32),
390            _ => unknown,
391        },
392        elf::EM_LOONGARCH => match r_type {
393            elf::R_LARCH_NONE => (K::None, g, 0),
394            elf::R_LARCH_32 => (K::Absolute, g, 32),
395            elf::R_LARCH_64 => (K::Absolute, g, 64),
396            elf::R_LARCH_32_PCREL => (K::Relative, g, 32),
397            elf::R_LARCH_64_PCREL => (K::Relative, g, 64),
398            elf::R_LARCH_B16 => (K::Relative, E::LoongArchBranch, 16),
399            elf::R_LARCH_B21 => (K::Relative, E::LoongArchBranch, 21),
400            elf::R_LARCH_B26 => (K::Relative, E::LoongArchBranch, 26),
401            _ => unknown,
402        },
403        elf::EM_68K => match r_type {
404            elf::R_68K_NONE => (K::None, g, 0),
405            elf::R_68K_32 => (K::Absolute, g, 32),
406            elf::R_68K_16 => (K::Absolute, g, 16),
407            elf::R_68K_8 => (K::Absolute, g, 8),
408            elf::R_68K_PC32 => (K::Relative, g, 32),
409            elf::R_68K_PC16 => (K::Relative, g, 16),
410            elf::R_68K_PC8 => (K::Relative, g, 8),
411            elf::R_68K_GOT32O => (K::Got, g, 32),
412            elf::R_68K_GOT16O => (K::Got, g, 16),
413            elf::R_68K_GOT8O => (K::Got, g, 8),
414            elf::R_68K_GOT32 => (K::GotRelative, g, 32),
415            elf::R_68K_GOT16 => (K::GotRelative, g, 16),
416            elf::R_68K_GOT8 => (K::GotRelative, g, 8),
417            elf::R_68K_PLT32 => (K::PltRelative, g, 32),
418            elf::R_68K_PLT16 => (K::PltRelative, g, 16),
419            elf::R_68K_PLT8 => (K::PltRelative, g, 8),
420            _ => unknown,
421        },
422        elf::EM_MIPS => match r_type {
423            elf::R_MIPS_NONE => (K::None, g, 0),
424            elf::R_MIPS_16 => (K::Absolute, g, 16),
425            elf::R_MIPS_32 => (K::Absolute, g, 32),
426            elf::R_MIPS_64 => (K::Absolute, g, 64),
427            _ => unknown,
428        },
429        elf::EM_MSP430 => match r_type {
430            elf::R_MSP430_NONE => (K::None, g, 0),
431            elf::R_MSP430_32 => (K::Absolute, g, 32),
432            elf::R_MSP430_16_BYTE => (K::Absolute, g, 16),
433            _ => unknown,
434        },
435        elf::EM_PARISC => match r_type {
436            elf::R_PARISC_NONE => (K::None, g, 0),
437            elf::R_PARISC_DIR32 => (K::Absolute, g, 32),
438            elf::R_PARISC_PCREL32 => (K::Relative, g, 32),
439            _ => unknown,
440        },
441        elf::EM_PPC => match r_type {
442            elf::R_PPC_NONE => (K::None, g, 0),
443            elf::R_PPC_ADDR32 => (K::Absolute, g, 32),
444            _ => unknown,
445        },
446        elf::EM_PPC64 => match r_type {
447            elf::R_PPC64_NONE => (K::None, g, 0),
448            elf::R_PPC64_ADDR32 => (K::Absolute, g, 32),
449            elf::R_PPC64_ADDR64 => (K::Absolute, g, 64),
450            _ => unknown,
451        },
452        elf::EM_RISCV => match r_type {
453            elf::R_RISCV_NONE => (K::None, g, 0),
454            elf::R_RISCV_32 => (K::Absolute, g, 32),
455            elf::R_RISCV_64 => (K::Absolute, g, 64),
456            _ => unknown,
457        },
458        elf::EM_S390 => match r_type {
459            elf::R_390_NONE => (K::None, g, 0),
460            elf::R_390_8 => (K::Absolute, g, 8),
461            elf::R_390_16 => (K::Absolute, g, 16),
462            elf::R_390_32 => (K::Absolute, g, 32),
463            elf::R_390_64 => (K::Absolute, g, 64),
464            elf::R_390_PC16 => (K::Relative, g, 16),
465            elf::R_390_PC32 => (K::Relative, g, 32),
466            elf::R_390_PC64 => (K::Relative, g, 64),
467            elf::R_390_PC16DBL => (K::Relative, E::S390xDbl, 16),
468            elf::R_390_PC32DBL => (K::Relative, E::S390xDbl, 32),
469            elf::R_390_PLT16DBL => (K::PltRelative, E::S390xDbl, 16),
470            elf::R_390_PLT32DBL => (K::PltRelative, E::S390xDbl, 32),
471            elf::R_390_GOT16 => (K::Got, g, 16),
472            elf::R_390_GOT32 => (K::Got, g, 32),
473            elf::R_390_GOT64 => (K::Got, g, 64),
474            elf::R_390_GOTENT => (K::GotRelative, E::S390xDbl, 32),
475            elf::R_390_GOTOFF16 => (K::GotBaseOffset, g, 16),
476            elf::R_390_GOTOFF32 => (K::GotBaseOffset, g, 32),
477            elf::R_390_GOTOFF64 => (K::GotBaseOffset, g, 64),
478            elf::R_390_GOTPC => (K::GotBaseRelative, g, 64),
479            elf::R_390_GOTPCDBL => (K::GotBaseRelative, E::S390xDbl, 32),
480            _ => unknown,
481        },
482        elf::EM_SBF => match r_type {
483            elf::R_SBF_NONE => (K::None, g, 0),
484            elf::R_SBF_64_64 => (K::Absolute, g, 64),
485            elf::R_SBF_64_32 => (K::Absolute, g, 32),
486            _ => unknown,
487        },
488        elf::EM_SHARC => match r_type {
489            elf::R_SHARC_ADDR24_V3 => (K::Absolute, E::SharcTypeA, 24),
490            elf::R_SHARC_ADDR32_V3 => (K::Absolute, E::SharcTypeA, 32),
491            elf::R_SHARC_ADDR_VAR_V3 => (K::Absolute, E::Generic, 32),
492            elf::R_SHARC_PCRSHORT_V3 => (K::Relative, E::SharcTypeA, 6),
493            elf::R_SHARC_PCRLONG_V3 => (K::Relative, E::SharcTypeA, 24),
494            elf::R_SHARC_DATA6_V3 => (K::Absolute, E::SharcTypeA, 6),
495            elf::R_SHARC_DATA16_V3 => (K::Absolute, E::SharcTypeA, 16),
496            elf::R_SHARC_DATA6_VISA_V3 => (K::Absolute, E::SharcTypeB, 6),
497            elf::R_SHARC_DATA7_VISA_V3 => (K::Absolute, E::SharcTypeB, 7),
498            elf::R_SHARC_DATA16_VISA_V3 => (K::Absolute, E::SharcTypeB, 16),
499            elf::R_SHARC_PCR6_VISA_V3 => (K::Relative, E::SharcTypeB, 16),
500            elf::R_SHARC_ADDR_VAR16_V3 => (K::Absolute, E::Generic, 16),
501            _ => unknown,
502        },
503        elf::EM_SPARC | elf::EM_SPARC32PLUS | elf::EM_SPARCV9 => match r_type {
504            elf::R_SPARC_NONE => (K::None, g, 0),
505            elf::R_SPARC_32 | elf::R_SPARC_UA32 => (K::Absolute, g, 32),
506            elf::R_SPARC_64 | elf::R_SPARC_UA64 => (K::Absolute, g, 64),
507            _ => unknown,
508        },
509        elf::EM_SH => match r_type {
510            elf::R_SH_NONE => (K::None, g, 0),
511            elf::R_SH_DIR32 => (K::Absolute, g, 32),
512            elf::R_SH_REL32 => (K::Relative, g, 32),
513            _ => unknown,
514        },
515        elf::EM_XTENSA => match r_type {
516            elf::R_XTENSA_NONE => (K::None, g, 0),
517            elf::R_XTENSA_32 => (K::Absolute, g, 32),
518            elf::R_XTENSA_32_PCREL => (K::Relative, g, 32),
519            _ => unknown,
520        },
521        _ => unknown,
522    };
523    let target = match reloc.symbol() {
524        None => RelocationTarget::Absolute,
525        Some(symbol) => RelocationTarget::Symbol(symbol),
526    };
527    Relocation {
528        kind,
529        encoding,
530        size,
531        target,
532        subtractor: None,
533        addend: reloc.r_addend,
534        implicit_addend,
535        flags,
536    }
537}
538
539/// A trait for generic access to [`elf::Rel32`] and [`elf::Rel64`].
540#[allow(missing_docs)]
541pub trait Rel: Debug + Pod + Clone {
542    type Word: Into<u64>;
543    type Sword: Into<i64>;
544    type Endian: endian::Endian;
545
546    fn r_offset(&self, endian: Self::Endian) -> Self::Word;
547    fn r_info(&self, endian: Self::Endian) -> Self::Word;
548    fn r_sym(&self, endian: Self::Endian) -> u32;
549    fn r_type(&self, endian: Self::Endian) -> u32;
550
551    /// Get the symbol index referenced by the relocation.
552    ///
553    /// Returns `None` for the null symbol index.
554    fn symbol(&self, endian: Self::Endian) -> Option<SymbolIndex> {
555        let sym = self.r_sym(endian);
556        if sym == 0 {
557            None
558        } else {
559            Some(SymbolIndex(sym as usize))
560        }
561    }
562}
563
564impl<Endian: endian::Endian> Rel for elf::Rel32<Endian> {
565    type Word = u32;
566    type Sword = i32;
567    type Endian = Endian;
568
569    #[inline]
570    fn r_offset(&self, endian: Self::Endian) -> Self::Word {
571        self.r_offset.get(endian)
572    }
573
574    #[inline]
575    fn r_info(&self, endian: Self::Endian) -> Self::Word {
576        self.r_info.get(endian)
577    }
578
579    #[inline]
580    fn r_sym(&self, endian: Self::Endian) -> u32 {
581        self.r_sym(endian)
582    }
583
584    #[inline]
585    fn r_type(&self, endian: Self::Endian) -> u32 {
586        self.r_type(endian)
587    }
588}
589
590impl<Endian: endian::Endian> Rel for elf::Rel64<Endian> {
591    type Word = u64;
592    type Sword = i64;
593    type Endian = Endian;
594
595    #[inline]
596    fn r_offset(&self, endian: Self::Endian) -> Self::Word {
597        self.r_offset.get(endian)
598    }
599
600    #[inline]
601    fn r_info(&self, endian: Self::Endian) -> Self::Word {
602        self.r_info.get(endian)
603    }
604
605    #[inline]
606    fn r_sym(&self, endian: Self::Endian) -> u32 {
607        self.r_sym(endian)
608    }
609
610    #[inline]
611    fn r_type(&self, endian: Self::Endian) -> u32 {
612        self.r_type(endian)
613    }
614}
615
616/// A trait for generic access to [`elf::Rela32`] and [`elf::Rela64`].
617#[allow(missing_docs)]
618pub trait Rela: Debug + Pod + Clone {
619    type Word: Into<u64>;
620    type Sword: Into<i64>;
621    type Endian: endian::Endian;
622
623    fn r_offset(&self, endian: Self::Endian) -> Self::Word;
624    fn r_info(&self, endian: Self::Endian, is_mips64el: bool) -> Self::Word;
625    fn r_addend(&self, endian: Self::Endian) -> Self::Sword;
626    fn r_sym(&self, endian: Self::Endian, is_mips64el: bool) -> u32;
627    fn r_type(&self, endian: Self::Endian, is_mips64el: bool) -> u32;
628
629    /// Get the symbol index referenced by the relocation.
630    ///
631    /// Returns `None` for the null symbol index.
632    fn symbol(&self, endian: Self::Endian, is_mips64el: bool) -> Option<SymbolIndex> {
633        let sym = self.r_sym(endian, is_mips64el);
634        if sym == 0 {
635            None
636        } else {
637            Some(SymbolIndex(sym as usize))
638        }
639    }
640}
641
642impl<Endian: endian::Endian> Rela for elf::Rela32<Endian> {
643    type Word = u32;
644    type Sword = i32;
645    type Endian = Endian;
646
647    #[inline]
648    fn r_offset(&self, endian: Self::Endian) -> Self::Word {
649        self.r_offset.get(endian)
650    }
651
652    #[inline]
653    fn r_info(&self, endian: Self::Endian, _is_mips64el: bool) -> Self::Word {
654        self.r_info.get(endian)
655    }
656
657    #[inline]
658    fn r_addend(&self, endian: Self::Endian) -> Self::Sword {
659        self.r_addend.get(endian)
660    }
661
662    #[inline]
663    fn r_sym(&self, endian: Self::Endian, _is_mips64el: bool) -> u32 {
664        self.r_sym(endian)
665    }
666
667    #[inline]
668    fn r_type(&self, endian: Self::Endian, _is_mips64el: bool) -> u32 {
669        self.r_type(endian)
670    }
671}
672
673impl<Endian: endian::Endian> Rela for elf::Rela64<Endian> {
674    type Word = u64;
675    type Sword = i64;
676    type Endian = Endian;
677
678    #[inline]
679    fn r_offset(&self, endian: Self::Endian) -> Self::Word {
680        self.r_offset.get(endian)
681    }
682
683    #[inline]
684    fn r_info(&self, endian: Self::Endian, is_mips64el: bool) -> Self::Word {
685        self.get_r_info(endian, is_mips64el)
686    }
687
688    #[inline]
689    fn r_addend(&self, endian: Self::Endian) -> Self::Sword {
690        self.r_addend.get(endian)
691    }
692
693    #[inline]
694    fn r_sym(&self, endian: Self::Endian, is_mips64el: bool) -> u32 {
695        self.r_sym(endian, is_mips64el)
696    }
697
698    #[inline]
699    fn r_type(&self, endian: Self::Endian, is_mips64el: bool) -> u32 {
700        self.r_type(endian, is_mips64el)
701    }
702}
703
704/// An iterator over the relative relocations in an ELF `SHT_RELR` section.
705///
706/// Returned by [`SectionHeader::relr`](super::SectionHeader::relr).
707#[derive(Debug)]
708pub struct RelrIterator<'data, Elf: FileHeader> {
709    offset: Elf::Word,
710    bits: Elf::Word,
711    count: u8,
712    iter: slice::Iter<'data, Elf::Relr>,
713    endian: Elf::Endian,
714}
715
716impl<'data, Elf: FileHeader> RelrIterator<'data, Elf> {
717    /// Create a new iterator given the `SHT_RELR` section data.
718    pub fn new(endian: Elf::Endian, data: &'data [Elf::Relr]) -> Self {
719        RelrIterator {
720            offset: Elf::Word::default(),
721            bits: Elf::Word::default(),
722            count: 0,
723            iter: data.iter(),
724            endian,
725        }
726    }
727}
728
729impl<'data, Elf: FileHeader> Iterator for RelrIterator<'data, Elf> {
730    type Item = Elf::Word;
731
732    fn next(&mut self) -> Option<Self::Item> {
733        loop {
734            while self.count > 0 {
735                self.count -= 1;
736                let offset = Elf::Relr::next(&mut self.offset, &mut self.bits);
737                if offset.is_some() {
738                    return offset;
739                }
740            }
741            let next = self.iter.next()?.get(self.endian);
742            if next.into() & 1 == 0 {
743                self.offset = next;
744                return Some(next);
745            }
746            self.bits = next;
747            self.count = Elf::Relr::COUNT;
748        }
749    }
750}
751
752/// A trait for generic access to [`elf::Relr32`] and [`elf::Relr64`].
753#[allow(missing_docs)]
754pub trait Relr: Debug + Pod + Clone {
755    type Word: Into<u64>;
756    type Endian: endian::Endian;
757
758    /// The number of bits in the bit mask, excluding the lowest bit.
759    const COUNT: u8;
760
761    /// Get the relocation entry.
762    ///
763    /// This value is an offset if the lowest bit is clear, or a bit mask if the lowest bit is set.
764    fn get(&self, endian: Self::Endian) -> Self::Word;
765
766    /// Return the offset corresponding to the next bit in the bit mask.
767    ///
768    /// Updates the offset and bit mask. This method should be called 31 times
769    /// for Relr32 and 63 times for Relr64 to iterate over all the bits.
770    ///
771    /// Returns `None` if the bit is not set.
772    fn next(offset: &mut Self::Word, bits: &mut Self::Word) -> Option<Self::Word>;
773}
774
775impl<Endian: endian::Endian> Relr for elf::Relr32<Endian> {
776    type Word = u32;
777    type Endian = Endian;
778    const COUNT: u8 = 31;
779
780    fn get(&self, endian: Self::Endian) -> Self::Word {
781        self.0.get(endian)
782    }
783
784    fn next(offset: &mut Self::Word, bits: &mut Self::Word) -> Option<Self::Word> {
785        *offset += 4;
786        *bits >>= 1;
787        if *bits & 1 != 0 {
788            Some(*offset)
789        } else {
790            None
791        }
792    }
793}
794
795impl<Endian: endian::Endian> Relr for elf::Relr64<Endian> {
796    type Word = u64;
797    type Endian = Endian;
798    const COUNT: u8 = 63;
799
800    fn get(&self, endian: Self::Endian) -> Self::Word {
801        self.0.get(endian)
802    }
803
804    fn next(offset: &mut Self::Word, bits: &mut Self::Word) -> Option<Self::Word> {
805        *offset += 8;
806        *bits >>= 1;
807        if *bits & 1 != 0 {
808            Some(*offset)
809        } else {
810            None
811        }
812    }
813}
814
815/// Compact relocation
816///
817/// The specification has been submited here: <https://groups.google.com/g/generic-abi/c/ppkaxtLb0P0/m/awgqZ_1CBAAJ>.
818#[derive(Debug, Clone, Copy, Default)]
819pub struct Crel {
820    /// Relocation offset.
821    pub r_offset: u64,
822    /// Relocation symbol index.
823    pub r_sym: u32,
824    /// Relocation type.
825    pub r_type: u32,
826    /// Relocation addend.
827    ///
828    /// Only set if `CrelIterator::is_rela()` returns `true`.
829    pub r_addend: i64,
830}
831
832impl Crel {
833    /// Get the symbol index referenced by the relocation.
834    ///
835    /// Returns `None` for the null symbol index.
836    pub fn symbol(&self) -> Option<SymbolIndex> {
837        if self.r_sym == 0 {
838            None
839        } else {
840            Some(SymbolIndex(self.r_sym as usize))
841        }
842    }
843
844    /// Build Crel type from Rel.
845    pub fn from_rel<R: Rel>(r: &R, endian: R::Endian) -> Crel {
846        Crel {
847            r_offset: r.r_offset(endian).into(),
848            r_sym: r.r_sym(endian),
849            r_type: r.r_type(endian),
850            r_addend: 0,
851        }
852    }
853
854    /// Build Crel type from Rela.
855    pub fn from_rela<R: Rela>(r: &R, endian: R::Endian, is_mips64el: bool) -> Crel {
856        Crel {
857            r_offset: r.r_offset(endian).into(),
858            r_sym: r.r_sym(endian, is_mips64el),
859            r_type: r.r_type(endian, is_mips64el),
860            r_addend: r.r_addend(endian).into(),
861        }
862    }
863}
864
865#[derive(Debug, Clone)]
866struct CrelIteratorHeader {
867    /// The number of remaining encoded relocations.
868    count: usize,
869    /// The number of flag bits each relocation uses.
870    flag_bits: u8,
871    /// Shift of the relocation value.
872    shift: u8,
873    /// True if the relocation format encodes addend.
874    is_rela: bool,
875}
876
877/// Compact relocation iterator.
878#[derive(Debug, Clone)]
879pub struct CrelIterator<'data> {
880    /// Input stream reader.
881    data: Bytes<'data>,
882    /// Parsed header information.
883    header: CrelIteratorHeader,
884    /// State of the iterator.
885    state: Crel,
886}
887
888impl<'data> CrelIterator<'data> {
889    /// Create a new CREL relocation iterator.
890    pub fn new(data: &'data [u8]) -> Result<Self, Error> {
891        const HEADER_ADDEND_BIT_MASK: u64 = 1 << 2;
892        const HEADER_SHIFT_MASK: u64 = 0x3;
893
894        let mut data = Bytes(data);
895        let header = data.read_uleb128().read_error("Invalid ELF CREL header")?;
896        let count = header >> 3;
897        let flag_bits = if header & HEADER_ADDEND_BIT_MASK != 0 {
898            3
899        } else {
900            2
901        };
902        let shift = (header & HEADER_SHIFT_MASK) as u8;
903        let is_rela = header & HEADER_ADDEND_BIT_MASK != 0;
904
905        Ok(CrelIterator {
906            data,
907            header: CrelIteratorHeader {
908                count: count as usize,
909                flag_bits,
910                shift,
911                is_rela,
912            },
913            state: Default::default(),
914        })
915    }
916
917    /// True if the encoded relocations have addend.
918    pub fn is_rela(&self) -> bool {
919        self.header.is_rela
920    }
921
922    /// Return the number of remaining encoded relocations.
923    pub fn len(&self) -> usize {
924        self.header.count
925    }
926
927    /// Return true if there are no more relocations to parse.
928    pub fn is_empty(&self) -> bool {
929        self.header.count == 0
930    }
931
932    fn parse(&mut self) -> read::Result<Crel> {
933        const DELTA_SYMBOL_INDEX_MASK: u8 = 1 << 0;
934        const DELTA_TYPE_MASK: u8 = 1 << 1;
935        const DELTA_ADDEND_MASK: u8 = 1 << 2;
936
937        // The delta offset and flags combined may be larger than u64,
938        // so we handle the first byte separately.
939        let byte = *self
940            .data
941            .read::<u8>()
942            .read_error("Cannot read offset and flags of CREL relocation")?;
943        let flags = byte & ((1 << self.header.flag_bits) - 1);
944
945        let mut delta_offset = u64::from(byte & 0x7f) >> self.header.flag_bits;
946        if byte & 0x80 != 0 {
947            delta_offset |= self
948                .data
949                .read_uleb128()
950                .read_error("Cannot read offset and flags of CREL relocation")?
951                << (7 - self.header.flag_bits);
952        }
953        self.state.r_offset = self
954            .state
955            .r_offset
956            .wrapping_add(delta_offset << self.header.shift);
957
958        if flags & DELTA_SYMBOL_INDEX_MASK != 0 {
959            let delta_symidx = self
960                .data
961                .read_sleb128()
962                .read_error("Cannot read symidx of CREL relocation")?;
963            self.state.r_sym = self.state.r_sym.wrapping_add(delta_symidx as u32);
964        }
965        if flags & DELTA_TYPE_MASK != 0 {
966            let delta_typ = self
967                .data
968                .read_sleb128()
969                .read_error("Cannot read type of CREL relocation")?;
970            self.state.r_type = self.state.r_type.wrapping_add(delta_typ as u32);
971        }
972        if self.header.is_rela && flags & DELTA_ADDEND_MASK != 0 {
973            let delta_addend = self
974                .data
975                .read_sleb128()
976                .read_error("Cannot read addend of CREL relocation")?;
977            self.state.r_addend = self.state.r_addend.wrapping_add(delta_addend);
978        }
979        self.header.count -= 1;
980        Ok(self.state)
981    }
982}
983
984impl<'data> Iterator for CrelIterator<'data> {
985    type Item = read::Result<Crel>;
986
987    fn next(&mut self) -> Option<Self::Item> {
988        if self.is_empty() {
989            return None;
990        }
991
992        let result = self.parse();
993        if result.is_err() {
994            self.header.count = 0;
995        }
996        Some(result)
997    }
998
999    fn size_hint(&self) -> (usize, Option<usize>) {
1000        (self.len(), Some(self.len()))
1001    }
1002}