]> git.proxmox.com Git - rustc.git/blob - vendor/object/src/read/elf/relocation.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / vendor / object / src / read / elf / relocation.rs
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, RelocationKind, RelocationTarget,
11 SymbolIndex,
12 };
13
14 use super::{ElfFile, FileHeader, SectionHeader, SectionTable};
15
16 /// A mapping from section index to associated relocation sections.
17 #[derive(Debug)]
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: usize,
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.sh_link(endian) as usize;
38 if sh_link != symbol_section {
39 continue;
40 }
41
42 let sh_info = section.sh_info(endian) as usize;
43 if sh_info == 0 {
44 // Skip dynamic relocations.
45 continue;
46 }
47 if sh_info >= relocations.len() {
48 return Err(Error("Invalid ELF sh_info for relocation section"));
49 }
50
51 // Handle multiple relocation sections by chaining them.
52 let next = relocations[sh_info];
53 relocations[sh_info] = index;
54 relocations[index] = next;
55 }
56 }
57 Ok(Self { relocations })
58 }
59
60 /// Given a section index, return the section index of the associated relocation section.
61 ///
62 /// This may also be called with a relocation section index, and it will return the
63 /// next associated relocation section.
64 pub fn get(&self, index: usize) -> Option<usize> {
65 self.relocations.get(index).cloned().filter(|x| *x != 0)
66 }
67 }
68
69 pub(super) enum ElfRelaIterator<'data, Elf: FileHeader> {
70 Rel(slice::Iter<'data, Elf::Rel>),
71 Rela(slice::Iter<'data, Elf::Rela>),
72 }
73
74 impl<'data, Elf: FileHeader> ElfRelaIterator<'data, Elf> {
75 fn is_rel(&self) -> bool {
76 match self {
77 ElfRelaIterator::Rel(_) => true,
78 ElfRelaIterator::Rela(_) => false,
79 }
80 }
81 }
82
83 impl<'data, Elf: FileHeader> Iterator for ElfRelaIterator<'data, Elf> {
84 type Item = Elf::Rela;
85
86 fn next(&mut self) -> Option<Self::Item> {
87 match self {
88 ElfRelaIterator::Rel(ref mut i) => i.next().cloned().map(Self::Item::from),
89 ElfRelaIterator::Rela(ref mut i) => i.next().cloned(),
90 }
91 }
92 }
93
94 /// An iterator over the dynamic relocations for an `ElfFile32`.
95 pub type ElfDynamicRelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
96 ElfDynamicRelocationIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
97 /// An iterator over the dynamic relocations for an `ElfFile64`.
98 pub type ElfDynamicRelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
99 ElfDynamicRelocationIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
100
101 /// An iterator over the dynamic relocations for an `ElfFile`.
102 pub struct ElfDynamicRelocationIterator<'data, 'file, Elf, R = &'data [u8]>
103 where
104 Elf: FileHeader,
105 R: ReadRef<'data>,
106 {
107 /// The current relocation section index.
108 pub(super) section_index: usize,
109 pub(super) file: &'file ElfFile<'data, Elf, R>,
110 pub(super) relocations: Option<ElfRelaIterator<'data, Elf>>,
111 }
112
113 impl<'data, 'file, Elf, R> Iterator for ElfDynamicRelocationIterator<'data, 'file, Elf, R>
114 where
115 Elf: FileHeader,
116 R: ReadRef<'data>,
117 {
118 type Item = (u64, Relocation);
119
120 fn next(&mut self) -> Option<Self::Item> {
121 let endian = self.file.endian;
122 loop {
123 if let Some(ref mut relocations) = self.relocations {
124 if let Some(reloc) = relocations.next() {
125 let relocation =
126 parse_relocation(self.file.header, endian, reloc, relocations.is_rel());
127 return Some((reloc.r_offset(endian).into(), relocation));
128 }
129 self.relocations = None;
130 }
131
132 let section = self.file.sections.section(self.section_index).ok()?;
133 self.section_index += 1;
134
135 let sh_link = section.sh_link(endian) as usize;
136 if sh_link != self.file.dynamic_symbols.section() {
137 continue;
138 }
139
140 match section.sh_type(endian) {
141 elf::SHT_REL => {
142 if let Ok(relocations) = section.data_as_array(endian, self.file.data) {
143 self.relocations = Some(ElfRelaIterator::Rel(relocations.iter()));
144 }
145 }
146 elf::SHT_RELA => {
147 if let Ok(relocations) = section.data_as_array(endian, self.file.data) {
148 self.relocations = Some(ElfRelaIterator::Rela(relocations.iter()));
149 }
150 }
151 _ => {}
152 }
153 }
154 }
155 }
156
157 impl<'data, 'file, Elf, R> fmt::Debug for ElfDynamicRelocationIterator<'data, 'file, Elf, R>
158 where
159 Elf: FileHeader,
160 R: ReadRef<'data>,
161 {
162 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
163 f.debug_struct("ElfDynamicRelocationIterator").finish()
164 }
165 }
166
167 /// An iterator over the relocations for an `ElfSection32`.
168 pub type ElfSectionRelocationIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
169 ElfSectionRelocationIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
170 /// An iterator over the relocations for an `ElfSection64`.
171 pub type ElfSectionRelocationIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
172 ElfSectionRelocationIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
173
174 /// An iterator over the relocations for an `ElfSection`.
175 pub struct ElfSectionRelocationIterator<'data, 'file, Elf, R = &'data [u8]>
176 where
177 Elf: FileHeader,
178 R: ReadRef<'data>,
179 {
180 /// The current pointer in the chain of relocation sections.
181 pub(super) section_index: usize,
182 pub(super) file: &'file ElfFile<'data, Elf, R>,
183 pub(super) relocations: Option<ElfRelaIterator<'data, Elf>>,
184 }
185
186 impl<'data, 'file, Elf, R> Iterator for ElfSectionRelocationIterator<'data, 'file, Elf, R>
187 where
188 Elf: FileHeader,
189 R: ReadRef<'data>,
190 {
191 type Item = (u64, Relocation);
192
193 fn next(&mut self) -> Option<Self::Item> {
194 let endian = self.file.endian;
195 loop {
196 if let Some(ref mut relocations) = self.relocations {
197 if let Some(reloc) = relocations.next() {
198 let relocation =
199 parse_relocation(self.file.header, endian, reloc, relocations.is_rel());
200 return Some((reloc.r_offset(endian).into(), relocation));
201 }
202 self.relocations = None;
203 }
204 self.section_index = self.file.relocations.get(self.section_index)?;
205 // The construction of RelocationSections ensures section_index is valid.
206 let section = self.file.sections.section(self.section_index).unwrap();
207 match section.sh_type(endian) {
208 elf::SHT_REL => {
209 if let Ok(relocations) = section.data_as_array(endian, self.file.data) {
210 self.relocations = Some(ElfRelaIterator::Rel(relocations.iter()));
211 }
212 }
213 elf::SHT_RELA => {
214 if let Ok(relocations) = section.data_as_array(endian, self.file.data) {
215 self.relocations = Some(ElfRelaIterator::Rela(relocations.iter()));
216 }
217 }
218 _ => {}
219 }
220 }
221 }
222 }
223
224 impl<'data, 'file, Elf, R> fmt::Debug for ElfSectionRelocationIterator<'data, 'file, Elf, R>
225 where
226 Elf: FileHeader,
227 R: ReadRef<'data>,
228 {
229 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230 f.debug_struct("ElfSectionRelocationIterator").finish()
231 }
232 }
233
234 fn parse_relocation<Elf: FileHeader>(
235 header: &Elf,
236 endian: Elf::Endian,
237 reloc: Elf::Rela,
238 implicit_addend: bool,
239 ) -> Relocation {
240 let mut encoding = RelocationEncoding::Generic;
241 let is_mips64el = header.is_mips64el(endian);
242 let (kind, size) = match header.e_machine(endian) {
243 elf::EM_AARCH64 => match reloc.r_type(endian, false) {
244 elf::R_AARCH64_ABS64 => (RelocationKind::Absolute, 64),
245 elf::R_AARCH64_ABS32 => (RelocationKind::Absolute, 32),
246 elf::R_AARCH64_ABS16 => (RelocationKind::Absolute, 16),
247 elf::R_AARCH64_PREL64 => (RelocationKind::Relative, 64),
248 elf::R_AARCH64_PREL32 => (RelocationKind::Relative, 32),
249 elf::R_AARCH64_PREL16 => (RelocationKind::Relative, 16),
250 elf::R_AARCH64_CALL26 => {
251 encoding = RelocationEncoding::AArch64Call;
252 (RelocationKind::PltRelative, 26)
253 }
254 r_type => (RelocationKind::Elf(r_type), 0),
255 },
256 elf::EM_ARM => match reloc.r_type(endian, false) {
257 elf::R_ARM_ABS32 => (RelocationKind::Absolute, 32),
258 r_type => (RelocationKind::Elf(r_type), 0),
259 },
260 elf::EM_AVR => match reloc.r_type(endian, false) {
261 elf::R_AVR_32 => (RelocationKind::Absolute, 32),
262 elf::R_AVR_16 => (RelocationKind::Absolute, 16),
263 r_type => (RelocationKind::Elf(r_type), 0),
264 },
265 elf::EM_BPF => match reloc.r_type(endian, false) {
266 elf::R_BPF_64_64 => (RelocationKind::Absolute, 64),
267 elf::R_BPF_64_32 => (RelocationKind::Absolute, 32),
268 r_type => (RelocationKind::Elf(r_type), 0),
269 },
270 elf::EM_386 => match reloc.r_type(endian, false) {
271 elf::R_386_32 => (RelocationKind::Absolute, 32),
272 elf::R_386_PC32 => (RelocationKind::Relative, 32),
273 elf::R_386_GOT32 => (RelocationKind::Got, 32),
274 elf::R_386_PLT32 => (RelocationKind::PltRelative, 32),
275 elf::R_386_GOTOFF => (RelocationKind::GotBaseOffset, 32),
276 elf::R_386_GOTPC => (RelocationKind::GotBaseRelative, 32),
277 elf::R_386_16 => (RelocationKind::Absolute, 16),
278 elf::R_386_PC16 => (RelocationKind::Relative, 16),
279 elf::R_386_8 => (RelocationKind::Absolute, 8),
280 elf::R_386_PC8 => (RelocationKind::Relative, 8),
281 r_type => (RelocationKind::Elf(r_type), 0),
282 },
283 elf::EM_X86_64 => match reloc.r_type(endian, false) {
284 elf::R_X86_64_64 => (RelocationKind::Absolute, 64),
285 elf::R_X86_64_PC32 => (RelocationKind::Relative, 32),
286 elf::R_X86_64_GOT32 => (RelocationKind::Got, 32),
287 elf::R_X86_64_PLT32 => (RelocationKind::PltRelative, 32),
288 elf::R_X86_64_GOTPCREL => (RelocationKind::GotRelative, 32),
289 elf::R_X86_64_32 => (RelocationKind::Absolute, 32),
290 elf::R_X86_64_32S => {
291 encoding = RelocationEncoding::X86Signed;
292 (RelocationKind::Absolute, 32)
293 }
294 elf::R_X86_64_16 => (RelocationKind::Absolute, 16),
295 elf::R_X86_64_PC16 => (RelocationKind::Relative, 16),
296 elf::R_X86_64_8 => (RelocationKind::Absolute, 8),
297 elf::R_X86_64_PC8 => (RelocationKind::Relative, 8),
298 r_type => (RelocationKind::Elf(r_type), 0),
299 },
300 elf::EM_HEXAGON => match reloc.r_type(endian, false) {
301 elf::R_HEX_32 => (RelocationKind::Absolute, 32),
302 r_type => (RelocationKind::Elf(r_type), 0),
303 },
304 elf::EM_MIPS => match reloc.r_type(endian, is_mips64el) {
305 elf::R_MIPS_16 => (RelocationKind::Absolute, 16),
306 elf::R_MIPS_32 => (RelocationKind::Absolute, 32),
307 elf::R_MIPS_64 => (RelocationKind::Absolute, 64),
308 r_type => (RelocationKind::Elf(r_type), 0),
309 },
310 elf::EM_MSP430 => match reloc.r_type(endian, false) {
311 elf::R_MSP430_32 => (RelocationKind::Absolute, 32),
312 elf::R_MSP430_16_BYTE => (RelocationKind::Absolute, 16),
313 r_type => (RelocationKind::Elf(r_type), 0),
314 },
315 elf::EM_PPC => match reloc.r_type(endian, false) {
316 elf::R_PPC_ADDR32 => (RelocationKind::Absolute, 32),
317 r_type => (RelocationKind::Elf(r_type), 0),
318 },
319 elf::EM_PPC64 => match reloc.r_type(endian, false) {
320 elf::R_PPC64_ADDR32 => (RelocationKind::Absolute, 32),
321 elf::R_PPC64_ADDR64 => (RelocationKind::Absolute, 64),
322 r_type => (RelocationKind::Elf(r_type), 0),
323 },
324 elf::EM_RISCV => match reloc.r_type(endian, false) {
325 elf::R_RISCV_32 => (RelocationKind::Absolute, 32),
326 elf::R_RISCV_64 => (RelocationKind::Absolute, 64),
327 r_type => (RelocationKind::Elf(r_type), 0),
328 },
329 elf::EM_S390 => match reloc.r_type(endian, false) {
330 elf::R_390_8 => (RelocationKind::Absolute, 8),
331 elf::R_390_16 => (RelocationKind::Absolute, 16),
332 elf::R_390_32 => (RelocationKind::Absolute, 32),
333 elf::R_390_64 => (RelocationKind::Absolute, 64),
334 elf::R_390_PC16 => (RelocationKind::Relative, 16),
335 elf::R_390_PC32 => (RelocationKind::Relative, 32),
336 elf::R_390_PC64 => (RelocationKind::Relative, 64),
337 elf::R_390_PC16DBL => {
338 encoding = RelocationEncoding::S390xDbl;
339 (RelocationKind::Relative, 16)
340 }
341 elf::R_390_PC32DBL => {
342 encoding = RelocationEncoding::S390xDbl;
343 (RelocationKind::Relative, 32)
344 }
345 elf::R_390_PLT16DBL => {
346 encoding = RelocationEncoding::S390xDbl;
347 (RelocationKind::PltRelative, 16)
348 }
349 elf::R_390_PLT32DBL => {
350 encoding = RelocationEncoding::S390xDbl;
351 (RelocationKind::PltRelative, 32)
352 }
353 elf::R_390_GOT16 => (RelocationKind::Got, 16),
354 elf::R_390_GOT32 => (RelocationKind::Got, 32),
355 elf::R_390_GOT64 => (RelocationKind::Got, 64),
356 elf::R_390_GOTENT => {
357 encoding = RelocationEncoding::S390xDbl;
358 (RelocationKind::GotRelative, 32)
359 }
360 elf::R_390_GOTOFF16 => (RelocationKind::GotBaseOffset, 16),
361 elf::R_390_GOTOFF32 => (RelocationKind::GotBaseOffset, 32),
362 elf::R_390_GOTOFF64 => (RelocationKind::GotBaseOffset, 64),
363 elf::R_390_GOTPC => (RelocationKind::GotBaseRelative, 64),
364 elf::R_390_GOTPCDBL => {
365 encoding = RelocationEncoding::S390xDbl;
366 (RelocationKind::GotBaseRelative, 32)
367 }
368 r_type => (RelocationKind::Elf(r_type), 0),
369 },
370 elf::EM_SPARC | elf::EM_SPARC32PLUS | elf::EM_SPARCV9 => {
371 match reloc.r_type(endian, false) {
372 elf::R_SPARC_32 | elf::R_SPARC_UA32 => (RelocationKind::Absolute, 32),
373 elf::R_SPARC_64 | elf::R_SPARC_UA64 => (RelocationKind::Absolute, 64),
374 r_type => (RelocationKind::Elf(r_type), 0),
375 }
376 }
377 _ => (RelocationKind::Elf(reloc.r_type(endian, false)), 0),
378 };
379 let sym = reloc.r_sym(endian, is_mips64el) as usize;
380 let target = if sym == 0 {
381 RelocationTarget::Absolute
382 } else {
383 RelocationTarget::Symbol(SymbolIndex(sym))
384 };
385 Relocation {
386 kind,
387 encoding,
388 size,
389 target,
390 addend: reloc.r_addend(endian).into(),
391 implicit_addend,
392 }
393 }
394
395 /// A trait for generic access to `Rel32` and `Rel64`.
396 #[allow(missing_docs)]
397 pub trait Rel: Debug + Pod + Clone {
398 type Word: Into<u64>;
399 type Sword: Into<i64>;
400 type Endian: endian::Endian;
401
402 fn r_offset(&self, endian: Self::Endian) -> Self::Word;
403 fn r_info(&self, endian: Self::Endian) -> Self::Word;
404 fn r_sym(&self, endian: Self::Endian) -> u32;
405 fn r_type(&self, endian: Self::Endian) -> u32;
406 }
407
408 impl<Endian: endian::Endian> Rel for elf::Rel32<Endian> {
409 type Word = u32;
410 type Sword = i32;
411 type Endian = Endian;
412
413 #[inline]
414 fn r_offset(&self, endian: Self::Endian) -> Self::Word {
415 self.r_offset.get(endian)
416 }
417
418 #[inline]
419 fn r_info(&self, endian: Self::Endian) -> Self::Word {
420 self.r_info.get(endian)
421 }
422
423 #[inline]
424 fn r_sym(&self, endian: Self::Endian) -> u32 {
425 self.r_sym(endian)
426 }
427
428 #[inline]
429 fn r_type(&self, endian: Self::Endian) -> u32 {
430 self.r_type(endian)
431 }
432 }
433
434 impl<Endian: endian::Endian> Rel for elf::Rel64<Endian> {
435 type Word = u64;
436 type Sword = i64;
437 type Endian = Endian;
438
439 #[inline]
440 fn r_offset(&self, endian: Self::Endian) -> Self::Word {
441 self.r_offset.get(endian)
442 }
443
444 #[inline]
445 fn r_info(&self, endian: Self::Endian) -> Self::Word {
446 self.r_info.get(endian)
447 }
448
449 #[inline]
450 fn r_sym(&self, endian: Self::Endian) -> u32 {
451 self.r_sym(endian)
452 }
453
454 #[inline]
455 fn r_type(&self, endian: Self::Endian) -> u32 {
456 self.r_type(endian)
457 }
458 }
459
460 /// A trait for generic access to `Rela32` and `Rela64`.
461 #[allow(missing_docs)]
462 pub trait Rela: Debug + Pod + Clone {
463 type Word: Into<u64>;
464 type Sword: Into<i64>;
465 type Endian: endian::Endian;
466
467 fn r_offset(&self, endian: Self::Endian) -> Self::Word;
468 fn r_info(&self, endian: Self::Endian, is_mips64el: bool) -> Self::Word;
469 fn r_addend(&self, endian: Self::Endian) -> Self::Sword;
470 fn r_sym(&self, endian: Self::Endian, is_mips64el: bool) -> u32;
471 fn r_type(&self, endian: Self::Endian, is_mips64el: bool) -> u32;
472 }
473
474 impl<Endian: endian::Endian> Rela for elf::Rela32<Endian> {
475 type Word = u32;
476 type Sword = i32;
477 type Endian = Endian;
478
479 #[inline]
480 fn r_offset(&self, endian: Self::Endian) -> Self::Word {
481 self.r_offset.get(endian)
482 }
483
484 #[inline]
485 fn r_info(&self, endian: Self::Endian, _is_mips64el: bool) -> Self::Word {
486 self.r_info.get(endian)
487 }
488
489 #[inline]
490 fn r_addend(&self, endian: Self::Endian) -> Self::Sword {
491 self.r_addend.get(endian)
492 }
493
494 #[inline]
495 fn r_sym(&self, endian: Self::Endian, _is_mips64el: bool) -> u32 {
496 self.r_sym(endian)
497 }
498
499 #[inline]
500 fn r_type(&self, endian: Self::Endian, _is_mips64el: bool) -> u32 {
501 self.r_type(endian)
502 }
503 }
504
505 impl<Endian: endian::Endian> Rela for elf::Rela64<Endian> {
506 type Word = u64;
507 type Sword = i64;
508 type Endian = Endian;
509
510 #[inline]
511 fn r_offset(&self, endian: Self::Endian) -> Self::Word {
512 self.r_offset.get(endian)
513 }
514
515 #[inline]
516 fn r_info(&self, endian: Self::Endian, is_mips64el: bool) -> Self::Word {
517 self.get_r_info(endian, is_mips64el)
518 }
519
520 #[inline]
521 fn r_addend(&self, endian: Self::Endian) -> Self::Sword {
522 self.r_addend.get(endian)
523 }
524
525 #[inline]
526 fn r_sym(&self, endian: Self::Endian, is_mips64el: bool) -> u32 {
527 self.r_sym(endian, is_mips64el)
528 }
529
530 #[inline]
531 fn r_type(&self, endian: Self::Endian, is_mips64el: bool) -> u32 {
532 self.r_type(endian, is_mips64el)
533 }
534 }