use core::ops::{Deref, DerefMut};
use elf::abi::{
SHN_UNDEF, STB_GLOBAL, STB_GNU_UNIQUE, STB_LOCAL, STB_WEAK, STT_COMMON, STT_FUNC,
STT_GNU_IFUNC, STT_NOTYPE, STT_OBJECT, STT_TLS,
};
use crate::arch::rel_type_to_str;
const OK_BINDS: usize = 1 << STB_GLOBAL | 1 << STB_WEAK | 1 << STB_GNU_UNIQUE;
const OK_TYPES: usize = 1 << STT_NOTYPE
| 1 << STT_OBJECT
| 1 << STT_FUNC
| 1 << STT_COMMON
| 1 << STT_TLS
| 1 << STT_GNU_IFUNC;
cfg_if::cfg_if! {
if #[cfg(target_pointer_width = "64")]{
pub(crate) const E_CLASS: u8 = elf::abi::ELFCLASS64;
pub(crate) type Phdr = elf::segment::Elf64_Phdr;
pub(crate) type Shdr = elf::section::Elf64_Shdr;
pub type ElfDyn = elf::dynamic::Elf64_Dyn;
pub(crate) type ElfEhdr = elf::file::Elf64_Ehdr;
pub(crate) type Rela = elf::relocation::Elf64_Rela;
pub(crate) type Rel = elf::relocation::Elf64_Rel;
pub(crate) type Relr = u64;
pub(crate) type Sym = elf::symbol::Elf64_Sym;
pub(crate) const REL_MASK: usize = 0xFFFFFFFF;
pub(crate) const REL_BIT: usize = 32;
pub(crate) const EHDR_SIZE: usize = core::mem::size_of::<elf::file::Elf64_Ehdr>();
}else{
pub(crate) const E_CLASS: u8 = elf::abi::ELFCLASS32;
pub(crate) type Phdr = elf::segment::Elf32_Phdr;
pub(crate) type Shdr = elf::section::Elf32_Shdr;
pub type ElfDyn = elf::dynamic::Elf32_Dyn;
pub(crate) type ElfEhdr = elf::file::Elf32_Ehdr;
pub(crate) type Rela = elf::relocation::Elf32_Rela;
pub(crate) type Rel = elf::relocation::Elf32_Rel;
pub(crate) type Relr = u32;
pub(crate) type Sym = Elf32Sym;
pub(crate) const REL_MASK: usize = 0xFF;
pub(crate) const REL_BIT: usize = 8;
pub(crate) const EHDR_SIZE: usize = core::mem::size_of::<elf::file::Elf32_Ehdr>();
}
}
#[allow(unused)]
#[repr(C)]
struct Elf32Sym {
pub st_name: u32,
pub st_value: u32,
pub st_size: u32,
pub st_info: u8,
pub st_other: u8,
pub st_shndx: u16,
}
pub const DT_RELRSZ: i64 = 35;
pub const DT_RELR: i64 = 36;
#[repr(transparent)]
pub struct ElfRelr {
relr: Relr,
}
impl ElfRelr {
#[inline]
pub fn value(&self) -> usize {
self.relr as usize
}
}
#[repr(transparent)]
pub struct ElfRela {
rela: Rela,
}
impl ElfRela {
#[inline]
pub fn r_type(&self) -> usize {
self.rela.r_info as usize & REL_MASK
}
#[inline]
pub fn r_symbol(&self) -> usize {
self.rela.r_info as usize >> REL_BIT
}
#[inline]
pub fn r_offset(&self) -> usize {
self.rela.r_offset as usize
}
#[inline]
pub fn r_addend(&self, _base: usize) -> isize {
self.rela.r_addend as isize
}
#[inline]
pub(crate) fn set_offset(&mut self, offset: usize) {
self.rela.r_offset = offset as _;
}
}
#[repr(transparent)]
pub struct ElfRel {
rel: Rel,
}
impl ElfRel {
#[inline]
pub fn r_type(&self) -> usize {
self.rel.r_info as usize & REL_MASK
}
#[inline]
pub fn r_symbol(&self) -> usize {
self.rel.r_info as usize >> REL_BIT
}
#[inline]
pub fn r_offset(&self) -> usize {
self.rel.r_offset as usize
}
#[inline]
pub fn r_addend(&self, base: usize) -> isize {
let ptr = (self.r_offset() + base) as *mut usize;
unsafe { ptr.read() as isize }
}
#[inline]
#[allow(unused)]
pub(crate) fn set_offset(&mut self, _offset: usize) {
todo!()
}
}
#[repr(transparent)]
pub struct ElfSymbol {
sym: Sym,
}
impl ElfSymbol {
#[inline]
pub fn st_value(&self) -> usize {
self.sym.st_value as usize
}
#[inline]
pub fn st_bind(&self) -> u8 {
self.sym.st_info >> 4
}
#[inline]
pub fn st_type(&self) -> u8 {
self.sym.st_info & 0xf
}
#[inline]
pub fn st_shndx(&self) -> usize {
self.sym.st_shndx as usize
}
#[inline]
pub fn st_name(&self) -> usize {
self.sym.st_name as usize
}
#[inline]
pub fn st_size(&self) -> usize {
self.sym.st_size as usize
}
#[inline]
pub fn st_other(&self) -> u8 {
self.sym.st_other
}
#[inline]
pub fn is_undef(&self) -> bool {
self.st_shndx() == SHN_UNDEF as usize
}
#[inline]
pub fn is_ok_bind(&self) -> bool {
(1 << self.st_bind()) & OK_BINDS != 0
}
#[inline]
pub fn is_ok_type(&self) -> bool {
(1 << self.st_type()) & OK_TYPES != 0
}
#[inline]
pub fn is_local(&self) -> bool {
self.st_bind() == STB_LOCAL
}
#[inline]
pub fn is_weak(&self) -> bool {
self.st_bind() == STB_WEAK
}
#[inline]
pub(crate) fn set_value(&mut self, value: usize) {
self.sym.st_value = value as _;
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct ElfPhdr {
phdr: Phdr,
}
#[derive(Debug)]
#[repr(transparent)]
pub struct ElfShdr {
shdr: Shdr,
}
impl ElfShdr {
pub(crate) fn new(
sh_name: u32,
sh_type: u32,
sh_flags: usize,
sh_addr: usize,
sh_offset: usize,
sh_size: usize,
sh_link: u32,
sh_info: u32,
sh_addralign: usize,
sh_entsize: usize,
) -> Self {
Self {
shdr: Shdr {
sh_name,
sh_type,
sh_flags: sh_flags as _,
sh_addr: sh_addr as _,
sh_offset: sh_offset as _,
sh_size: sh_size as _,
sh_link,
sh_info,
sh_addralign: sh_addralign as _,
sh_entsize: sh_entsize as _,
},
}
}
}
impl Deref for ElfShdr {
type Target = Shdr;
fn deref(&self) -> &Self::Target {
&self.shdr
}
}
impl DerefMut for ElfShdr {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.shdr
}
}
impl ElfShdr {
pub(crate) fn content<T>(&self) -> &'static [T] {
self.content_mut()
}
pub(crate) fn content_mut<T>(&self) -> &'static mut [T] {
let start = self.sh_addr as usize;
let len = (self.sh_size / self.sh_entsize) as usize;
debug_assert!(core::mem::size_of::<T>() == self.sh_entsize as usize);
debug_assert!(self.sh_size % self.sh_entsize == 0);
debug_assert!(self.sh_addr % self.sh_addralign == 0);
unsafe { core::slice::from_raw_parts_mut(start as *mut T, len) }
}
}
impl Deref for ElfPhdr {
type Target = Phdr;
fn deref(&self) -> &Self::Target {
&self.phdr
}
}
impl DerefMut for ElfPhdr {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.phdr
}
}
impl Clone for ElfPhdr {
fn clone(&self) -> Self {
Self {
phdr: Phdr {
p_type: self.phdr.p_type,
p_flags: self.phdr.p_flags,
p_align: self.phdr.p_align,
p_offset: self.phdr.p_offset,
p_vaddr: self.phdr.p_vaddr,
p_paddr: self.phdr.p_paddr,
p_filesz: self.phdr.p_filesz,
p_memsz: self.phdr.p_memsz,
},
}
}
}
#[cfg(all(not(target_arch = "x86"), not(target_arch = "arm")))]
pub type ElfRelType = ElfRela;
#[cfg(any(target_arch = "x86", target_arch = "arm"))]
pub type ElfRelType = ElfRel;
impl ElfRelType {
#[inline]
pub fn r_type_str(&self) -> &'static str {
let r_type = self.r_type();
rel_type_to_str(r_type)
}
}