use crate::{
Result,
image::{ModuleHandle, ModuleScope},
relocation::{
BindingMode, EmulatedArch, Emulator, Relocatable, RelocateArgs, RelocationArch,
RelocationHandler, SupportLazy,
},
sync::Arc,
};
use alloc::boxed::Box;
use core::marker::PhantomData;
pub struct Relocator<
T,
PreH,
PostH,
D: 'static = (),
Arch: RelocationArch = crate::arch::NativeArch,
> {
object: T,
scope: ModuleScope<Arch>,
pre_handler: PreH,
post_handler: PostH,
binding: BindingMode,
emu: Option<Arc<dyn Emulator<Arch>>>,
_marker: PhantomData<fn() -> (D, Arch)>,
}
impl<T, PreH, PostH, D: 'static, Arch> Clone for Relocator<T, PreH, PostH, D, Arch>
where
Arch: RelocationArch,
T: Clone,
PreH: Clone,
PostH: Clone,
{
fn clone(&self) -> Self {
Self {
object: self.object.clone(),
scope: self.scope.clone(),
pre_handler: self.pre_handler.clone(),
post_handler: self.post_handler.clone(),
binding: self.binding,
emu: self.emu.clone(),
_marker: PhantomData,
}
}
}
impl Relocator<(), (), (), ()> {
pub fn new() -> Self {
Self {
object: (),
scope: ModuleScope::empty(),
pre_handler: (),
post_handler: (),
binding: BindingMode::Default,
emu: None,
_marker: PhantomData,
}
}
}
impl<Arch: RelocationArch> Relocator<(), (), (), (), Arch> {
pub fn for_arch<NewArch: RelocationArch>(self) -> Relocator<(), (), (), (), NewArch> {
Relocator {
object: self.object,
scope: ModuleScope::empty(),
pre_handler: self.pre_handler,
post_handler: self.post_handler,
binding: self.binding,
emu: None,
_marker: PhantomData,
}
}
}
impl<T, PreH, PostH, D: 'static, Arch> Relocator<T, PreH, PostH, D, Arch>
where
Arch: RelocationArch,
PreH: RelocationHandler<Arch>,
PostH: RelocationHandler<Arch>,
{
pub fn scope<I, R>(mut self, scope: I) -> Self
where
I: IntoIterator<Item = R>,
R: Into<ModuleHandle<Arch>>,
{
self.scope = ModuleScope::new(scope);
self
}
pub fn shared_scope(mut self, scope: ModuleScope<Arch>) -> Self {
self.scope = scope;
self
}
pub fn extend_scope<I, R>(mut self, scope: I) -> Self
where
I: IntoIterator<Item = R>,
R: Into<ModuleHandle<Arch>>,
{
self.scope = self.scope.extend(scope);
self
}
pub fn with_object<U, NewD>(self, object: U) -> Relocator<U, PreH, PostH, NewD, U::Arch>
where
U: Relocatable<NewD>,
{
Relocator {
object,
scope: ModuleScope::empty(),
pre_handler: self.pre_handler,
post_handler: self.post_handler,
binding: self.binding,
emu: None,
_marker: PhantomData,
}
}
pub fn pre_handler<NewPreH>(self, handler: NewPreH) -> Relocator<T, NewPreH, PostH, D, Arch>
where
NewPreH: RelocationHandler<Arch>,
{
Relocator {
object: self.object,
scope: self.scope,
pre_handler: handler,
post_handler: self.post_handler,
binding: self.binding,
emu: self.emu,
_marker: PhantomData,
}
}
pub fn post_handler<NewPostH>(self, handler: NewPostH) -> Relocator<T, PreH, NewPostH, D, Arch>
where
NewPostH: RelocationHandler<Arch>,
{
Relocator {
object: self.object,
scope: self.scope,
pre_handler: self.pre_handler,
post_handler: handler,
binding: self.binding,
emu: self.emu,
_marker: PhantomData,
}
}
pub fn binding(mut self, binding: BindingMode) -> Self {
self.binding = binding;
self
}
#[inline]
pub fn set_binding(&mut self, binding: BindingMode) {
self.binding = binding;
}
}
impl<T, PreH, PostH, D: 'static, Arch> Relocator<T, PreH, PostH, D, Arch>
where
Arch: EmulatedArch,
{
pub fn emulator<E>(mut self, emu: E) -> Self
where
E: Emulator<Arch>,
{
self.emu = Some(Arc::from(Box::new(emu) as Box<dyn Emulator<Arch>>));
self
}
#[inline]
pub fn emu<E>(self, emu: E) -> Self
where
E: Emulator<Arch>,
{
self.emulator(emu)
}
}
impl<T, PreH, PostH, D: 'static, Arch> Relocator<T, PreH, PostH, D, Arch>
where
T: Relocatable<D, Arch = Arch>,
Arch: RelocationArch,
PreH: RelocationHandler<Arch>,
PostH: RelocationHandler<Arch>,
{
pub fn relocate(self) -> Result<T::Output> {
let Self {
object,
scope,
pre_handler,
post_handler,
binding,
emu,
_marker,
} = self;
object.relocate(RelocateArgs::new(
scope,
binding,
&pre_handler,
&post_handler,
emu,
))
}
}
impl<T, PreH, PostH, D: 'static, Arch> Relocator<T, PreH, PostH, D, Arch>
where
T: SupportLazy,
Arch: RelocationArch,
PreH: RelocationHandler<Arch>,
PostH: RelocationHandler<Arch>,
{
pub fn eager(mut self) -> Self {
self.binding = BindingMode::Eager;
self
}
pub fn lazy(mut self) -> Self {
self.binding = BindingMode::Lazy;
self
}
}