7 use crate::endian
::{self, Endianness}
;
10 self, Error
, ReadRef
, Relocation
, RelocationEncoding
, RelocationKind
, RelocationTarget
,
14 use super::{ElfFile, FileHeader, SectionHeader, SectionTable}
;
16 /// A mapping from section index to associated relocation sections.
18 pub struct RelocationSections
{
19 relocations
: Vec
<usize>,
22 impl RelocationSections
{
23 /// Create a new mapping using the section table.
25 /// Skips relocation sections that do not use the given symbol table section.
26 pub fn parse
<'data
, Elf
: FileHeader
, R
: ReadRef
<'data
>>(
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
{
42 let sh_info
= section
.sh_info(endian
) as usize;
44 // Skip dynamic relocations.
47 if sh_info
>= relocations
.len() {
48 return Err(Error("Invalid ELF sh_info for relocation section"));
51 // Handle multiple relocation sections by chaining them.
52 let next
= relocations
[sh_info
];
53 relocations
[sh_info
] = index
;
54 relocations
[index
] = next
;
57 Ok(Self { relocations }
)
60 /// Given a section index, return the section index of the associated relocation section.
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)
69 pub(super) enum ElfRelaIterator
<'data
, Elf
: FileHeader
> {
70 Rel(slice
::Iter
<'data
, Elf
::Rel
>),
71 Rela(slice
::Iter
<'data
, Elf
::Rela
>),
74 impl<'data
, Elf
: FileHeader
> ElfRelaIterator
<'data
, Elf
> {
75 fn is_rel(&self) -> bool
{
77 ElfRelaIterator
::Rel(_
) => true,
78 ElfRelaIterator
::Rela(_
) => false,
83 impl<'data
, Elf
: FileHeader
> Iterator
for ElfRelaIterator
<'data
, Elf
> {
84 type Item
= Elf
::Rela
;
86 fn next(&mut self) -> Option
<Self::Item
> {
88 ElfRelaIterator
::Rel(ref mut i
) => i
.next().cloned().map(Self::Item
::from
),
89 ElfRelaIterator
::Rela(ref mut i
) => i
.next().cloned(),
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
>;
101 /// An iterator over the dynamic relocations for an `ElfFile`.
102 pub struct ElfDynamicRelocationIterator
<'data
, 'file
, Elf
, R
= &'data
[u8]>
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
>>,
113 impl<'data
, 'file
, Elf
, R
> Iterator
for ElfDynamicRelocationIterator
<'data
, 'file
, Elf
, R
>
118 type Item
= (u64, Relocation
);
120 fn next(&mut self) -> Option
<Self::Item
> {
121 let endian
= self.file
.endian
;
123 if let Some(ref mut relocations
) = self.relocations
{
124 if let Some(reloc
) = relocations
.next() {
126 parse_relocation(self.file
.header
, endian
, reloc
, relocations
.is_rel());
127 return Some((reloc
.r_offset(endian
).into(), relocation
));
129 self.relocations
= None
;
132 let section
= self.file
.sections
.section(self.section_index
).ok()?
;
133 self.section_index
+= 1;
135 let sh_link
= section
.sh_link(endian
) as usize;
136 if sh_link
!= self.file
.dynamic_symbols
.section() {
140 match section
.sh_type(endian
) {
142 if let Ok(relocations
) = section
.data_as_array(endian
, self.file
.data
) {
143 self.relocations
= Some(ElfRelaIterator
::Rel(relocations
.iter()));
147 if let Ok(relocations
) = section
.data_as_array(endian
, self.file
.data
) {
148 self.relocations
= Some(ElfRelaIterator
::Rela(relocations
.iter()));
157 impl<'data
, 'file
, Elf
, R
> fmt
::Debug
for ElfDynamicRelocationIterator
<'data
, 'file
, Elf
, R
>
162 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
163 f
.debug_struct("ElfDynamicRelocationIterator").finish()
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
>;
174 /// An iterator over the relocations for an `ElfSection`.
175 pub struct ElfSectionRelocationIterator
<'data
, 'file
, Elf
, R
= &'data
[u8]>
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
>>,
186 impl<'data
, 'file
, Elf
, R
> Iterator
for ElfSectionRelocationIterator
<'data
, 'file
, Elf
, R
>
191 type Item
= (u64, Relocation
);
193 fn next(&mut self) -> Option
<Self::Item
> {
194 let endian
= self.file
.endian
;
196 if let Some(ref mut relocations
) = self.relocations
{
197 if let Some(reloc
) = relocations
.next() {
199 parse_relocation(self.file
.header
, endian
, reloc
, relocations
.is_rel());
200 return Some((reloc
.r_offset(endian
).into(), relocation
));
202 self.relocations
= None
;
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
) {
209 if let Ok(relocations
) = section
.data_as_array(endian
, self.file
.data
) {
210 self.relocations
= Some(ElfRelaIterator
::Rel(relocations
.iter()));
214 if let Ok(relocations
) = section
.data_as_array(endian
, self.file
.data
) {
215 self.relocations
= Some(ElfRelaIterator
::Rela(relocations
.iter()));
224 impl<'data
, 'file
, Elf
, R
> fmt
::Debug
for ElfSectionRelocationIterator
<'data
, 'file
, Elf
, R
>
229 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
230 f
.debug_struct("ElfSectionRelocationIterator").finish()
234 fn parse_relocation
<Elf
: FileHeader
>(
238 implicit_addend
: bool
,
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)
254 r_type
=> (RelocationKind
::Elf(r_type
), 0),
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),
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),
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),
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),
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)
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),
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),
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),
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),
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),
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),
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),
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)
341 elf
::R_390_PC32DBL
=> {
342 encoding
= RelocationEncoding
::S390xDbl
;
343 (RelocationKind
::Relative
, 32)
345 elf
::R_390_PLT16DBL
=> {
346 encoding
= RelocationEncoding
::S390xDbl
;
347 (RelocationKind
::PltRelative
, 16)
349 elf
::R_390_PLT32DBL
=> {
350 encoding
= RelocationEncoding
::S390xDbl
;
351 (RelocationKind
::PltRelative
, 32)
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)
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)
368 r_type
=> (RelocationKind
::Elf(r_type
), 0),
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),
377 _
=> (RelocationKind
::Elf(reloc
.r_type(endian
, false)), 0),
379 let sym
= reloc
.r_sym(endian
, is_mips64el
) as usize;
380 let target
= if sym
== 0 {
381 RelocationTarget
::Absolute
383 RelocationTarget
::Symbol(SymbolIndex(sym
))
390 addend
: reloc
.r_addend(endian
).into(),
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
;
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;
408 impl<Endian
: endian
::Endian
> Rel
for elf
::Rel32
<Endian
> {
411 type Endian
= Endian
;
414 fn r_offset(&self, endian
: Self::Endian
) -> Self::Word
{
415 self.r_offset
.get(endian
)
419 fn r_info(&self, endian
: Self::Endian
) -> Self::Word
{
420 self.r_info
.get(endian
)
424 fn r_sym(&self, endian
: Self::Endian
) -> u32 {
429 fn r_type(&self, endian
: Self::Endian
) -> u32 {
434 impl<Endian
: endian
::Endian
> Rel
for elf
::Rel64
<Endian
> {
437 type Endian
= Endian
;
440 fn r_offset(&self, endian
: Self::Endian
) -> Self::Word
{
441 self.r_offset
.get(endian
)
445 fn r_info(&self, endian
: Self::Endian
) -> Self::Word
{
446 self.r_info
.get(endian
)
450 fn r_sym(&self, endian
: Self::Endian
) -> u32 {
455 fn r_type(&self, endian
: Self::Endian
) -> u32 {
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
;
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;
474 impl<Endian
: endian
::Endian
> Rela
for elf
::Rela32
<Endian
> {
477 type Endian
= Endian
;
480 fn r_offset(&self, endian
: Self::Endian
) -> Self::Word
{
481 self.r_offset
.get(endian
)
485 fn r_info(&self, endian
: Self::Endian
, _is_mips64el
: bool
) -> Self::Word
{
486 self.r_info
.get(endian
)
490 fn r_addend(&self, endian
: Self::Endian
) -> Self::Sword
{
491 self.r_addend
.get(endian
)
495 fn r_sym(&self, endian
: Self::Endian
, _is_mips64el
: bool
) -> u32 {
500 fn r_type(&self, endian
: Self::Endian
, _is_mips64el
: bool
) -> u32 {
505 impl<Endian
: endian
::Endian
> Rela
for elf
::Rela64
<Endian
> {
508 type Endian
= Endian
;
511 fn r_offset(&self, endian
: Self::Endian
) -> Self::Word
{
512 self.r_offset
.get(endian
)
516 fn r_info(&self, endian
: Self::Endian
, is_mips64el
: bool
) -> Self::Word
{
517 self.get_r_info(endian
, is_mips64el
)
521 fn r_addend(&self, endian
: Self::Endian
) -> Self::Sword
{
522 self.r_addend
.get(endian
)
526 fn r_sym(&self, endian
: Self::Endian
, is_mips64el
: bool
) -> u32 {
527 self.r_sym(endian
, is_mips64el
)
531 fn r_type(&self, endian
: Self::Endian
, is_mips64el
: bool
) -> u32 {
532 self.r_type(endian
, is_mips64el
)