dlopen_rs/lib.rs
1//!A Rust library that implements a series of interfaces such as `dlopen` and `dlsym`, consistent with the behavior of libc,
2//!providing robust support for dynamic library loading and symbol resolution.
3//!
4//!This library serves four purposes:
5//!1. Provide a pure Rust alternative to musl ld.so or glibc ld.so.
6//!2. Provide loading ELF dynamic libraries support for `#![no_std]` targets.
7//!3. Easily swap out symbols in shared libraries with your own custom symbols at runtime
8//!4. Faster than `ld.so` in most cases (loading dynamic libraries and getting symbols)
9//!
10//!Currently, it supports `x86_64`, `RV64`, and `AArch64` architectures.
11//!
12//! # Examples
13//! ```
14//! # use dlopen_rs::{ElfLibrary, OpenFlags};
15//! use std::path::Path;
16//!
17//! fn main(){
18//! dlopen_rs::init();
19//! let path = Path::new("./target/release/libexample.so");
20//! let libexample = ElfLibrary::dlopen(path, OpenFlags::RTLD_LOCAL | OpenFlags::RTLD_LAZY).unwrap();
21//!
22//! let add = unsafe {
23//! libexample.get::<fn(i32, i32) -> i32>("add").unwrap()
24//! };
25//! println!("{}", add(1,1));
26//! }
27//! ```
28#![cfg_attr(not(feature = "std"), no_std)]
29extern crate alloc;
30
31pub mod abi;
32#[cfg(feature = "debug")]
33mod debug;
34mod dl_iterate_phdr;
35mod dladdr;
36mod dlopen;
37mod dlsym;
38#[cfg(feature = "std")]
39mod init;
40mod loader;
41mod register;
42use alloc::{
43 boxed::Box,
44 string::{String, ToString},
45};
46use bitflags::bitflags;
47use core::{any::Any, fmt::Display};
48
49pub use elf_loader::Symbol;
50#[cfg(feature = "std")]
51pub use init::init;
52pub use loader::{Dylib, ElfLibrary};
53
54#[cfg(not(any(
55 target_arch = "x86_64",
56 target_arch = "aarch64",
57 target_arch = "riscv64",
58)))]
59compile_error!("unsupport arch");
60
61bitflags! {
62 /// Control how dynamic libraries are loaded.
63 #[derive(Clone, Copy, Debug)]
64 pub struct OpenFlags:u32{
65 /// This is the converse of RTLD_GLOBAL, and the default if neither flag is specified.
66 /// Symbols defined in this shared object are not made available to resolve references in subsequently loaded shared objects.
67 const RTLD_LOCAL = 0;
68 /// Perform lazy binding. Resolve symbols only as the code that references them is executed.
69 /// If the symbol is never referenced, then it is never resolved.
70 const RTLD_LAZY = 1;
71 /// If this value is specified, or the environment variable LD_BIND_NOW is set to a nonempty string,
72 /// all undefined symbols in the shared object are resolved before dlopen() returns.
73 const RTLD_NOW= 2;
74 /// Not supported
75 const RTLD_NOLOAD = 4;
76 /// Not supported
77 const RTLD_DEEPBIND =8;
78 /// The symbols defined by this shared object will be made available for symbol resolution of subsequently loaded shared objects.
79 const RTLD_GLOBAL = 256;
80 /// Do not unload the shared object during dlclose(). Consequently,
81 /// the object's static and global variables are not reinitialized if the object is reloaded with dlopen() at a later time.
82 const RTLD_NODELETE = 4096;
83 /// dlopen-rs custom flag, true local loading, does not involve any global variable operations, no lock, and has the fastest loading speed.
84 const CUSTOM_NOT_REGISTER = 1024;
85 }
86}
87
88/// dlopen-rs error type
89#[derive(Debug)]
90pub enum Error {
91 /// Returned when encountered an io error.
92 #[cfg(feature = "std")]
93 IOError { err: std::io::Error },
94 /// Returned when encountered a loader error.
95 LoaderError { err: elf_loader::Error },
96 /// Returned when failed to find a library.
97 FindLibError { msg: String },
98 /// Returned when failed to find a symbol.
99 FindSymbolError { msg: String },
100 /// Returned when failed to iterate phdr.
101 IteratorPhdrError { err: Box<dyn Any> },
102}
103
104impl Display for Error {
105 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
106 match self {
107 #[cfg(feature = "std")]
108 Error::IOError { err } => write!(f, "{err}"),
109 Error::LoaderError { err } => write!(f, "{err}"),
110 Error::FindLibError { msg } => write!(f, "{msg}"),
111 Error::FindSymbolError { msg } => write!(f, "{msg}"),
112 Error::IteratorPhdrError { err } => write!(f, "{:?}", err),
113 }
114 }
115}
116
117#[cfg(feature = "std")]
118impl std::error::Error for Error {
119 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
120 match self {
121 Error::IOError { err } => Some(err),
122 _ => None,
123 }
124 }
125}
126
127impl From<elf_loader::Error> for Error {
128 #[cold]
129 fn from(value: elf_loader::Error) -> Self {
130 Error::LoaderError { err: value }
131 }
132}
133
134#[cfg(feature = "std")]
135impl From<std::io::Error> for Error {
136 #[cold]
137 fn from(value: std::io::Error) -> Self {
138 Error::IOError { err: value }
139 }
140}
141
142#[cold]
143#[inline(never)]
144fn find_lib_error(msg: impl ToString) -> Error {
145 Error::FindLibError {
146 msg: msg.to_string(),
147 }
148}
149
150#[cold]
151#[inline(never)]
152fn find_symbol_error(msg: impl ToString) -> Error {
153 Error::FindSymbolError {
154 msg: msg.to_string(),
155 }
156}
157
158pub type Result<T> = core::result::Result<T, Error>;