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>;