elf_loader 0.16.0

A no_std-friendly ELF loader and runtime linker for Rust.
Documentation
//! Shared-object image types.
//!
//! Use [`RawDylib`] for a mapped-but-unrelocated shared object. Relocation returns
//! the common [`LoadedCore`] representation.

use crate::{
    Result,
    elf::ElfPhdr,
    image::{ElfCore, LoadedCore, ModuleTls, RawDynamic},
    input::Path,
    lazy::{LazyBinder, SupportLazy},
    memory::{HostRegion, RegionAccess, VmAddr},
    observer::RelocationObserver,
    relocation::{Relocatable, RelocateArgs, RelocationArch},
    segment::ElfSegments,
    tls::TlsResolver,
};
use core::fmt::Debug;

/// A mapped but unrelocated shared object.
///
/// Values of this type are returned by [`crate::Loader::load_dylib`]. They expose
/// ELF metadata immediately and can later be turned into a [`LoadedCore`] by running
/// relocation.
///
/// The optional `Arch` type parameter selects the target architecture used by
/// [`crate::Relocator::run`]. By default it is [`crate::arch::NativeArch`].
pub struct RawDylib<
    D,
    Arch = crate::arch::NativeArch,
    R: RegionAccess = HostRegion,
    Tls: TlsResolver<Arch> = (),
> where
    D: 'static,
    Arch: RelocationArch,
{
    /// The common part containing basic ELF object information.
    pub(crate) inner: RawDynamic<D, Arch, R, Tls>,
}

impl<D, Arch: RelocationArch, R: RegionAccess, Tls: TlsResolver<Arch>> Debug
    for RawDylib<D, Arch, R, Tls>
{
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.debug_struct("RawDylib")
            .field("name", &self.inner.name())
            .field("needed_libs", &self.inner.needed_libs())
            .finish()
    }
}

impl<D: 'static, Arch: RelocationArch, R: RegionAccess, Tls: TlsResolver<Arch>> SupportLazy
    for RawDylib<D, Arch, R, Tls>
{
}

impl<D: 'static, Arch: RelocationArch, R: RegionAccess, Tls: TlsResolver<Arch>> Relocatable<D>
    for RawDylib<D, Arch, R, Tls>
{
    type Output = LoadedCore<D, Arch, R, Tls>;
    type Arch = Arch;
    type Tls = Tls;

    fn relocate<Obs, Binder>(
        self,
        args: RelocateArgs<'_, Arch, Tls, Obs, Binder>,
    ) -> Result<Self::Output>
    where
        Obs: RelocationObserver<Arch> + ?Sized,
        Binder: LazyBinder<Arch> + ?Sized,
    {
        Relocatable::relocate(self.inner, args)
    }
}

impl<D, Arch: RelocationArch, R: RegionAccess, Tls: TlsResolver<Arch>> RawDylib<D, Arch, R, Tls> {
    /// Creates a new `RawDylib` from a `RawDynamic`.
    #[inline]
    pub fn from_dynamic(inner: RawDynamic<D, Arch, R, Tls>) -> Self {
        Self { inner }
    }

    /// Converts this `RawDylib` into a `RawDynamic`.
    #[inline]
    pub fn into_dynamic(self) -> RawDynamic<D, Arch, R, Tls> {
        self.inner
    }

    /// Gets the entry point of the ELF object.
    #[inline]
    pub fn entry(&self) -> usize {
        self.inner.entry()
    }

    /// Gets the core component reference of the ELF object.
    #[inline]
    pub fn core_ref(&self) -> &ElfCore<D, Arch, R, Tls> {
        self.inner.core_ref()
    }

    /// Gets the core component of the ELF object.
    #[inline]
    pub fn core(&self) -> ElfCore<D, Arch, R, Tls> {
        self.inner.core()
    }

    /// Converts this object into its core component.
    #[inline]
    pub fn into_core(self) -> ElfCore<D, Arch, R, Tls> {
        self.inner.into_core()
    }

    /// Whether lazy binding is enabled for the current ELF object
    #[inline]
    pub fn is_lazy(&self) -> bool {
        self.inner.is_lazy()
    }

    /// Returns TLS metadata associated with this image.
    pub fn tls(&self) -> ModuleTls {
        self.inner.tls()
    }

    /// Returns the DT_RPATH value.
    #[inline]
    pub fn rpath(&self) -> Option<&str> {
        self.inner.rpath()
    }

    /// Returns the DT_RUNPATH value.
    #[inline]
    pub fn runpath(&self) -> Option<&str> {
        self.inner.runpath()
    }

    /// Returns the DT_SONAME value.
    #[inline]
    pub fn soname(&self) -> Option<&str> {
        self.inner.soname()
    }

    /// Returns the PT_INTERP value.
    #[inline]
    pub fn interp(&self) -> Option<&str> {
        self.inner.interp()
    }

    /// Returns the loader source path or caller-provided source identifier.
    #[inline]
    pub fn path(&self) -> &Path {
        self.inner.path()
    }

    /// Returns the ELF module identity used for diagnostics.
    #[inline]
    pub fn name(&self) -> &str {
        self.inner.name()
    }

    /// Returns the program headers of the ELF object.
    pub fn phdrs(&self) -> &[ElfPhdr<Arch::Layout>] {
        self.inner.phdrs()
    }

    /// Returns the base address of the loaded ELF object.
    pub fn base(&self) -> VmAddr {
        self.inner.base()
    }

    /// Returns the mapped segments owned by this image.
    pub fn segments(&self) -> &ElfSegments<R> {
        self.inner.segments()
    }

    /// Returns the list of needed library names from the dynamic section.
    pub fn needed_libs(&self) -> &[&str] {
        self.inner.needed_libs()
    }

    /// Returns a reference to the user data.
    pub fn user_data(&self) -> &D {
        self.inner.user_data()
    }

    /// Returns a mutable reference to the user data.
    #[inline]
    pub fn user_data_mut(&mut self) -> Option<&mut D> {
        self.inner.user_data_mut()
    }
}