use super::section::SectionIndex;
use crate::entity::PrimaryMap;
use crate::lib::std::fmt;
use crate::lib::std::vec::Vec;
use crate::{Addend, CodeOffset};
use crate::{LibCall, LocalFunctionIndex};
use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
#[derive(
RkyvSerialize, RkyvDeserialize, Archive, rkyv::CheckBytes, Copy, Clone, Debug, PartialEq, Eq,
)]
#[archive(as = "Self")]
#[repr(u8)]
pub enum RelocationKind {
Abs4,
Abs8,
X86PCRel4,
X86PCRel8,
X86CallPCRel4,
X86CallPLTRel4,
X86GOTPCRel4,
Arm32Call,
Arm64Call,
Arm64Movw0,
Arm64Movw1,
Arm64Movw2,
Arm64Movw3,
RiscvPCRelHi20,
RiscvPCRelLo12I,
RiscvCall,
ElfX86_64TlsGd,
}
impl fmt::Display for RelocationKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Self::Abs4 => write!(f, "Abs4"),
Self::Abs8 => write!(f, "Abs8"),
Self::X86PCRel4 => write!(f, "PCRel4"),
Self::X86PCRel8 => write!(f, "PCRel8"),
Self::X86CallPCRel4 => write!(f, "CallPCRel4"),
Self::X86CallPLTRel4 => write!(f, "CallPLTRel4"),
Self::X86GOTPCRel4 => write!(f, "GOTPCRel4"),
Self::Arm32Call | Self::Arm64Call | Self::RiscvCall => write!(f, "Call"),
Self::Arm64Movw0 => write!(f, "Arm64MovwG0"),
Self::Arm64Movw1 => write!(f, "Arm64MovwG1"),
Self::Arm64Movw2 => write!(f, "Arm64MovwG2"),
Self::Arm64Movw3 => write!(f, "Arm64MovwG3"),
Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"),
Self::RiscvPCRelHi20 => write!(f, "RiscvPCRelHi20"),
Self::RiscvPCRelLo12I => write!(f, "RiscvPCRelLo12I"),
}
}
}
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
#[derive(RkyvSerialize, RkyvDeserialize, Archive, Debug, Clone, PartialEq, Eq)]
#[archive_attr(derive(rkyv::CheckBytes, Debug))]
pub struct Relocation {
pub kind: RelocationKind,
pub reloc_target: RelocationTarget,
pub offset: CodeOffset,
pub addend: Addend,
}
#[allow(missing_docs)]
pub trait RelocationLike {
fn kind(&self) -> RelocationKind;
fn reloc_target(&self) -> RelocationTarget;
fn offset(&self) -> CodeOffset;
fn addend(&self) -> Addend;
fn for_address(&self, start: usize, target_func_address: u64) -> (usize, u64) {
match self.kind() {
RelocationKind::Abs8
| RelocationKind::Arm64Movw0
| RelocationKind::Arm64Movw1
| RelocationKind::Arm64Movw2
| RelocationKind::Arm64Movw3
| RelocationKind::RiscvPCRelLo12I => {
let reloc_address = start + self.offset() as usize;
let reloc_addend = self.addend() as isize;
let reloc_abs = target_func_address
.checked_add(reloc_addend as u64)
.unwrap();
(reloc_address, reloc_abs)
}
RelocationKind::X86PCRel4 => {
let reloc_address = start + self.offset() as usize;
let reloc_addend = self.addend() as isize;
let reloc_delta_u32 = (target_func_address as u32)
.wrapping_sub(reloc_address as u32)
.checked_add(reloc_addend as u32)
.unwrap();
(reloc_address, reloc_delta_u32 as u64)
}
RelocationKind::X86PCRel8 => {
let reloc_address = start + self.offset() as usize;
let reloc_addend = self.addend() as isize;
let reloc_delta = target_func_address
.wrapping_sub(reloc_address as u64)
.checked_add(reloc_addend as u64)
.unwrap();
(reloc_address, reloc_delta)
}
RelocationKind::X86CallPCRel4 | RelocationKind::X86CallPLTRel4 => {
let reloc_address = start + self.offset() as usize;
let reloc_addend = self.addend() as isize;
let reloc_delta_u32 = (target_func_address as u32)
.wrapping_sub(reloc_address as u32)
.wrapping_add(reloc_addend as u32);
(reloc_address, reloc_delta_u32 as u64)
}
RelocationKind::Arm64Call
| RelocationKind::RiscvCall
| RelocationKind::RiscvPCRelHi20 => {
let reloc_address = start + self.offset() as usize;
let reloc_addend = self.addend() as isize;
let reloc_delta_u32 = target_func_address
.wrapping_sub(reloc_address as u64)
.wrapping_add(reloc_addend as u64);
(reloc_address, reloc_delta_u32)
}
_ => panic!("Relocation kind unsupported"),
}
}
}
impl RelocationLike for Relocation {
fn kind(&self) -> RelocationKind {
self.kind
}
fn reloc_target(&self) -> RelocationTarget {
self.reloc_target
}
fn offset(&self) -> CodeOffset {
self.offset
}
fn addend(&self) -> Addend {
self.addend
}
}
impl RelocationLike for ArchivedRelocation {
fn kind(&self) -> RelocationKind {
self.kind
}
fn reloc_target(&self) -> RelocationTarget {
self.reloc_target
}
fn offset(&self) -> CodeOffset {
self.offset
}
fn addend(&self) -> Addend {
self.addend
}
}
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
#[derive(
RkyvSerialize, RkyvDeserialize, Archive, rkyv::CheckBytes, Debug, Copy, Clone, PartialEq, Eq,
)]
#[archive(as = "Self")]
#[repr(u8)]
pub enum RelocationTarget {
LocalFunc(LocalFunctionIndex),
LibCall(LibCall),
CustomSection(SectionIndex),
}
pub type Relocations = PrimaryMap<LocalFunctionIndex, Vec<Relocation>>;