1 | use alloc::fmt; |
2 | use alloc::vec::Vec; |
3 | use core::fmt::Debug; |
4 | use core::slice; |
5 | |
6 | use crate::elf; |
7 | use crate::endian::{self, Endianness}; |
8 | use crate::pod::Pod; |
9 | use crate::read::{ |
10 | self, Error, ReadRef, Relocation, RelocationEncoding, RelocationFlags, RelocationKind, |
11 | RelocationTarget, SectionIndex, SymbolIndex, |
12 | }; |
13 | |
14 | use super::{ElfFile, FileHeader, SectionHeader, SectionTable}; |
15 | |
16 | /// A mapping from section index to associated relocation sections. |
17 | #[derive (Debug, Default)] |
18 | pub struct RelocationSections { |
19 | relocations: Vec<usize>, |
20 | } |
21 | |
22 | impl 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 | |
80 | pub(super) enum ElfRelaIterator<'data, Elf: FileHeader> { |
81 | Rel(slice::Iter<'data, Elf::Rel>), |
82 | Rela(slice::Iter<'data, Elf::Rela>), |
83 | } |
84 | |
85 | impl<'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 | |
94 | impl<'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: &mut Iter<'_, ::Rel>) => i.next().cloned().map(Self::Item::from), |
100 | ElfRelaIterator::Rela(ref mut i: &mut Iter<'_, ::Rela>) => i.next().cloned(), |
101 | } |
102 | } |
103 | } |
104 | |
105 | /// An iterator for the dynamic relocations in an [`ElfFile32`](super::ElfFile32). |
106 | pub 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). |
109 | pub 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`]. |
113 | pub struct ElfDynamicRelocationIterator<'data, 'file, Elf, R = &'data [u8]> |
114 | where |
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 | |
124 | impl<'data, 'file, Elf, R> Iterator for ElfDynamicRelocationIterator<'data, 'file, Elf, R> |
125 | where |
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 | |
167 | impl<'data, 'file, Elf, R> fmt::Debug for ElfDynamicRelocationIterator<'data, 'file, Elf, R> |
168 | where |
169 | Elf: FileHeader, |
170 | R: ReadRef<'data>, |
171 | { |
172 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
173 | f.debug_struct(name:"ElfDynamicRelocationIterator" ).finish() |
174 | } |
175 | } |
176 | |
177 | /// An iterator for the relocations for an [`ElfSection32`](super::ElfSection32). |
178 | pub 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). |
181 | pub 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). |
185 | pub struct ElfSectionRelocationIterator<'data, 'file, Elf, R = &'data [u8]> |
186 | where |
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 | |
196 | impl<'data, 'file, Elf, R> Iterator for ElfSectionRelocationIterator<'data, 'file, Elf, R> |
197 | where |
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 | |
234 | impl<'data, 'file, Elf, R> fmt::Debug for ElfSectionRelocationIterator<'data, 'file, Elf, R> |
235 | where |
236 | Elf: FileHeader, |
237 | R: ReadRef<'data>, |
238 | { |
239 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
240 | f.debug_struct(name:"ElfSectionRelocationIterator" ).finish() |
241 | } |
242 | } |
243 | |
244 | fn 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)] |
461 | pub 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: u32 = self.r_sym(endian); |
476 | if sym == 0 { |
477 | None |
478 | } else { |
479 | Some(SymbolIndex(sym as usize)) |
480 | } |
481 | } |
482 | } |
483 | |
484 | impl<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 | |
510 | impl<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)] |
538 | pub 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: u32 = self.r_sym(endian, is_mips64el); |
554 | if sym == 0 { |
555 | None |
556 | } else { |
557 | Some(SymbolIndex(sym as usize)) |
558 | } |
559 | } |
560 | } |
561 | |
562 | impl<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 | |
593 | impl<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)] |
628 | pub 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 | |
636 | impl<'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 | |
649 | impl<'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: Option<{unknown}> = 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)] |
674 | pub 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 | |
695 | impl<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 | |
715 | impl<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 | } |
734 | |