From ad6e6ffef2263bfb74755b825722c700e0ee4165 Mon Sep 17 00:00:00 2001 From: Michael Mikovsky <77305074+Astatin3@users.noreply.github.com> Date: Wed, 5 Nov 2025 22:59:01 -0700 Subject: [PATCH] Module object --- unshell-logger/src/lib.rs | 2 + unshell-module-load/Cargo.toml | 11 ++++ unshell-module-load/src/main.rs | 98 ++++++++++++++++++++------------- unshell-module-test/src/lib.rs | 20 +------ unshell-modules/src/lib.rs | 42 +------------- 5 files changed, 77 insertions(+), 96 deletions(-) diff --git a/unshell-logger/src/lib.rs b/unshell-logger/src/lib.rs index 416f484..acb2b04 100644 --- a/unshell-logger/src/lib.rs +++ b/unshell-logger/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(improper_ctypes_definitions)] + use log::{LevelFilter, Log, SetLoggerError}; #[allow(dead_code)] diff --git a/unshell-module-load/Cargo.toml b/unshell-module-load/Cargo.toml index 3f5e9d1..5ffa2fe 100644 --- a/unshell-module-load/Cargo.toml +++ b/unshell-module-load/Cargo.toml @@ -1,3 +1,5 @@ +# cargo-features = ["trim-paths"] + [package] name = "unshell-module-load" version = "0.1.0" @@ -9,3 +11,12 @@ log = "0.4.28" pretty_env_logger = "0.5.0" unshell-logger = {path = "../unshell-logger"} unshell-modules = {path = "../unshell-modules"} + +[profile.release] +strip = true # Strip symbols from the binary +opt-level = "z" # Optimize for size +lto = true # Link tree optimization +codegen-units = 1 +panic = "abort" +debug = false # Remove debug +# trim-paths="all" diff --git a/unshell-module-load/src/main.rs b/unshell-module-load/src/main.rs index 06d8cd9..c628f9c 100644 --- a/unshell-module-load/src/main.rs +++ b/unshell-module-load/src/main.rs @@ -1,23 +1,10 @@ -use std::any::Any; +#[macro_use] +extern crate log; use libloading::{Library, Symbol}; use log::{info, warn}; use unshell_logger::SetupLogger; -use unshell_modules::{module, module_interface}; -// use unshell_modules::IntoFunctionPtr; -// use unshell_modules::test; -// use unshell_modules::ExportFunction; - -// fn test1() { -// warn!("Test1 not called"); -// } - -// fn test2() { -// warn!("Test2 not called"); -// } -// fn test3() { -// warn!("Test3 not called"); -// } +use unshell_modules::module_interface; module_interface! { Interface { @@ -27,35 +14,70 @@ module_interface! { } } -fn main() { - // println!("Hello, world!"); +#[allow(dead_code)] +#[derive(Debug)] +enum ModuleError { + LibLoadingError(libloading::Error), + LinkError(String), +} - // test(); +struct Module { + name: String, + lib: Library, +} - pretty_env_logger::init(); +impl Module { + pub fn new(path: &str) -> Result { + let lib = unsafe { Library::new(&path) }.map_err(|e| ModuleError::LibLoadingError(e))?; - warn!("Warning message"); + Ok(Self { + name: path.to_owned(), + lib, + }) + } + pub fn get_symbol(&self, symbol: &[u8]) -> Result, ModuleError> { + let symbol = unsafe { self.lib.get::(symbol) } + .map_err(|e| ModuleError::LinkError(format!("Failed to load symbol: {}", e)))?; - unsafe { - let lib = Library::new("../unshell-module-test/target/release/libunshell_module_test.so") - .unwrap(); - - let ret = lib.get::(b"setup_logger"); - - if let Ok(setup_logger) = ret { + Ok(symbol) + } + pub fn init_logger(&self) { + if let Ok(setup_logger) = self.get_symbol::(b"setup_logger") { setup_logger(log::logger(), log::max_level()).unwrap(); } else { warn!("setup_logger not found"); } - - let module = lib.get:: Interface>(b"functions").unwrap(); - - let i = module(); - - // i.test1(); - - info!("Func: {:?}", i.test1); - - i.test1(); + } + pub fn get_interface(&self) -> Result { + if let Ok(interface_function) = self.get_symbol:: T>(b"interface") { + Ok(interface_function()) + } else { + Err(ModuleError::LinkError(format!( + "Interface function not found!" + ))) + } + } +} + +fn main() { + pretty_env_logger::init(); + + info!("Initalized"); + + match || -> Result<(), ModuleError> { + let module = + Module::new("../unshell-module-test/target/release/libunshell_module_test.so")?; + module.init_logger(); + + let interface = module.get_interface::()?; + + interface.test1(); + + Ok(()) + }() { + Ok(_) => {} + Err(e) => { + error!("ERROR! {:?}", e); + } } } diff --git a/unshell-module-test/src/lib.rs b/unshell-module-test/src/lib.rs index abc7569..0ddb790 100644 --- a/unshell-module-test/src/lib.rs +++ b/unshell-module-test/src/lib.rs @@ -3,17 +3,14 @@ extern crate log; pub use unshell_logger::setup_logger; -use unshell_modules::{module, module_interface}; +use unshell_modules::module_interface; -// #[unsafe(no_mangle)] extern "C" fn test1() { warn!("Test1 called"); } -// #[unsafe(no_mangle)] extern "C" fn test2() { warn!("Test2 called"); } -// #[unsafe(no_mangle)] extern "C" fn test3() { warn!("Test3 called"); } @@ -27,19 +24,8 @@ module_interface! { } #[unsafe(no_mangle)] -pub fn test() { - info!("Module loaded"); -} - -#[unsafe(no_mangle)] -pub fn functions() -> Interface { - info!("Module loaded"); - // let m = TestModule::new(); - let i = unsafe { Interface::from_raw(test1, test2, test3) }; - - i.test1(); - - i +pub fn interface() -> Interface { + Interface::from_raw(test1, test2, test3) } #[unsafe(no_mangle)] diff --git a/unshell-modules/src/lib.rs b/unshell-modules/src/lib.rs index 082c94f..5db8284 100644 --- a/unshell-modules/src/lib.rs +++ b/unshell-modules/src/lib.rs @@ -1,31 +1,3 @@ -#[macro_export] -macro_rules! module { - ($module_name:ident { $(fn $fn_name:ident($($arg:ident : $ty:ty),* $(,)?) $(-> $ret:ty)?);* $(;)? }) => { - #[allow(non_camel_case_types)] - pub struct $module_name; - - impl $module_name { - $( - #[inline(always)] - pub fn $fn_name(&self, $($arg: $ty),*) $(-> $ret)? { - $fn_name($($arg),*) - } - )* - - /// Create a new instance of this module - pub fn new() -> Self { - Self - } - } - - impl Default for $module_name { - fn default() -> Self { - Self::new() - } - } - }; -} - #[macro_export] macro_rules! module_interface { ($interface_name:ident { $(fn $fn_name:ident($($arg:ident : $ty:ty),* $(,)?) $(-> $ret:ty)?);* $(;)? }) => { @@ -39,25 +11,13 @@ macro_rules! module_interface { } impl $interface_name { - /// Unsafe cast from a module type to this interface - /// - /// # Safety - /// - /// The caller must ensure that: - /// - The module has exactly the same function signatures in the same order - /// - The functions follow the C calling convention - /// - The module's memory layout matches this interface - pub unsafe fn from_module(module: &T) -> Self { - *(module as *const T as *const Self) - } - /// Create from raw function pointers /// /// # Safety /// /// The caller must ensure all function pointers are valid and have /// the correct signatures - pub unsafe fn from_raw( + pub fn from_raw( $($fn_name: extern "C" fn($($ty),*) $(-> $ret)?),* ) -> Self { Self {