A dynamic linker fully implemented in Rust.
dlopen-rs
A pure-Rust ELF dynamic linker, dlopen compatibility layer, and experimental Linux rtld.
dlopen-rs provides a Rust-friendly dynamic library loading API and exports libc-compatible entry points such as dlopen, dlsym, dladdr, and dliteratephdr. The project moves ELF loading, dependency resolution, relocation, symbol lookup, and TLS management into Rust, while steadily growing an rtld implementation that can eventually replace glibc ld.so.
Capabilities
- Dynamic loading: Load ELF shared objects from paths or in-memory bytes.
- Dependency resolution: Handle
DT_NEEDED,RPATH,RUNPATH,ld.so.cache, and common system search paths. - Symbol lookup: Provide Rust APIs and C ABI entry points, including global lookup, dependency scopes,
RTLDNEXT, andRTLDDEFAULT. - Relocation: Support regular dynamic relocations, PLT/GOT relocation, lazy binding, and RELR.
- TLS: Support dynamic TLS, static TLS registration, and initial-thread TLS needed during rtld startup.
no_std: Run the core loading path withoutstd, with an optional Linux syscall backend viause-syscall.- Replacement rtld: Build an experimental ELF interpreter that advertises itself as
ld-linux-x86-64.so.2.
Project Status
| Area | Status | | --- | --- | | Rust ElfLibrary API | Usable | | libc-compatible dlopen/dlsym/dladdr/dliteratephdr | Usable | | LD_PRELOAD compatibility library | Usable | | no_std + syscall loading path | Usable, still being refined | | Replacement rtld | Experimental, focused on x86_64 Linux/glibc compatibility |
Installation
For regular Rust programs:
[dependencies]
dlopen-rs = "0.8.0"
For no_std with the syscall backend:
[dependencies]
dlopen-rs = { version = "0.8.0", default-features = false, features = ["use-syscall"] }
Rust API Example
Build the example shared object first:
cargo build --release -p example_dylib
Then run the dlopen-rs example:
cargo run --release --example dlopen
Core usage:
use dlopen_rs::{ElfLibrary, OpenFlags, Result};
fn main() -> Result<()> { let lib = ElfLibrary::dlopen("./target/release/libexample.so", OpenFlags::RTLD_LAZY)?; let add = unsafe { lib.get::<fn(i32, i32) -> i32>("add")? };
println!("add(1, 1) = {}", add(1, 1)); Ok(()) }
LD_PRELOAD Compatibility Library
The cdylib crate builds a libc dlopen-family compatibility library:
cargo build --release -p cdylib
cargo build --release -p example_dylib
cargo build --release --example preload
RUST_LOG=trace \ LD_PRELOAD=./target/release/libdlopen.so \ ./target/release/examples/preload
This is useful for checking how well dlopen-rs can interpose existing dlopen/dlsym calls.
Replacement rtld
The rtld crate builds an experimental ELF interpreter intended to grow into a replacement for glibc ld-linux-x86-64.so.2:
cargo build-rtld
Artifacts are written to:
target/x86_64-unknown-linux-none/release/librtld.so
target/x86_64-unknown-linux-none/release/ld-linux-x86-64.so.2
This path uses x8664-unknown-linux-none, -Z build-std=core,alloc,compilerbuiltins, and custom linker arguments. Use a nightly toolchain, or another toolchain capable of -Z build-std, when building this target.
Development Commands
The repository defines Cargo aliases that keep host/std checks separate from rtld/no_std checks:
cargo check-host
cargo check-rtld
cargo build-rtld
Common validation set:
cargo check-host
cargo check-rtld
cargo check --no-default-features --lib
cargo check --no-default-features --features use-syscall --lib
cargo test --test rtldartifact rtldartifacthasinterpreter_shape
Feature Flags
| Feature | Default | Description | | --- | --- | --- | | std | Yes | Enables standard library integration, host initialization, and ctor support. | | use-syscall | No | Uses the Linux syscall backend, mainly for no_std and rtld paths. | | version | No | Enables ELF symbol version support. |
Architecture Support
| Architecture | Dynamic Loading | Lazy Binding | Replacement rtld | | --- | --- | --- | --- | | x86_64 Linux | Supported | Supported | Experimental | | aarch64 | Supported | Supported | Not enabled | | riscv64 | Supported | Some paths still being validated | Not enabled |
Repository Layout
src/ Rust API, C ABI, loader/register core logic
src/rtld.rs no_std rtld entry points and rtld-specific TLS glue
src/host_init.rs std/host import of objects already loaded by the host ld.so
cdylib/ LD_PRELOAD compatibility library
rtld/ replacement ld.so artifact crate
rtld/impl/ no_std rtld implementation
example-dylib/ example shared object
examples/ API and LD_PRELOAD examples
tests/ integration tests and rtld artifact checks
License
Licensed under the Apache License 2.0.
Contributing
Issues and pull requests are welcome. For GDB/rdebug/linkmap related debugging notes, see TroubleshootingGdb.md.
Minimum Supported Rust Version (MSRV): 1.93.0 or higher.