Skip to main content

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//! ```no_run
14//! # use dlopen_rs::{ElfLibrary, OpenFlags};
15//!
16//! fn main(){
17//!     let path = "./target/release/libexample.so";
18//!     let libexample = ElfLibrary::dlopen(path, OpenFlags::RTLD_LOCAL | OpenFlags::RTLD_LAZY).unwrap();
19//!
20//!     let add = unsafe {
21//!         libexample.get::<fn(i32, i32) -> i32>("add").unwrap()
22//!     };
23//!     println!("{}", add(1,1));
24//! }
25//! ```
26#![allow(clippy::type_complexity)]
27#![warn(
28    clippy::unnecessary_lazy_evaluations,
29    clippy::collapsible_if,
30    clippy::explicit_iter_loop,
31    clippy::manual_assert,
32    clippy::needless_question_mark,
33    clippy::needless_return,
34    clippy::needless_update,
35    clippy::redundant_clone,
36    clippy::redundant_else,
37    clippy::redundant_static_lifetimes
38)]
39#![cfg_attr(not(feature = "std"), no_std)]
40
41extern crate alloc;
42
43#[cfg(all(feature = "std", feature = "use-syscall"))]
44compile_error!("feature \"std\" and feature \"use-syscall\" cannot be enabled at the same time");
45
46pub mod api;
47mod core_impl;
48mod error;
49mod os;
50mod utils;
51
52use bitflags::bitflags;
53
54pub use crate::api::dlsym::{dlsym_default, dlsym_next};
55pub use crate::core_impl::loader::ElfLibrary;
56pub use crate::core_impl::traits::AsFilename;
57pub use crate::error::Error;
58pub use elf_loader::image::Symbol;
59
60#[cfg(not(any(
61    target_arch = "x86_64",
62    target_arch = "aarch64",
63    target_arch = "riscv64",
64)))]
65compile_error!("unsupport arch");
66
67bitflags! {
68    /// Flags that control how dynamic libraries are loaded and resolved.
69    #[derive(Clone, Copy, Debug)]
70    pub struct OpenFlags:u32{
71        /// Symbols in this library are not made available to resolve references in subsequently loaded libraries.
72        const RTLD_LOCAL = 0;
73        /// Perform lazy binding: resolve symbols only as they are executed.
74        const RTLD_LAZY = 1;
75        /// Resolve all symbols before `dlopen` returns.
76        const RTLD_NOW = 2;
77        /// The library is not loaded. This can be used to test if the library is already resident.
78        const RTLD_NOLOAD = 4;
79        /// Prefer the search scope of this library over the global scope for symbol resolution.
80        const RTLD_DEEPBIND = 8;
81        /// Make symbols in this library available for symbol resolution in subsequently loaded libraries.
82        const RTLD_GLOBAL = 256;
83        /// Do not unload the library during `dlclose`.
84        const RTLD_NODELETE = 4096;
85    }
86}
87
88impl OpenFlags {
89    pub(crate) fn is_global(&self) -> bool {
90        self.contains(OpenFlags::RTLD_GLOBAL)
91    }
92
93    pub(crate) fn is_nodelete(&self) -> bool {
94        self.contains(OpenFlags::RTLD_NODELETE)
95    }
96
97    pub(crate) fn is_now(&self) -> bool {
98        self.contains(OpenFlags::RTLD_NOW)
99    }
100
101    pub(crate) fn is_noload(&self) -> bool {
102        self.contains(OpenFlags::RTLD_NOLOAD)
103    }
104
105    pub(crate) fn is_lazy(&self) -> bool {
106        self.contains(OpenFlags::RTLD_LAZY)
107    }
108
109    pub(crate) fn is_deepbind(&self) -> bool {
110        self.contains(OpenFlags::RTLD_DEEPBIND)
111    }
112
113    pub(crate) fn promotable(&self) -> OpenFlags {
114        *self & (OpenFlags::RTLD_GLOBAL | OpenFlags::RTLD_NODELETE)
115    }
116}
117
118pub type Result<T> = core::result::Result<T, Error>;