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
//!A pure-rust library designed for loading ELF dynamic libraries from memory or from files.
//!
//!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)
//!
//!Additional, it integrates seamlessly with the system’s dynamic linker in `std` environments when the `ldso` feature is enabled.
//!Currently, it supports `x86_64`, `RV64`, and `AArch64` architectures.
//!
//! # Examples
//! ```
//! use dlopen_rs::ELFLibrary;
//! use std::path::Path;
//! let path = Path::new("./target/release/libexample.so");
//!	let libc = ELFLibrary::sys_load("libc.so.6").unwrap();
//!	let libgcc = ELFLibrary::sys_load("libgcc_s.so.1").unwrap();
//! let libexample = ELFLibrary::from_file(path, None)
//!		.unwrap()
//!		.relocate(&[libgcc, libc])
//!     .finish()
//!		.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;
mod dlopen;
#[cfg(feature = "ldso")]
mod ldso;
mod loader;
mod register;
use alloc::string::{String, ToString};
use core::fmt::Display;

pub use elf_loader::{RelocatedDylib, Symbol};
pub use loader::ElfLibrary;

#[cfg(not(any(
    target_arch = "x86_64",
    target_arch = "aarch64",
    target_arch = "riscv64",
)))]
compile_error!("unsupport arch");

/// 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 },
}

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}"),
        }
    }
}

#[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(),
    }
}

pub type Result<T> = core::result::Result<T, Error>;