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
use core::{
marker::PhantomData,
mem::transmute,
ops::Deref,
sync::atomic::{AtomicUsize, Ordering},
};
/// Creates a function defenition with explicitly defined offset from module or signature.
/// ```
/// # use memflex::ResolveBy;
/// fn get_address_in_module<const N: usize>(_: ResolveBy<N>) -> usize {
/// todo!()
/// }
///
/// memflex::function! {
/// extern fn CALLE(i32, i32) -> i32 = "file.exe"#0x1122;
///
/// // Use `get_address_in_module` function to get the address duh
/// extern fn OTHER_FN(f32, bool) -> u64 = (get_address_in_module)"file.exe"#0x1122;
///
/// // Resolve by signature
/// extern fn SIG_FN() -> u64 = "file.exe"%"4A 5B 3C AA 14";
/// }
/// ```
#[macro_export]
macro_rules! function {
(
$(
$(extern $($abi:literal)?)? fn $fname:ident( $($atype:ty),* ) $(-> $ret:ty)? = $( ($resolver:ident) )? $modname:literal $sep:tt $offset:expr;
)*
) => {
$(
static $fname: $crate::Function< $(extern $($abi)?)? fn($($atype),*) $(-> $ret)?> = $crate::Function::new(
|| unsafe {
($crate::__resolver!( $($resolver)? ))( $crate::__resolve_by!($sep $modname, $offset ) )
}
);
)*
};
}
/// Function that resolve its address on the first access.
pub struct Function<F> {
address: AtomicUsize,
init: fn() -> usize,
_ph: PhantomData<F>,
}
impl<F> Function<F> {
#[doc(hidden)]
pub const fn new(init: fn() -> usize) -> Self {
Self {
address: AtomicUsize::new(0),
init,
_ph: PhantomData,
}
}
/// Returns function address
pub fn address(&self) -> usize {
let mut address = self.address.load(Ordering::Acquire);
if address == 0 {
address = (self.init)();
self.address.store(address, Ordering::Release);
}
address
}
/// Force inits function
pub fn force(&self) {
_ = self.address();
}
}
impl<F> Deref for Function<F> {
type Target = F;
fn deref(&self) -> &Self::Target {
self.force();
unsafe { transmute(self) }
}
}