//! # Relocation computations //! //! The following notation is used to describe relocation computations //! specific to x86_64 ELF. //! //! * A: The addend used to compute the value of the relocatable field. //! * B: The base address at which a shared object is loaded into memory //! during execution. Generally, a shared object file is built with a //! base virtual address of 0. However, the execution address of the //! shared object is different. //! * G: The offset into the global offset table at which the address of //! the relocation entry's symbol resides during execution. //! * GOT: The address of the global offset table. //! * L: The section offset or address of the procedure linkage table entry //! for a symbol. //! * P: The section offset or address of the storage unit being relocated, //! computed using r_offset. //! * S: The value of the symbol whose index resides in the relocation entry. //! * Z: The size of the symbol whose index resides in the relocation entry. //! //! Below are some common x86_64 relocation computations you might find useful: //! //! | Relocation | Value | Size | Formula | //! |:--------------------------|:------|:----------|:------------------| //! | `R_X86_64_NONE` | 0 | NONE | NONE | //! | `R_X86_64_64` | 1 | 64 | S + A | //! | `R_X86_64_PC32` | 2 | 32 | S + A - P | //! | `R_X86_64_GOT32` | 3 | 32 | G + A | //! | `R_X86_64_PLT32` | 4 | 32 | L + A - P | //! | `R_X86_64_COPY` | 5 | NONE | NONE | //! | `R_X86_64_GLOB_DAT` | 6 | 64 | S | //! | `R_X86_64_JUMP_SLOT` | 7 | 64 | S | //! | `R_X86_64_RELATIVE` | 8 | 64 | B + A | //! | `R_X86_64_GOTPCREL` | 9 | 32 | G + GOT + A - P | //! | `R_X86_64_32` | 10 | 32 | S + A | //! | `R_X86_64_32S` | 11 | 32 | S + A | //! | `R_X86_64_16` | 12 | 16 | S + A | //! | `R_X86_64_PC16` | 13 | 16 | S + A - P | //! | `R_X86_64_8` | 14 | 8 | S + A | //! | `R_X86_64_PC8` | 15 | 8 | S + A - P | //! | `R_X86_64_DTPMOD64` | 16 | 64 | | //! | `R_X86_64_DTPOFF64` | 17 | 64 | | //! | `R_X86_64_TPOFF64` | 18 | 64 | | //! | `R_X86_64_TLSGD` | 19 | 32 | | //! | `R_X86_64_TLSLD` | 20 | 32 | | //! | `R_X86_64_DTPOFF32` | 21 | 32 | | //! | `R_X86_64_GOTTPOFF` | 22 | 32 | | //! | `R_X86_64_TPOFF32` | 23 | 32 | | //! | `R_X86_64_PC64` | 24 | 64 | S + A - P | //! | `R_X86_64_GOTOFF64` | 25 | 64 | S + A - GOT | //! | `R_X86_64_GOTPC32` | 26 | 32 | GOT + A - P | //! | `R_X86_64_SIZE32` | 32 | 32 | Z + A | //! | `R_X86_64_SIZE64` | 33 | 64 | Z + A | //! | `R_X86_64_GOTPC32_TLSDESC`| 34 | 32 | | //! | `R_X86_64_TLSDESC_CALL` | 35 | NONE | | //! | `R_X86_64_TLSDESC` | 36 | 64 × 2 | | //! | `R_X86_64_IRELATIVE` | 37 | 64 | indirect (B + A) | //! //! TLS information is at <http://people.redhat.com/aoliva/writeups/TLS/RFC-TLSDESC-x86.txt> //! //! `R_X86_64_IRELATIVE` is similar to `R_X86_64_RELATIVE` except that //! the value used in this relocation is the program address returned by the function, //! which takes no arguments, at the address of the result of the corresponding //! `R_X86_64_RELATIVE` relocation. //! //! Read more <https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-54839.html>
include!("constants_relocation.rs");
macro_rules! elf_reloc {
($size:ident, $isize:ty) => { use core::fmt; #[cfg(feature = "alloc")] use scroll::{Pread, Pwrite, SizeWith}; #[repr(C)] #[derive(Clone, Copy, PartialEq, Default)] #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] /// Relocation with an explicit addend pubstruct Rela { /// Address pub r_offset: $size, /// Relocation type and symbol index pub r_info: $size, /// Addend pub r_addend: $isize,
} #[repr(C)] #[derive(Clone, PartialEq, Default)] #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] /// Relocation without an addend pubstruct Rel { /// address pub r_offset: $size, /// relocation type and symbol address pub r_info: $size,
} use plain; unsafeimpl plain::Plain for Rela {} unsafeimpl plain::Plain for Rel {}
impl fmt::Debug for Rela { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let sym = r_sym(self.r_info); let typ = r_type(self.r_info);
f.debug_struct("Rela")
.field("r_offset", &format_args!("{:x}", self.r_offset))
.field("r_info", &format_args!("{:x}", self.r_info))
.field("r_addend", &format_args!("{:x}", self.r_addend))
.field("r_typ", &typ)
.field("r_sym", &sym)
.finish()
}
} impl fmt::Debug for Rel { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let sym = r_sym(self.r_info); let typ = r_type(self.r_info);
f.debug_struct("Rel")
.field("r_offset", &format_args!("{:x}", self.r_offset))
.field("r_info", &format_args!("{:x}", self.r_info))
.field("r_typ", &typ)
.field("r_sym", &sym)
.finish()
}
}
};
}
impl From<Reloc> for Rela { fn from(rela: Reloc) -> Self { let r_info = r_info(rela.r_sym as $size, $size::from(rela.r_type));
Rela {
r_offset: rela.r_offset as $size,
r_info: r_info,
r_addend: rela.r_addend.unwrap_or(0) as $isize,
}
}
}
impl From<Reloc> for Rel { fn from(rel: Reloc) -> Self { let r_info = r_info(rel.r_sym as $size, $size::from(rel.r_type));
Rel {
r_offset: rel.r_offset as $size,
r_info: r_info,
}
}
}
/// Gets the rela entries given a rela pointer and the _size_ of the rela section in the binary, /// in bytes. /// Assumes the pointer is valid and can safely return a slice of memory pointing to the relas because: /// 1. `ptr` points to memory received from the kernel (i.e., it loaded the executable), _or_ /// 2. The binary has already been mmapped (i.e., it's a `SharedObject`), and hence it's safe to return a slice of that memory. /// 3. Or if you obtained the pointer in some other lawful manner pubunsafefn from_raw_rela<'a>(ptr: *const Rela, size: usize) -> &'a [Rela] {
slice::from_raw_parts(ptr, size / SIZEOF_RELA)
}
/// Gets the rel entries given a rel pointer and the _size_ of the rel section in the binary, /// in bytes. /// Assumes the pointer is valid and can safely return a slice of memory pointing to the rels because: /// 1. `ptr` points to memory received from the kernel (i.e., it loaded the executable), _or_ /// 2. The binary has already been mmapped (i.e., it's a `SharedObject`), and hence it's safe to return a slice of that memory. /// 3. Or if you obtained the pointer in some other lawful manner pubunsafefn from_raw_rel<'a>(ptr: *const Rel, size: usize) -> &'a [Rel] {
slice::from_raw_parts(ptr, size / SIZEOF_REL)
}
////////////////////////////// // Generic Reloc /////////////////////////////
if_alloc! { use scroll::{ctx, Pread}; use scroll::ctx::SizeWith; use core::fmt; use core::result; usecrate::container::{Ctx, Container}; use alloc::vec::Vec;
#[derive(Clone, Copy, PartialEq, Default)] /// A unified ELF relocation structure pubstruct Reloc { /// Address pub r_offset: u64, /// Addend pub r_addend: Option<i64>, /// The index into the corresponding symbol table - either dynamic or regular pub r_sym: usize, /// The relocation type pub r_type: u32,
}
/// Try to parse a single relocation from the binary, at `index`. #[inline] pubfn get(&self, index: usize) -> Option<Reloc> { if index >= self.count {
None
} else {
Some(self.bytes.pread_with(index * Reloc::size_with(&self.ctx), self.ctx).unwrap())
}
}
/// The number of relocations in the section. #[inline] pubfn len(&self) -> usize { self.count
}
/// Returns true if section has no relocations. #[inline] pubfn is_empty(&self) -> bool { self.count == 0
}
/// Iterate over all relocations. pubfn iter(&self) -> RelocIterator<'a> { self.into_iter()
}
/// Parse all relocations into a vector. pubfn to_vec(&self) -> Vec<Reloc> { self.iter().collect()
}
}
impl<'a, 'b> IntoIterator for &'b RelocSection<'a> { type Item = <RelocIterator<'a> as Iterator>::Item; type IntoIter = RelocIterator<'a>;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.