| Crates.io | dlopen-rs |
| lib.rs | dlopen-rs |
| version | 0.7.3 |
| created_at | 2024-07-25 06:00:18.119694+00 |
| updated_at | 2025-03-04 18:46:08.8002+00 |
| description | A dynamic linker fully implemented in Rust. |
| homepage | |
| repository | https://github.com/weizhiao/dlopen-rs |
| max_upload_size | |
| id | 1314738 |
| size | 146,822 |
English | 中文
dlopen-rs is a dynamic linker fully implemented in Rust, providing a set of Rust-friendly interfaces for manipulating dynamic libraries, as well as C-compatible interfaces consistent with libc behavior.
You can use dlopen-rs as a replacement for libloading to load dynamic libraries. It also allows replacing libc's dlopen, dlsym, dl_iterate_phdr and other functions with implementations from dlopen-rs using LD_PRELOAD without code modifications.
# Compile the library as a dynamic library
$ cargo build -r -p cdylib
# Compile test cases
$ cargo build -r -p dlopen-rs --example preload
# Replace libc implementations with ours
$ RUST_LOG=trace LD_PRELOAD=./target/release/libdlopen.so ./target/release/examples/preload
ld.so for dynamic library loading and symbol resolution.CUSTOM_NOT_REGISTER flag in OpenFlags enables multiple coexisting copies of a library (identical or modified) in memory, facilitating runtime dynamic library hot-swapping.| Feature | Default | Description |
|---|---|---|
| std | Yes | Enable std |
| debug | No | Enable this to use gdb/lldb for debugging loaded dynamic libraries. Note that only dynamic libraries loaded using dlopen-rs can be debugged with gdb. |
| mmap | Yes | Enable default implementation on platforms with mmap |
| version | No | Activate specific versions of symbols for dynamic library loading |
| tls | Yes | Enable this to use thread local storage. |
| unwinding | No | Enable this to use the exception handling mechanism provided by dlopen-rs. |
| libgcc | Yes | Enable this if the program uses libgcc to handle exceptions. |
| libunwind | No | Enable this if the program uses libunwind to handle exceptions. |
| Arch | Support | Lazy Binding | Test |
|---|---|---|---|
| x86_64 | ✅ | ✅ | ✅(CI) |
| aarch64 | ✅ | ✅ | ✅(QEMU) |
| riscv64 | ✅ | ✅ | ✅(QEMU) |
| loongarch64 | ✅ | ❌ | ❌ |
The dlopen interface is used to load dynamic libraries, and the dl_iterate_phdr interface is used to iterate through the already loaded dynamic libraries. Additionally, this library uses the log crate, and you can use your preferred library to output log information to view the workflow of dlopen-rs. In the examples of this library, the env_logger crate is used.
use dlopen_rs::ELFLibrary;
use std::path::Path;
fn main() {
std::env::set_var("RUST_LOG", "trace");
env_logger::init();
dlopen_rs::init();
let path = Path::new("./target/release/libexample.so");
let libexample =
ElfLibrary::dlopen(path, OpenFlags::RTLD_LOCAL | OpenFlags::RTLD_LAZY).unwrap();
let add = unsafe { libexample.get::<fn(i32, i32) -> i32>("add").unwrap() };
println!("{}", add(1, 1));
let print = unsafe { libexample.get::<fn(&str)>("print").unwrap() };
print("dlopen-rs: hello world");
let dl_info = ElfLibrary::dladdr(print.into_raw() as usize).unwrap();
println!("{:?}", dl_info);
ElfLibrary::dl_iterate_phdr(|info| {
println!(
"iterate dynamic library: {}",
unsafe { CStr::from_ptr(info.dlpi_name).to_str().unwrap() }
);
Ok(())
})
.unwrap();
}
Fine-grained control of the load flow of the dynamic library, you can replace certain functions in the dynamic library that need to be relocated with your own implementation. In the following example, we replace malloc with mymalloc in the dynamic library and turn on lazy binding.
use dlopen_rs::ELFLibrary;
use libc::size_t;
use std::{ffi::c_void, path::Path};
extern "C" fn mymalloc(size: size_t) -> *mut c_void {
println!("malloc:{}bytes", size);
unsafe { libc::malloc(size) }
}
fn main() {
std::env::set_var("RUST_LOG", "debug");
env_logger::init();
dlopen_rs::init();
let path = Path::new("./target/release/libexample.so");
let libc = ElfLibrary::load_existing("libc.so.6").unwrap();
let libgcc = ElfLibrary::load_existing("libgcc_s.so.1").unwrap();
let libexample = ElfLibrary::from_file(path, OpenFlags::CUSTOM_NOT_REGISTER)
.unwrap()
.relocate_with(&[libc, libgcc], &|name: &str| {
if name == "malloc" {
return Some(mymalloc as _);
} else {
return None;
}
})
.unwrap();
let add = unsafe { libexample.get::<fn(i32, i32) -> i32>("add").unwrap() };
println!("{}", add(1, 1));
let print = unsafe { libexample.get::<fn(&str)>("print").unwrap() };
print("dlopen-rs: hello world");
}
Rust 1.85 or higher.
If you encounter any issues during use, feel free to raise them on GitHub. We warmly welcome everyone to contribute code to help improve the functionality of dlopen-rs. 😊