elf_loader/lib.rs
1//! # Relink
2//!
3//! Relink is a high-performance, `no_std`-friendly ELF loader and runtime linker for Rust.
4//! It maps ELF images from files or memory, performs relocations at runtime, and exposes
5//! typed symbol lookups with Rust lifetimes.
6//!
7//! ## Start with [`Loader`]
8//!
9//! - Use [`Loader::load`] to auto-detect whether the input is a dylib, executable, or
10//! relocatable object.
11//! - Use [`Loader::scan`] to classify executable or dynamic ELF metadata without mapping it.
12//! - Use [`Loader::load_dylib`] or [`Loader::load_exec`] when you want strict type checks.
13//! - Use [`Loader::load_dynamic`] when you want any `PT_DYNAMIC` image, including a dynamic
14//! `ET_EXEC`.
15//! - Use [`Loader::scan`] and [`Loader::load_scanned_dynamic`] to split dynamic metadata
16//! discovery from mapping.
17//! - Use `Loader::load_object` to load `ET_REL` object files when the `object` feature is enabled.
18//! - Inputs can come from file paths, [`input::Path`] / [`input::PathBuf`], raw bytes,
19//! [`input::ElfFile`], or [`input::ElfBinary`].
20//!
21//! ## Highlights
22//!
23//! - Safer symbol lifetimes. Typed symbols borrow the loaded image, so they cannot outlive
24//! the library that produced them.
25//! - Hybrid linking. Compose `.so`, `.o`, and synthetic modules at runtime with `scope()` and
26//! `extend_scope()`.
27//! - Explicit dependency loading. Build your own dependency policy with an
28//! actual [`Loader`], [`linker::KeyResolver`], [`linker::Linker`], and
29//! [`linker::LinkContext`].
30//! - Deep customization. Inject host or bridge symbols with
31//! [`image::SyntheticModule`], intercept relocations with handlers, and
32//! inspect segments with [`loader::LoadHook`].
33//! - Optional advanced features. TLS relocation handling, lazy binding, relocatable object
34//! loading, logging, and versioned symbol lookup are feature-gated.
35//!
36//! ## Example
37//!
38//! ```rust,no_run
39//! use elf_loader::{
40//! Loader, Result,
41//! image::{SyntheticSymbol, SyntheticModule},
42//! };
43//!
44//! extern "C" fn host_double(value: i32) -> i32 {
45//! value * 2
46//! }
47//!
48//! fn main() -> Result<()> {
49//! let host = SyntheticModule::new(
50//! "__host",
51//! [SyntheticSymbol::function("host_double", host_double as *const ())],
52//! );
53//!
54//! let lib = Loader::new()
55//! .load_dylib("path/to/plugin.so")?
56//! .relocator()
57//! .scope([host])
58//! .relocate()?;
59//!
60//! let run = unsafe {
61//! lib.get::<extern "C" fn(i32) -> i32>("run")
62//! .expect("symbol `run` not found")
63//! };
64//! assert_eq!(run(21), 42);
65//! Ok(())
66//! }
67//! ```
68//!
69//! ## Loading Dependencies With [`linker::Linker`]
70//!
71//! Use [`linker::Linker::load`] when you want a reusable [`linker::LinkContext`]
72//! and resolver-driven `DT_NEEDED` dependency loading. The built-in
73//! [`linker::SearchPathResolver`] covers the common filesystem search-path case;
74//! implement [`linker::KeyResolver`] when dependencies come from memory,
75//! package stores, or another registry.
76//!
77//! ```rust,no_run
78//! use elf_loader::{
79//! Result,
80//! input::PathBuf,
81//! linker::{LinkContext, Linker, SearchPathResolver},
82//! };
83//!
84//! fn main() -> Result<()> {
85//! let root = PathBuf::from("path/to/plugin.so");
86//! let mut context: LinkContext<PathBuf, ()> = LinkContext::new();
87//!
88//! let loaded = Linker::new()
89//! .resolver(SearchPathResolver::new())
90//! .load(&mut context, root)?;
91//!
92//! let run = unsafe {
93//! loaded
94//! .get::<extern "C" fn() -> i32>("run")
95//! .expect("symbol `run` not found")
96//! };
97//! let _ = run();
98//!
99//! Ok(())
100//! }
101//! ```
102//!
103//! ## Feature Flags
104//!
105//! - `tls` (default): enables TLS relocation handling. For TLS-using modules, start from
106//! [`Loader::with_default_tls_resolver`] or provide a custom TLS resolver.
107//! - `lazy-binding`: enables `Relocator::lazy` and PLT/GOT lazy binding.
108//! - `object`: enables `Loader::load_object` and relocatable object (`ET_REL`) loading.
109//! - `version`: enables version-aware symbol lookup via `ElfCore::get_version`.
110//! - `log`, `portable-atomic`, and `use-syscall`: optional integrations for diagnostics and
111//! specialized targets.
112//!
113//! ## More
114//!
115//! - The [`examples`](https://github.com/weizhiao/elf_loader/tree/main/examples) directory
116//! covers loading from memory, `Linker::load`, scan-first linking, lifecycle hooks,
117//! relocation handlers, and object loading.
118//! - The crate currently targets `x86_64`, `x86`, `aarch64`, `arm`, `riscv64`, `riscv32`,
119//! and `loongarch64`.
120//! - Relocatable object support is currently centered on `x86_64`.
121#![cfg_attr(docsrs, feature(doc_cfg))]
122#![no_std]
123#![warn(
124 clippy::unnecessary_wraps,
125 clippy::unnecessary_lazy_evaluations,
126 clippy::collapsible_if,
127 clippy::cast_lossless,
128 clippy::explicit_iter_loop,
129 clippy::manual_assert,
130 clippy::needless_question_mark,
131 clippy::needless_return,
132 clippy::needless_update,
133 clippy::redundant_clone,
134 clippy::redundant_else,
135 clippy::redundant_static_lifetimes
136)]
137#![allow(
138 clippy::len_without_is_empty,
139 clippy::unnecessary_cast,
140 clippy::uninit_vec
141)]
142extern crate alloc;
143
144/// Compile-time check for supported architectures
145#[cfg(not(any(
146 target_arch = "x86_64",
147 target_arch = "aarch64",
148 target_arch = "riscv64",
149 target_arch = "riscv32",
150 target_arch = "loongarch64",
151 target_arch = "x86",
152 target_arch = "arm",
153)))]
154compile_error!(
155 "Unsupported target architecture. Supported architectures: x86_64, aarch64, riscv64, riscv32, loongarch64, x86, arm"
156);
157
158mod aligned_bytes;
159pub mod arch;
160pub mod elf;
161mod entity;
162mod error;
163pub mod image;
164pub mod input;
165pub mod linker;
166pub mod loader;
167mod logging;
168#[cfg(feature = "object")]
169mod object;
170pub mod os;
171pub mod relocation;
172mod segment;
173mod sync;
174pub mod tls;
175
176pub(crate) use aligned_bytes::AlignedBytes;
177pub(crate) use error::*;
178
179pub use aligned_bytes::ByteRepr;
180pub use error::{
181 CustomError, Error, IoError, LinkerError, MmapError, ParseDynamicError, ParseEhdrError,
182 ParsePhdrError, RelocationError, RelocationFailure, TlsError,
183};
184pub use loader::Loader;
185
186/// A type alias for `Result`s returned by `elf_loader` functions.
187///
188/// This is a convenience alias that eliminates the need to repeatedly specify
189/// the `Error` type in function signatures.
190pub type Result<T> = core::result::Result<T, Error>;