use crate::{
Loader, Result,
image::{ElfCore, LoadedCore, builder::ObjectBuilder, common::CoreInner},
input::{ElfReader, IntoElfReader},
loader::{DynLifecycleHandler, LoadHook},
os::Mmap,
relocation::{Relocatable, RelocationHandler, Relocator, StaticRelocation, SymbolLookup},
segment::section::PltGotSection,
sync::{Arc, AtomicBool},
tls::TlsResolver,
};
use alloc::{boxed::Box, vec::Vec};
use core::{borrow::Borrow, fmt::Debug, ops::Deref};
impl<M, H, D, Tls> Loader<M, H, D, Tls>
where
M: Mmap,
H: LoadHook,
D: Default + 'static,
Tls: TlsResolver,
{
pub fn load_object<'a, I>(&mut self, input: I) -> Result<RawObject<D>>
where
I: IntoElfReader<'a>,
{
let object = input.into_reader()?;
self.load_object_impl(object)
}
pub(crate) fn load_object_impl(&mut self, mut object: impl ElfReader) -> Result<RawObject<D>> {
#[cfg(feature = "log")]
log::debug!("Loading object: {}", object.file_name());
let ehdr = self.buf.prepare_ehdr(&mut object)?;
let shdrs = self
.buf
.prepare_shdrs_mut(&ehdr, &mut object)?
.ok_or_else(|| crate::parse_ehdr_error("object file must have section headers"))?;
let builder = self
.inner
.create_object_builder::<M, Tls>(ehdr, shdrs, object)?;
let raw = builder.build();
#[cfg(feature = "log")]
log::info!(
"Loaded object: {} at [0x{:x}-0x{:x}]",
raw.name(),
raw.base(),
raw.base() + raw.core.inner.segments.len()
);
Ok(raw)
}
}
impl<Tls: TlsResolver, D> ObjectBuilder<Tls, D> {
pub(crate) fn build(self) -> RawObject<D> {
let inner = CoreInner {
is_init: AtomicBool::new(false),
name: self.name,
symtab: self.symtab,
fini: None,
fini_array: None,
fini_handler: self.fini_fn,
user_data: self.user_data,
dynamic_info: None,
tls_mod_id: self.tls_mod_id,
tls_tp_offset: self.tls_tp_offset,
tls_unregister: Tls::unregister,
tls_desc_args: Box::new([]),
segments: self.segments,
};
RawObject {
core: ElfCore {
inner: Arc::new(inner),
},
pltgot: self.pltgot,
relocation: self.relocation,
mprotect: self.mprotect,
init_array: self.init_array,
init: self.init_fn,
tls_get_addr: Tls::tls_get_addr as *const () as usize,
}
}
}
pub struct RawObject<D = ()> {
pub(crate) core: ElfCore<D>,
pub(crate) relocation: StaticRelocation,
pub(crate) pltgot: PltGotSection,
pub(crate) mprotect: Box<dyn Fn() -> Result<()>>,
pub(crate) init: DynLifecycleHandler,
pub(crate) init_array: Option<&'static [fn()]>,
pub(crate) tls_get_addr: usize,
}
impl<D> Deref for RawObject<D> {
type Target = ElfCore<D>;
fn deref(&self) -> &Self::Target {
&self.core
}
}
impl<D: 'static> RawObject<D> {
pub fn relocator(self) -> Relocator<Self, (), (), (), (), (), D> {
Relocator::new(self)
}
}
impl<D> Debug for RawObject<D> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("RawObject")
.field("core", &self.core)
.finish()
}
}
impl<D: 'static> Relocatable<D> for RawObject<D> {
type Output = LoadedObject<D>;
fn relocate<PreS, PostS, LazyS, PreH, PostH>(
self,
scope: Vec<LoadedCore<D>>,
pre_find: &PreS,
post_find: &PostS,
pre_handler: &PreH,
post_handler: &PostH,
_lazy: Option<bool>,
_lazy_scope: Option<LazyS>,
) -> Result<Self::Output>
where
PreS: SymbolLookup + ?Sized,
PostS: SymbolLookup + ?Sized,
LazyS: SymbolLookup + Send + Sync + 'static,
PreH: RelocationHandler + ?Sized,
PostH: RelocationHandler + ?Sized,
{
let inner = self.relocate_impl(&scope, pre_find, post_find, pre_handler, post_handler)?;
Ok(LoadedObject { inner })
}
}
#[derive(Debug, Clone)]
pub struct LoadedObject<D> {
pub(crate) inner: LoadedCore<D>,
}
impl<D> Deref for LoadedObject<D> {
type Target = LoadedCore<D>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<D> Borrow<LoadedCore<D>> for LoadedObject<D> {
fn borrow(&self) -> &LoadedCore<D> {
&self.inner
}
}
impl<D> Borrow<LoadedCore<D>> for &LoadedObject<D> {
fn borrow(&self) -> &LoadedCore<D> {
&self.inner
}
}