use crate::object::{
ObjectBuilder, ObjectExportsCell, ObjectSections, ObjectSymbolTable, PltGotSection,
SectionSegments,
};
use crate::segment::ElfSegments;
use crate::{
Result,
arch::NativeArch,
elf::{ElfSectionId, Lifecycle},
image::{
CoreRuntime, ElfCore, ElfModule, LoadedCore, ModuleHandle, ModuleSearch, ModuleState,
SymbolExports,
},
lazy::LazyBinder,
memory::{HostRegion, RegionAccess},
observer::RelocationObserver,
relocation::{ObjectArch, Relocatable, RelocateArgs, RelocationArch},
runtime::DomainId,
sync::{Arc, OnceCell, arc_unsize},
tls::{CoreTlsState, TlsResolver},
};
use alloc::boxed::Box;
use core::{fmt::Debug, ops::Deref};
pub struct RawObject<
D: Send + Sync + 'static = (),
Arch: ObjectArch = NativeArch,
R: RegionAccess = HostRegion,
Tls: TlsResolver<Arch> = (),
> {
pub(crate) core: ElfCore<D, Arch, R, Tls>,
pub(crate) symtab: ObjectSymbolTable<Arch::Layout>,
pub(crate) exports: Arc<ObjectExportsCell<Arch::Layout>>,
pub(crate) sections: ObjectSections<Arch::Layout>,
pub(crate) pltgot: PltGotSection,
pub(crate) section_segments: SectionSegments<Arch>,
pub(crate) init_segments: Option<ElfSegments<R>>,
pub(crate) init: Lifecycle,
pub(crate) fini: Lifecycle,
}
impl<D: Send + Sync + 'static, Arch: ObjectArch, R: RegionAccess, Tls: TlsResolver<Arch>> Deref
for RawObject<D, Arch, R, Tls>
{
type Target = ElfCore<D, Arch, R, Tls>;
fn deref(&self) -> &Self::Target {
&self.core
}
}
impl<Tls, D: Send + Sync + 'static, Arch, R> ObjectBuilder<Tls, D, Arch, R>
where
Tls: TlsResolver<Arch>,
Arch: ObjectArch,
R: RegionAccess,
{
pub(crate) fn build_object(mut self) -> RawObject<D, Arch, R, Tls> {
let (segments, init_segments) = self.segments.into_parts();
let pltgot = self.section_segments.take_pltgot();
let exports = Arc::new(ObjectExportsCell::new());
let inner = ElfModule {
runtime: Box::new(CoreRuntime::new::<D, R, Tls>(None)),
executor: self.executor,
state: ModuleState::new(self.source_id, self.domain),
lifecycle: OnceCell::new(),
search: ModuleSearch::new(self.path),
exports: arc_unsize!(Arc::clone(&exports) => dyn SymbolExports<Arch::Layout>),
user_data: self.user_data,
dynamic_info: None,
lazy_lookup: OnceCell::new(),
tls: CoreTlsState::without_module(self.tls_resolver),
segments,
};
let inner = Arc::new(inner);
ElfModule::bind_runtime_owner(&inner);
RawObject {
core: ElfCore { inner },
symtab: self.symtab,
exports,
sections: self.sections,
pltgot,
section_segments: self.section_segments,
init_segments,
init: self.init,
fini: self.fini,
}
}
}
impl<D: Send + Sync + 'static, Arch: ObjectArch, R: RegionAccess, Tls: TlsResolver<Arch>>
RawObject<D, Arch, R, Tls>
{
#[inline]
pub fn sections(&self) -> &ObjectSections<Arch::Layout> {
&self.sections
}
#[inline]
pub(crate) fn section_is_mapped(&self, id: ElfSectionId) -> bool {
self.sections.section_is_mapped(id)
}
}
impl<D: Send + Sync + 'static, Arch: ObjectArch, R: RegionAccess, Tls: TlsResolver<Arch>> Debug
for RawObject<D, Arch, R, Tls>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("RawObject")
.field("core", &self.core)
.finish()
}
}
impl<D: Send + Sync + 'static, Arch, R, Tls> Relocatable<D> for RawObject<D, Arch, R, Tls>
where
Arch: ObjectArch,
R: RegionAccess,
Tls: TlsResolver<Arch>,
{
type Output = LoadedObject<D, Arch, R, Tls>;
type Arch = Arch;
type Tls = Tls;
#[inline]
fn domain_id(&self) -> DomainId {
self.core.state().domain_id()
}
fn relocate<Obs, Binder>(
self,
args: RelocateArgs<'_, Arch, Tls, Obs, Binder>,
) -> Result<Self::Output>
where
Obs: RelocationObserver<Arch> + ?Sized,
Binder: LazyBinder<Arch> + ?Sized,
{
self.relocate_impl(args)
}
}
pub struct LoadedObject<
D: Send + Sync + 'static = (),
Arch: RelocationArch = NativeArch,
R: RegionAccess = HostRegion,
Tls: TlsResolver<Arch> = (),
> {
pub(crate) inner: LoadedCore<D, Arch, R, Tls>,
}
impl<D: Send + Sync + 'static, Arch: RelocationArch, R: RegionAccess, Tls: TlsResolver<Arch>> Clone
for LoadedObject<D, Arch, R, Tls>
{
#[inline]
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl<D: Send + Sync + 'static, Arch: RelocationArch, R: RegionAccess, Tls: TlsResolver<Arch>> Debug
for LoadedObject<D, Arch, R, Tls>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LoadedObject")
.field("inner", &self.inner)
.finish()
}
}
impl<D: Send + Sync + 'static, Arch: RelocationArch, R: RegionAccess, Tls: TlsResolver<Arch>> Deref
for LoadedObject<D, Arch, R, Tls>
{
type Target = LoadedCore<D, Arch, R, Tls>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<D: Send + Sync + 'static, Arch: RelocationArch, R: RegionAccess, Tls: TlsResolver<Arch>>
From<LoadedObject<D, Arch, R, Tls>> for LoadedCore<D, Arch, R, Tls>
{
#[inline]
fn from(object: LoadedObject<D, Arch, R, Tls>) -> Self {
object.inner
}
}
impl<
D: Send + Sync + 'static,
Arch: RelocationArch,
R: RegionAccess,
Tls: TlsResolver<Arch> + 'static,
> From<LoadedObject<D, Arch, R, Tls>> for ModuleHandle<Arch, Tls>
{
#[inline]
fn from(object: LoadedObject<D, Arch, R, Tls>) -> Self {
Self::new(object.inner)
}
}
impl<
D: Send + Sync + 'static,
Arch: RelocationArch,
R: RegionAccess,
Tls: TlsResolver<Arch> + 'static,
> From<&LoadedObject<D, Arch, R, Tls>> for ModuleHandle<Arch, Tls>
{
#[inline]
fn from(object: &LoadedObject<D, Arch, R, Tls>) -> Self {
Self::new(object.inner.clone())
}
}