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;
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
31#[cfg(feature = "std")]
32pub mod abi;
33#[cfg(feature = "debug")]
34mod debug;
35mod dladdr;
36mod dlopen;
37#[cfg(feature = "std")]
38mod init;
39mod loader;
40mod register;
41use alloc::string::{String, ToString};
42use bitflags::bitflags;
43use core::fmt::Display;
44
45pub use elf_loader::Symbol;
46#[cfg(feature = "std")]
47pub use init::init;
48pub use loader::{Dylib, ElfLibrary};
49
50#[cfg(not(any(
51 target_arch = "x86_64",
52 target_arch = "aarch64",
53 target_arch = "riscv64",
54)))]
55compile_error!("unsupport arch");
56
57bitflags! {
58 /// Control how dynamic libraries are loaded.
59 #[derive(Clone, Copy, Debug)]
60 pub struct OpenFlags:u32{
61 /// This is the converse of RTLD_GLOBAL, and the default if neither flag is specified.
62 /// Symbols defined in this shared object are not made available to resolve references in subsequently loaded shared objects.
63 const RTLD_LOCAL = 0;
64 /// Perform lazy binding. Resolve symbols only as the code that references them is executed.
65 /// If the symbol is never referenced, then it is never resolved.
66 const RTLD_LAZY = 1;
67 /// If this value is specified, or the environment variable LD_BIND_NOW is set to a nonempty string,
68 /// all undefined symbols in the shared object are resolved before dlopen() returns.
69 const RTLD_NOW= 2;
70 /// Not supported
71 const RTLD_NOLOAD = 4;
72 /// Not supported
73 const RTLD_DEEPBIND =8;
74 /// The symbols defined by this shared object will be made available for symbol resolution of subsequently loaded shared objects.
75 const RTLD_GLOBAL = 256;
76 /// Do not unload the shared object during dlclose(). Consequently,
77 /// the object's static and global variables are not reinitialized if the object is reloaded with dlopen() at a later time.
78 const RTLD_NODELETE = 4096;
79 /// dlopen-rs custom flag, true local loading, does not involve any global variable operations, no lock, and has the fastest loading speed.
80 const CUSTOM_NOT_REGISTER = 1024;
81 }
82}
83
84/// dlopen-rs error type
85#[derive(Debug)]
86pub enum Error {
87 /// Returned when encountered an io error.
88 #[cfg(feature = "std")]
89 IOError { err: std::io::Error },
90 /// Returned when encountered a loader error.
91 LoaderError { err: elf_loader::Error },
92 /// Returned when failed to find a library.
93 FindLibError { msg: String },
94 /// Returned when failed to find a symbol.
95 FindSymbolError { msg: String },
96}
97
98impl Display for Error {
99 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
100 match self {
101 #[cfg(feature = "std")]
102 Error::IOError { err } => write!(f, "{err}"),
103 Error::LoaderError { err } => write!(f, "{err}"),
104 Error::FindLibError { msg } => write!(f, "{msg}"),
105 Error::FindSymbolError { msg } => write!(f, "{msg}"),
106 }
107 }
108}
109
110#[cfg(feature = "std")]
111impl std::error::Error for Error {
112 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
113 match self {
114 Error::IOError { err } => Some(err),
115 _ => None,
116 }
117 }
118}
119
120impl From<elf_loader::Error> for Error {
121 #[cold]
122 fn from(value: elf_loader::Error) -> Self {
123 Error::LoaderError { err: value }
124 }
125}
126
127#[cfg(feature = "std")]
128impl From<std::io::Error> for Error {
129 #[cold]
130 fn from(value: std::io::Error) -> Self {
131 Error::IOError { err: value }
132 }
133}
134
135#[cold]
136#[inline(never)]
137fn find_lib_error(msg: impl ToString) -> Error {
138 Error::FindLibError {
139 msg: msg.to_string(),
140 }
141}
142
143#[cold]
144#[inline(never)]
145fn find_symbol_error(msg: impl ToString) -> Error {
146 Error::FindSymbolError {
147 msg: msg.to_string(),
148 }
149}
150
151pub type Result<T> = core::result::Result<T, Error>;