use super::{ElfCommonPart, Relocated, create_lazy_scope};
use crate::{
CoreComponent, Loader, RelocatedDylib, Result,
arch::ElfPhdr,
loader::Builder,
mmap::Mmap,
object::{ElfObject, ElfObjectAsync},
parse_ehdr_error,
relocation::{LazyScope, UnknownHandler, relocate_impl},
};
use alloc::{boxed::Box, vec::Vec};
use core::{fmt::Debug, marker::PhantomData, ops::Deref};
impl Deref for ElfExec {
type Target = ElfCommonPart;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
pub struct ElfExec {
inner: ElfCommonPart,
}
impl Debug for ElfExec {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ElfExec")
.field("name", &self.inner.name())
.field("needed_libs", &self.inner.needed_libs())
.finish()
}
}
impl ElfExec {
pub fn easy_relocate<'iter, 'scope, 'find, 'lib, F>(
self,
scope: impl IntoIterator<Item = &'iter RelocatedDylib<'scope>>,
pre_find: &'find F,
) -> Result<RelocatedExec<'lib>>
where
F: Fn(&str) -> Option<*const ()>,
'scope: 'iter,
'iter: 'lib,
'find: 'lib,
{
if self.inner.relocation().is_empty() {
return Ok(RelocatedExec {
entry: self.inner.entry,
inner: Relocated {
core: self.inner.into_core_component(),
_marker: PhantomData,
},
});
}
let mut helper = Vec::new();
let temp = unsafe { &RelocatedDylib::from_core_component(self.core_component()) };
if self.inner.symtab().is_some() {
helper.push(unsafe { core::mem::transmute::<&RelocatedDylib, &RelocatedDylib>(temp) });
}
let iter = scope.into_iter();
let local_lazy_scope = if self.is_lazy() {
let mut libs = Vec::new();
iter.for_each(|lib| {
libs.push(lib.downgrade());
helper.push(lib);
});
Some(create_lazy_scope(libs, pre_find))
} else {
iter.for_each(|lib| {
helper.push(lib);
});
None
};
Ok(RelocatedExec {
entry: self.inner.entry,
inner: relocate_impl(
self.inner,
&helper,
pre_find,
&mut |_, _, _| Err(Box::new(())),
local_lazy_scope,
)?,
})
}
pub fn relocate<'iter, 'scope, 'find, 'lib, F>(
self,
scope: impl AsRef<[&'iter RelocatedDylib<'scope>]>,
pre_find: &'find F,
deal_unknown: &mut UnknownHandler,
local_lazy_scope: Option<LazyScope<'lib>>,
) -> Result<RelocatedExec<'lib>>
where
F: Fn(&str) -> Option<*const ()>,
'scope: 'iter,
'iter: 'lib,
'find: 'lib,
{
if self.inner.relocation().is_empty() {
return Ok(RelocatedExec {
entry: self.inner.entry,
inner: Relocated {
core: self.inner.into_core_component(),
_marker: PhantomData,
},
});
}
Ok(RelocatedExec {
entry: self.inner.entry,
inner: relocate_impl(
self.inner,
scope.as_ref(),
pre_find,
deal_unknown,
local_lazy_scope,
)?,
})
}
}
impl Builder {
pub(crate) fn create_exec(self, _phdrs: &[ElfPhdr]) -> ElfExec {
let inner = self.create_inner(&[], false);
ElfExec { inner }
}
}
impl<M: Mmap> Loader<M> {
pub fn easy_load_exec(&mut self, object: impl ElfObject) -> Result<ElfExec> {
self.load_exec(object, None)
}
pub fn load_exec(
&mut self,
mut object: impl ElfObject,
lazy_bind: Option<bool>,
) -> Result<ElfExec> {
let ehdr = self.buf.prepare_ehdr(&mut object)?;
if ehdr.is_dylib() {
return Err(parse_ehdr_error("file type mismatch"));
}
let (builder, phdrs) = self.load_impl(ehdr, object, lazy_bind)?;
Ok(builder.create_exec(phdrs))
}
pub async fn load_exec_async(
&mut self,
mut object: impl ElfObjectAsync,
lazy_bind: Option<bool>,
) -> Result<ElfExec> {
let ehdr = self.buf.prepare_ehdr(&mut object)?;
if ehdr.is_dylib() {
return Err(parse_ehdr_error("file type mismatch"));
}
let (builder, phdrs) = self.load_async_impl(ehdr, object, lazy_bind).await?;
Ok(builder.create_exec(phdrs))
}
}
#[derive(Clone)]
pub struct RelocatedExec<'scope> {
entry: usize,
inner: Relocated<'scope>,
}
impl RelocatedExec<'_> {
#[inline]
pub fn entry(&self) -> usize {
self.entry
}
}
impl Debug for RelocatedExec<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.inner.fmt(f)
}
}
impl Deref for RelocatedExec<'_> {
type Target = CoreComponent;
fn deref(&self) -> &Self::Target {
&self.inner
}
}