use crate::object::{ObjectBuilder, ObjectRelocation, PltGotSection};
use crate::{
Result,
elf::Lifecycle,
loader::DynLifecycleHandler,
relocation::{
RelocAddr, Relocatable, RelocateArgs, RelocationArch, RelocationHandler, Relocator,
},
sync::{Arc, AtomicBool},
tls::{CoreTlsState, TlsResolver},
};
use alloc::boxed::Box;
use core::{borrow::Borrow, fmt::Debug, ops::Deref};
use super::{CoreInner, ElfCore, LoadedCore, ModuleHandle, core::CoreFiniHandler};
pub struct RawObject<D: 'static = (), Arch: RelocationArch = crate::arch::NativeArch> {
pub(crate) core: ElfCore<D, Arch>,
pub(crate) relocation: ObjectRelocation<Arch>,
pub(crate) pltgot: PltGotSection,
pub(crate) mprotect: Box<dyn Fn() -> Result<()>>,
pub(crate) init: DynLifecycleHandler,
pub(crate) init_array: Option<&'static [fn()]>,
}
impl<D: 'static, Arch: RelocationArch> Deref for RawObject<D, Arch> {
type Target = ElfCore<D, Arch>;
fn deref(&self) -> &Self::Target {
&self.core
}
}
impl<D: 'static, Arch: RelocationArch> RawObject<D, Arch> {
pub(crate) fn from_builder<T: TlsResolver>(builder: ObjectBuilder<T, D, Arch>) -> Self {
let inner = CoreInner {
is_init: AtomicBool::new(false),
path: builder.path,
symtab: builder.symtab,
fini: Lifecycle::empty(),
fini_handler: CoreFiniHandler::Native(builder.fini_fn),
user_data: builder.user_data,
dynamic_info: None,
tls: CoreTlsState::new(
builder.tls_mod_id,
builder.tls_tp_offset,
RelocAddr::from_ptr(T::tls_get_addr as *const ()),
T::unregister,
),
segments: builder.segments,
};
Self {
core: ElfCore {
inner: Arc::new(inner),
},
pltgot: builder.pltgot,
relocation: builder.relocation,
mprotect: builder.mprotect,
init_array: builder.init_array,
init: builder.init_fn,
}
}
pub fn relocator(self) -> Relocator<Self, (), (), D, Arch>
where
Self: Relocatable<D, Arch = Arch>,
{
Relocator::new().with_object(self)
}
}
impl<D: 'static, Arch: RelocationArch> Debug for RawObject<D, Arch> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("RawObject")
.field("core", &self.core)
.finish()
}
}
impl<D: 'static, Arch> Relocatable<D> for RawObject<D, Arch>
where
Arch: RelocationArch,
{
type Output = LoadedObject<D, Arch>;
type Arch = Arch;
fn relocate<PreH, PostH>(
self,
args: RelocateArgs<'_, D, Arch, PreH, PostH>,
) -> Result<Self::Output>
where
PreH: RelocationHandler<Arch> + ?Sized,
PostH: RelocationHandler<Arch> + ?Sized,
{
let RelocateArgs {
scope,
pre_handler,
post_handler,
..
} = args;
let inner = self.relocate_impl(scope, pre_handler, post_handler)?;
Ok(LoadedObject { inner })
}
}
#[derive(Debug, Clone)]
pub struct LoadedObject<D: 'static, Arch: RelocationArch = crate::arch::NativeArch> {
pub(crate) inner: LoadedCore<D, Arch>,
}
impl<D: 'static, Arch: RelocationArch> Deref for LoadedObject<D, Arch> {
type Target = LoadedCore<D, Arch>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<D: 'static, Arch: RelocationArch> Borrow<LoadedCore<D, Arch>> for LoadedObject<D, Arch> {
fn borrow(&self) -> &LoadedCore<D, Arch> {
&self.inner
}
}
impl<D: 'static, Arch: RelocationArch> Borrow<LoadedCore<D, Arch>> for &LoadedObject<D, Arch> {
fn borrow(&self) -> &LoadedCore<D, Arch> {
&self.inner
}
}
impl<D: 'static, Arch: RelocationArch> From<LoadedObject<D, Arch>> for LoadedCore<D, Arch> {
#[inline]
fn from(object: LoadedObject<D, Arch>) -> Self {
object.inner
}
}
impl<D: 'static, Arch: RelocationArch> From<&LoadedObject<D, Arch>> for LoadedCore<D, Arch> {
#[inline]
fn from(object: &LoadedObject<D, Arch>) -> Self {
object.inner.clone()
}
}
impl<D: 'static, Arch: RelocationArch> From<LoadedObject<D, Arch>> for ModuleHandle<Arch> {
#[inline]
fn from(object: LoadedObject<D, Arch>) -> Self {
Self::new(object.inner)
}
}
impl<D: 'static, Arch: RelocationArch> From<&LoadedObject<D, Arch>> for ModuleHandle<Arch> {
#[inline]
fn from(object: &LoadedObject<D, Arch>) -> Self {
Self::new(object.inner.clone())
}
}