#[cfg(feature = "object")]
use super::RelocHelper;
use super::{RelocValue, RelocationValueKind};
#[cfg(feature = "object")]
use crate::elf::ElfShdr;
use crate::{
ByteRepr, RelocReason, Result,
arch::ArchKind,
elf::{ElfLayout, ElfMachine, ElfRelEntry, ElfRelocationType},
image::ModuleScope,
lazy::{LazyBinder, LazyBindingSlots},
memory::VmAddr,
observer::RelocationObserver,
tls::TlsResolver,
};
#[cfg(feature = "object")]
use crate::{elf::ElfRelType, memory::RegionAccess};
pub trait RelocationArch: 'static {
const KIND: ArchKind;
const MACHINE: ElfMachine;
type Layout: ElfLayout;
type Relocation: ByteRepr + ElfRelEntry<Self::Layout> + 'static;
const NONE: ElfRelocationType;
const RELATIVE: ElfRelocationType;
const GOT: ElfRelocationType;
const SYMBOLIC: ElfRelocationType;
const JUMP_SLOT: ElfRelocationType;
const IRELATIVE: ElfRelocationType;
const COPY: ElfRelocationType;
const DTPMOD: ElfRelocationType;
const DTPOFF: ElfRelocationType;
const TPOFF: ElfRelocationType;
const TLSDESC: Option<ElfRelocationType> = None;
const TLS_DTV_OFFSET: usize = 0;
const LAZY_BINDING_SLOTS: LazyBindingSlots;
const SUPPORTS_NATIVE_RUNTIME: bool = false;
#[inline]
fn validate_e_flags(_flags: u32) -> Result<()> {
Ok(())
}
#[inline]
fn is_tlsdesc(r_type: ElfRelocationType) -> bool {
Self::TLSDESC.is_some_and(|tlsdesc| r_type == tlsdesc)
}
#[inline]
fn is_tls(r_type: ElfRelocationType) -> bool {
r_type == Self::DTPMOD
|| r_type == Self::DTPOFF
|| r_type == Self::TPOFF
|| Self::is_tlsdesc(r_type)
}
#[inline]
fn rel_type_to_str(_r_type: ElfRelocationType) -> &'static str {
"UNKNOWN"
}
}
#[cfg(feature = "object")]
#[doc(hidden)]
pub trait ObjectArch: RelocationArch {
type State: Default;
#[allow(private_bounds)]
#[allow(private_interfaces)]
fn prepare_relocation<D, R, Tls, Obs, H, Memory>(
_state: &mut Self::State,
_helper: &mut RelocHelper<'_, D, Self, R, Tls, Obs, H, Memory>,
_shdrs: &[ElfShdr<Self::Layout>],
) -> Result<()>
where
Self: Sized,
D: 'static,
R: RegionAccess,
Tls: TlsResolver<Self>,
Obs: RelocationObserver<Self> + ?Sized,
Memory: crate::memory::ImageMemory,
{
Ok(())
}
#[allow(private_bounds)]
#[allow(private_interfaces)]
fn relocate<D, R, Tls, Obs, H, Memory>(
_state: &mut Self::State,
helper: &mut RelocHelper<'_, D, Self, R, Tls, Obs, H, Memory>,
rel: &ElfRelType<Self>,
_target: &ElfShdr<Self::Layout>,
_pltgot: &mut crate::object::layout::PltGotSection,
) -> Result<()>
where
Self: Sized,
D: 'static,
R: RegionAccess,
Tls: TlsResolver<Self>,
Obs: RelocationObserver<Self> + ?Sized,
Memory: crate::memory::ImageMemory,
{
Err(helper.reloc_error(rel, RelocReason::Unsupported))
}
#[inline]
fn needs_got(_r_type: ElfRelocationType) -> bool
where
Self: Sized,
{
false
}
#[inline]
fn needs_plt(_r_type: ElfRelocationType) -> bool
where
Self: Sized,
{
false
}
}
#[cfg(not(feature = "object"))]
#[doc(hidden)]
pub trait ObjectArch: RelocationArch {}
#[cfg(not(feature = "object"))]
impl<T: RelocationArch> ObjectArch for T {}
pub(crate) trait RelocationValueProvider {
fn relocation_value_kind(
_relocation_type: usize,
) -> core::result::Result<RelocationValueKind, RelocReason> {
Err(RelocReason::Unsupported)
}
fn relocation_value<T>(
input: RelocationValueInput,
skip: impl FnOnce(RelocValue<()>) -> T,
write_addr: impl FnOnce(VmAddr) -> T,
write_word32: impl FnOnce(RelocValue<u32>) -> T,
write_sword32: impl FnOnce(RelocValue<i32>) -> T,
) -> core::result::Result<T, RelocReason> {
let kind = Self::relocation_value_kind(input.relocation_type)?;
match kind {
RelocationValueKind::None => Ok(skip(RelocValue::new(()))),
RelocationValueKind::Address(formula) => {
Ok(write_addr(VmAddr::new(
formula.compute(input.target, input.addend, input.place) as usize,
)))
}
RelocationValueKind::Word32(formula) => {
u32::try_from(formula.compute(input.target, input.addend, input.place))
.map(RelocValue::new)
.map(write_word32)
.map_err(|_| RelocReason::IntConversionOutOfRange)
}
RelocationValueKind::SWord32(formula) => {
i32::try_from(formula.compute(input.target, input.addend, input.place))
.map(RelocValue::new)
.map(write_sword32)
.map_err(|_| RelocReason::IntConversionOutOfRange)
}
}
}
}
#[derive(Clone, Copy)]
pub(crate) struct RelocationValueInput {
pub(crate) relocation_type: usize,
pub(crate) target: usize,
pub(crate) addend: isize,
pub(crate) place: usize,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum BindingMode {
#[default]
Default,
Eager,
Lazy,
}
pub struct RelocateArgs<
'a,
Arch: RelocationArch,
Tls: TlsResolver<Arch>,
Obs: ?Sized,
Binder: ?Sized,
> {
pub(crate) scope: ModuleScope<Arch, Tls>,
pub(crate) binding: BindingMode,
pub(crate) lazy_binder: &'a Binder,
pub(crate) observer: &'a mut Obs,
}
pub trait Relocatable<D = ()>: Sized {
type Output;
type Arch: RelocationArch;
type Tls: TlsResolver<Self::Arch>;
fn relocate<Obs, Binder>(
self,
args: RelocateArgs<'_, Self::Arch, Self::Tls, Obs, Binder>,
) -> Result<Self::Output>
where
Obs: RelocationObserver<Self::Arch> + ?Sized,
Binder: LazyBinder<Self::Arch> + ?Sized;
}