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