#[cfg(feature = "object")]
use super::RelocHelper;
use super::{HandleResult, RelocValue, RelocationValueKind};
#[cfg(feature = "object")]
use crate::elf::{ElfRelType, ElfShdr};
#[cfg(feature = "object")]
use crate::object::layout::PltGotSection;
use crate::{
ByteRepr, RelocReason, Result,
arch::ArchKind,
elf::{ElfLayout, ElfMachine, ElfRelEntry, ElfRelocationType, ElfTarget, ElfWord},
image::{GlobalScope, LocalScope},
lazy::{LazyBinder, LazyPlacement},
memory::{ImageMemory, ImageMemoryExt, RegionAccess, VmAddr},
observer::{RelocationEvent, RelocationObserver},
relocation::SymbolRegistry,
runtime::DomainId,
sync::Arc,
tls::TlsResolver,
};
pub trait RelocationArch: 'static {
const KIND: ArchKind;
const MACHINE: ElfMachine;
type Layout: ElfLayout;
const TARGET: ElfTarget = ElfTarget::new(
<Self::Layout as ElfLayout>::CLASS,
<Self::Layout as ElfLayout>::DATA_ENCODING,
Self::MACHINE,
);
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: Option<ElfRelocationType>;
const COPY: Option<ElfRelocationType>;
const DTPMOD: Option<ElfRelocationType>;
const DTPOFF: ElfRelocationType;
const TPOFF: ElfRelocationType;
const TLSDESC: Option<ElfRelocationType> = None;
const TLS_DTV_OFFSET: usize = 0;
const LAZY_BINDING: LazyPlacement;
const SUPPORTS_NATIVE_RUNTIME: bool = false;
const SUPPORTS_SECTION_REORDER: bool = false;
#[inline]
fn validate_e_flags(_flags: u32) -> Result<()> {
Ok(())
}
#[inline]
fn apply_relative<Memory>(rel: &Self::Relocation, memory: &Memory) -> Result<()>
where
Self: Sized,
Memory: ImageMemory,
<Self::Layout as ElfLayout>::Word: ByteRepr,
{
let base = memory.base();
let place = base + rel.r_offset();
let addend = rel.read_addend(memory, place)?;
let value = base.wrapping_add_signed(addend);
let word = <Self::Layout as ElfLayout>::Word::from_usize(value.get());
unsafe { memory.write_value(place, word) }
}
#[inline]
fn is_tls(r_type: ElfRelocationType) -> bool {
Self::DTPMOD == Some(r_type)
|| Self::DTPOFF == r_type
|| Self::TPOFF == r_type
|| Self::TLSDESC == Some(r_type)
}
#[inline]
fn relocate_custom<D, R, Tls, H>(
_event: &mut RelocationEvent<'_, D, Self, R, Tls, H>,
) -> Result<HandleResult>
where
Self: Sized,
D: Send + Sync + 'static,
R: RegionAccess,
Tls: TlsResolver<Self>,
{
Ok(HandleResult::Unhandled)
}
#[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: Send + Sync + 'static,
R: RegionAccess,
Tls: TlsResolver<Self>,
Obs: RelocationObserver<Self> + ?Sized,
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 PltGotSection,
) -> Result<()>
where
Self: Sized,
D: Send + Sync + 'static,
R: RegionAccess,
Tls: TlsResolver<Self>,
Obs: RelocationObserver<Self> + ?Sized,
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,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum LookupOrder {
#[default]
GlobalFirst,
LocalFirst,
}
pub struct RelocateArgs<
'a,
Arch: RelocationArch,
Tls: TlsResolver<Arch>,
Obs: ?Sized,
Binder: ?Sized,
> {
pub(crate) scope: LocalScope<Arch, Tls>,
pub(crate) global: Option<GlobalScope<Arch, Tls>>,
pub(crate) symbols: Option<Arc<SymbolRegistry<Arch, Tls>>>,
pub(crate) binding: BindingMode,
pub(crate) lookup_order: LookupOrder,
pub(crate) run_init: bool,
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 domain_id(&self) -> DomainId;
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;
}