elf_loader 0.16.0

A no_std-friendly ELF loader and runtime linker for Rust.
Documentation
use crate::{
    arch::NativeArch,
    elf::{ElfLayout, ElfSymbol, SymbolLookup, SymbolTable},
    memory::ImageMemory,
    relocation::RelocationArch,
    sync::Arc,
    tls::{TlsModuleId, TlsResolver, TlsTpOffset},
};
use alloc::boxed::Box;
use core::any::Any;

/// Runtime symbol exports for a module.
///
/// Export backends may be backed by an ELF dynamic symbol table, an object export
/// table, kernel export metadata, or a caller-provided synthetic table.
pub trait SymbolExports<L: ElfLayout>: Send + Sync {
    /// Returns exported symbol entries when this backend can enumerate them.
    fn symbols(&self) -> &[ElfSymbol<L>];

    /// Returns the name for a symbol entry from this export table.
    fn symbol_name<'exports>(&'exports self, symbol: &ElfSymbol<L>) -> Option<&'exports str>;

    /// Looks up one exported symbol by name and optional version.
    fn lookup<'exports>(
        &'exports self,
        lookup: &mut SymbolLookup<'_>,
    ) -> Option<&'exports ElfSymbol<L>>;
}

#[inline]
pub(crate) fn exports_handle<L, E>(exports: E) -> Arc<dyn SymbolExports<L>>
where
    L: ElfLayout,
    E: SymbolExports<L> + 'static,
{
    Arc::from(Box::new(exports) as Box<dyn SymbolExports<L>>)
}

impl<L> SymbolExports<L> for SymbolTable<L>
where
    L: ElfLayout,
{
    #[inline]
    fn symbols(&self) -> &[ElfSymbol<L>] {
        self.view().symbols()
    }

    #[inline]
    fn symbol_name<'exports>(&'exports self, symbol: &ElfSymbol<L>) -> Option<&'exports str> {
        Some(self.strtab().get_str(symbol.st_name()))
    }

    #[inline]
    fn lookup<'exports>(
        &'exports self,
        lookup: &mut SymbolLookup<'_>,
    ) -> Option<&'exports ElfSymbol<L>> {
        self.view().lookup_filter(lookup)
    }
}

/// TLS metadata associated with a runtime module.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ModuleTls {
    /// No TLS metadata is available for the module.
    None,
    /// The module has a static TLS block at a fixed thread-pointer offset.
    Static {
        /// Runtime TLS module identifier.
        mod_id: TlsModuleId,
        /// Offset of this module's static TLS block relative to the thread pointer.
        tp_offset: TlsTpOffset,
    },
    /// The module uses dynamic TLS and resolves addresses through `__tls_get_addr`.
    Dynamic {
        /// Runtime TLS module identifier.
        mod_id: TlsModuleId,
    },
}

impl Default for ModuleTls {
    #[inline]
    fn default() -> Self {
        Self::None
    }
}

impl ModuleTls {
    /// No TLS metadata is available for the module.
    pub const NONE: Self = Self::None;

    /// Creates module TLS metadata from the registered dynamic and static TLS values.
    #[inline]
    pub const fn new(mod_id: Option<TlsModuleId>, tp_offset: Option<TlsTpOffset>) -> Self {
        match (mod_id, tp_offset) {
            (Some(mod_id), Some(tp_offset)) => Self::Static { mod_id, tp_offset },
            (Some(mod_id), None) => Self::Dynamic { mod_id },
            _ => Self::None,
        }
    }

    /// Returns the registered TLS module id, when available.
    #[inline]
    pub const fn mod_id(self) -> Option<TlsModuleId> {
        match self {
            Self::None => None,
            Self::Static { mod_id, .. } | Self::Dynamic { mod_id, .. } => Some(mod_id),
        }
    }

    /// Returns the static TLS thread-pointer offset, when available.
    #[inline]
    pub const fn tp_offset(self) -> Option<TlsTpOffset> {
        match self {
            Self::Static { tp_offset, .. } => Some(tp_offset),
            Self::None | Self::Dynamic { .. } => None,
        }
    }
}

/// A runtime module that can satisfy symbol lookups during relocation.
///
/// Implementations may be backed by a loaded ELF image, a synthetic/virtual DSO,
/// or any other module that can expose ELF-like symbol definitions.
pub trait Module<Arch: RelocationArch = NativeArch, Tls: TlsResolver<Arch> = ()>:
    Any + Send + Sync
{
    /// Returns the module name used for diagnostics.
    fn name(&self) -> &str;

    /// Returns the runtime symbol exports for this module.
    fn exports(&self) -> &dyn SymbolExports<Arch::Layout>;

    /// Returns this module's runtime memory view.
    fn memory(&self) -> &dyn ImageMemory;

    /// Returns TLS metadata for this module.
    fn tls(&self) -> ModuleTls {
        ModuleTls::NONE
    }
}

impl<M, Arch, Tls> Module<Arch, Tls> for Arc<M>
where
    M: Module<Arch, Tls> + ?Sized + 'static,
    Arch: RelocationArch,
    Tls: TlsResolver<Arch> + 'static,
{
    #[inline]
    fn name(&self) -> &str {
        (**self).name()
    }

    #[inline]
    fn exports(&self) -> &dyn SymbolExports<Arch::Layout> {
        (**self).exports()
    }

    #[inline]
    fn memory(&self) -> &dyn ImageMemory {
        (**self).memory()
    }

    #[inline]
    fn tls(&self) -> ModuleTls {
        (**self).tls()
    }
}