use super::lifecycle::{LifecycleHandlers, LifecycleRunner};
use crate::{
arch::NativeArch,
elf::{ElfRelEntry, ElfRelType, ElfSymbol, HashTable, SymbolEntry, SymbolTableView},
image::{ElfCore, LocalScope},
input::Path,
lazy::LazyValues,
memory::{HostRegion, RegionAccess, VmAddr},
relocation::{BindingDeps, RelocationArch, SymDef, SymbolResolver},
tls::TlsResolver,
};
pub struct RelocationEvent<
'a,
D: Send + Sync + 'static,
Arch: RelocationArch = NativeArch,
R: RegionAccess = HostRegion,
Tls: TlsResolver<Arch> = (),
H = HashTable<<Arch as RelocationArch>::Layout>,
> {
core: &'a ElfCore<D, Arch, R, Tls>,
rel: &'a ElfRelType<Arch>,
resolver: &'a SymbolResolver<'a, Arch, Tls>,
bindings: &'a mut BindingDeps,
symbols: SymbolTableView<'a, Arch::Layout, H>,
}
impl<'a, D: Send + Sync + 'static, Arch: RelocationArch, R: RegionAccess, Tls: TlsResolver<Arch>, H>
RelocationEvent<'a, D, Arch, R, Tls, H>
{
#[inline]
pub(crate) const fn new(
core: &'a ElfCore<D, Arch, R, Tls>,
rel: &'a ElfRelType<Arch>,
resolver: &'a SymbolResolver<'a, Arch, Tls>,
bindings: &'a mut BindingDeps,
symbols: SymbolTableView<'a, Arch::Layout, H>,
) -> Self {
Self {
core,
rel,
resolver,
bindings,
symbols,
}
}
#[inline]
pub fn rel(&self) -> &ElfRelType<Arch> {
self.rel
}
#[inline]
pub fn lib(&self) -> &ElfCore<D, Arch, R, Tls> {
self.core
}
#[inline]
pub fn scope(&self) -> &LocalScope<Arch, Tls> {
self.resolver.scope()
}
#[inline]
pub fn lazy(&self) -> Option<LazyValues> {
self.lib().inner.runtime.lazy_values()
}
#[inline]
pub fn symbol(&self, r_sym: usize) -> SymbolEntry<'a, Arch::Layout> {
self.symbols.entry(r_sym)
}
#[inline]
pub fn relocation_symbol(&self) -> Option<SymbolEntry<'a, Arch::Layout>> {
let r_sym = self.rel.r_symbol();
(r_sym != 0).then(|| self.symbol(r_sym))
}
#[inline]
pub fn bind_symdef(&mut self, r_sym: usize) -> Option<SymDef<'_, Arch, Tls>> {
let definition = self.resolver.find(&self.symbol(r_sym));
if let Some(definition) = &definition {
self.bindings.record(definition.effect());
}
definition
}
}
pub struct SymbolBindingEvent<
'a,
D: Send + Sync + 'static,
Arch: RelocationArch = NativeArch,
R: RegionAccess = HostRegion,
Tls: TlsResolver<Arch> = (),
> {
core: &'a ElfCore<D, Arch, R, Tls>,
rel: Option<&'a ElfRelType<Arch>>,
symbol: &'a ElfSymbol<Arch::Layout>,
symbol_name: &'a str,
resolved: Option<VmAddr>,
}
impl<'a, D: Send + Sync + 'static, Arch: RelocationArch, R: RegionAccess, Tls: TlsResolver<Arch>>
SymbolBindingEvent<'a, D, Arch, R, Tls>
{
#[inline]
pub(crate) const fn new(
core: &'a ElfCore<D, Arch, R, Tls>,
rel: Option<&'a ElfRelType<Arch>>,
symbol: &'a ElfSymbol<Arch::Layout>,
symbol_name: &'a str,
resolved: Option<VmAddr>,
) -> Self {
Self {
core,
rel,
symbol,
symbol_name,
resolved,
}
}
#[inline]
pub const fn core(&self) -> &'a ElfCore<D, Arch, R, Tls> {
self.core
}
#[inline]
pub const fn rel(&self) -> Option<&ElfRelType<Arch>> {
self.rel
}
#[inline]
pub const fn symbol(&self) -> &ElfSymbol<Arch::Layout> {
self.symbol
}
#[inline]
pub const fn symbol_name(&self) -> &'a str {
self.symbol_name
}
#[inline]
pub const fn resolved_addr(&self) -> Option<VmAddr> {
self.resolved
}
#[inline]
pub fn set_resolved_addr(&mut self, addr: VmAddr) {
self.resolved = Some(addr);
}
#[inline]
pub fn clear_resolved_addr(&mut self) {
self.resolved = None;
}
#[inline]
pub(crate) const fn into_resolved_addr(self) -> Option<VmAddr> {
self.resolved
}
}
pub struct DynamicRelocatedEvent<
'a,
D: Send + Sync + 'static,
Arch: RelocationArch = NativeArch,
R: RegionAccess = HostRegion,
Tls: TlsResolver<Arch> = (),
> {
core: &'a ElfCore<D, Arch, R, Tls>,
dynamic_addr: VmAddr,
lifecycle: LifecycleHandlers,
}
impl<'a, D: Send + Sync + 'static, Arch: RelocationArch, R: RegionAccess, Tls: TlsResolver<Arch>>
DynamicRelocatedEvent<'a, D, Arch, R, Tls>
{
#[inline]
pub(crate) const fn new(
core: &'a ElfCore<D, Arch, R, Tls>,
dynamic_addr: VmAddr,
initializer: LifecycleRunner,
finalizer: LifecycleRunner,
) -> Self {
Self {
core,
dynamic_addr,
lifecycle: LifecycleHandlers::new(initializer, finalizer),
}
}
#[inline]
pub const fn core(&self) -> &ElfCore<D, Arch, R, Tls> {
self.core
}
#[inline]
pub fn path(&self) -> &Path {
self.core.path()
}
#[inline]
pub fn name(&self) -> &str {
self.core.name()
}
#[inline]
pub fn base(&self) -> VmAddr {
self.core.segments().base()
}
#[inline]
pub const fn dynamic_addr(&self) -> VmAddr {
self.dynamic_addr
}
#[inline]
pub fn lifecycle_mut(&mut self) -> &mut LifecycleHandlers {
&mut self.lifecycle
}
#[inline]
pub(crate) fn into_lifecycle(self) -> LifecycleHandlers {
self.lifecycle
}
}