getfn/
lib.rs

1//! Utilities for referring to functions by pointer.
2//! 
3//! Using the `getfn!` macro, you can generate a pair of functions: the first
4//! function acts as a "getter" function, and is prefixed with `getfn_`. The
5//! second function simply calls the function normally:
6//! 
7//! ```
8//! use getfn::getfn;
9//! 
10//! getfn! {
11//! 	(|| { println!("hi!"); })
12//! 	fn my_func();
13//! }
14//! 
15//! my_func(); // hi!
16//! let f = getfn_my_func();
17//! f(); // hi!
18//! ```
19//! 
20//! You might be wondering why not simply use `let f = my_func;` instead of
21//! having a separate getter. The reason is that the resulting function pointer
22//! in `f` will not have the exact same address as the one passed into `getfn!`.
23//! This is necessary in cases like game modding, where to [hook] a function,
24//! you must have its exact address. To aid these usecases, `getfn` also offers
25//! a `get_addr!` macro, which is a DSL for getting the address of a function:
26//! ```norun
27//! // gets the base address of the `MyGame.exe` module using the backend
28//! // (currently assumed to be `winapi` accessible from `crate::__getfn_winapi_`)
29//! let f = getfn::get_addr!("MyGame.exe" + 0x20bf00);
30//! ```
31//! These can be combined together using the `symbol_fn!` macro:
32//! ```norun
33//! use getfn::symbol_fn;
34//! use std::ffi::c_void;
35//! 
36//! symbol_fn! {
37//! 	("MyGame.exe" + 0x20bf00)
38//! 	extern "C" fn my_game_func(a: i32) -> bool;
39//! }
40//! println!("{}", my_game_func(5));
41//! 
42//! let func = getfn_my_game_func();
43//! 
44//! extern "C" fn detour(a: i32) -> bool { a == 5 }
45//! 
46//! // .. hook `func` ..
47//! let mut orig = std::ptr::null_mut();
48//! MH_CreateHook(func as *mut c_void, detour, &mut orig as *mut _ as _);
49//! ```
50//! [hook]: https://en.wikipedia.org/wiki/Hooking
51
52#![no_std]
53
54pub use paste;
55
56#[macro_export]
57macro_rules! getfn {
58	() => {};
59	(
60		($e:expr) $vis:vis $(extern $cc:literal)? fn $name:ident($($arg:ident : $argtype:ty),* $(,)?) $(-> $ret:ty)?;
61		$($tt:tt)*
62	) => {
63		$crate::paste::item! {
64			#[allow(unused_parens)]
65			$vis fn [<getfn_ $name>]() -> ($(extern $cc)? fn($($argtype),*) $(-> $ret)?) { $e }
66		}
67
68		$crate::paste::item! {
69			$vis fn $name($($arg: $argtype),*) $(-> $ret)? {
70				[<getfn_ $name>]()($($arg),*)
71			}
72		}
73
74		$crate::getfn!($($tt)*);
75	};
76	(
77		($e:expr) $vis:vis unsafe $(extern $cc:literal)? fn $name:ident($($arg:ident : $argtype:ty),* $(,)?) $(-> $ret:ty)?;
78		$($tt:tt)*
79	) => {
80		$crate::paste::item! {
81			#[allow(unused_parens)]
82			$vis fn [<getfn_ $name>]() -> (unsafe $(extern $cc)? fn($($argtype),*) $(-> $ret)?) { $e }
83		}
84
85		$crate::paste::item! {
86			$vis unsafe fn $name($($arg: $argtype),*) $(-> $ret)? {
87				[<getfn_ $name>]()($($arg),*)
88			}
89		}
90
91		$crate::getfn!($($tt)*);
92	};
93	(
94		($e:expr) $vis:vis $(extern $cc:literal)? fn Self::$name:ident($($arg:ident : $argtype:ty),* $(,)?) $(-> $ret:ty)?;
95		$($tt:tt)*
96	) => {
97		$crate::paste::item! {
98			#[allow(unused_parens)]
99			$vis fn [<getfn_ $name>]() -> ($(extern $cc)? fn($($argtype),*) $(-> $ret)?) { $e }
100		}
101		$crate::paste::item! {
102			$vis fn $name($($arg: $argtype),*) $(-> $ret)? {
103				Self::[<getfn_ $name>]()($($arg),*)
104			}
105		}
106
107		$crate::getfn!($($tt)*);
108	};
109	(
110		($e:expr) $vis:vis unsafe $(extern $cc:literal)? fn Self::$name:ident($($arg:ident : $argtype:ty),* $(,)?) $(-> $ret:ty)?;
111		$($tt:tt)*
112	) => {
113		$crate::paste::item! {
114			#[allow(unused_parens)]
115			$vis fn [<getfn_ $name>]() -> (unsafe $(extern $cc)? fn($($argtype),*) $(-> $ret)?) { $e }
116		}
117		$crate::paste::item! {
118			$vis unsafe fn $name($($arg: $argtype),*) $(-> $ret)? {
119				Self::[<getfn_ $name>]()($($arg),*)
120			}
121		}
122
123		$crate::getfn!($($tt)*);
124	};
125	(
126		($e:expr) $vis:vis $(extern $cc:literal)? fn Self::$name:ident([$($self:tt)+] $($arg:ident : $argtype:ty),* $(,)?) $(-> $ret:ty)?;
127		$($tt:tt)*
128	) => {
129		$crate::paste::item! {
130			#[allow(unused_parens)]
131			$vis fn [<getfn_ $name>]() -> ($crate::_getfn_ret!([$($self)+] $($cc)?, $($ret)?, $($argtype),*)) { $e }
132		}
133		$crate::paste::item! {
134			$vis fn $name($($self)+, $($arg: $argtype),*) $(-> $ret)? {
135				Self::[<getfn_ $name>]()($crate::_getfn_get_self_tok!($($self)+), $($arg),*)
136			}
137		}
138
139		$crate::getfn!($($tt)*);
140	};
141	(
142		($e:expr) $vis:vis unsafe $(extern $cc:literal)? fn Self::$name:ident([$($self:tt)+] $($arg:ident : $argtype:ty),* $(,)?) $(-> $ret:ty)?;
143		$($tt:tt)*
144	) => {
145		$crate::paste::item! {
146			#[allow(unused_parens)]
147			$vis fn [<getfn_ $name>]() -> (unsafe $crate::_getfn_ret!([$($self)+] $($cc)?, $($ret)?, $($argtype),*)) { $e }
148		}
149		$crate::paste::item! {
150			$vis unsafe fn $name($($self)+, $($arg: $argtype),*) $(-> $ret)? {
151				Self::[<getfn_ $name>]()($crate::_getfn_get_self_tok!($($self)+), $($arg),*)
152			}
153		}
154
155		$crate::getfn!($($tt)*);
156	};
157}
158
159#[doc(hidden)]
160#[macro_export]
161macro_rules! _getfn_ret {
162	([self] $($cc:literal)?, $($ret:ty)?, $($args:tt)*) => ($(extern $cc)? fn(Self, $($args),*) $(-> $ret)?);
163	([& $($lt:lifetime)? self] $($cc:literal)?, $($ret:ty)?, $($args:tt)*) => ($(extern $cc)? fn(&$($lt)? Self, $($args),*) $(-> $ret)?);
164	([& $($lt:lifetime)? mut self] $($cc:literal)?, $($ret:ty)?, $($args:tt)*) => ($(extern $cc)? fn(&$($lt)? mut Self, $($args),*) $(-> $ret)?);
165}
166
167#[doc(hidden)]
168#[macro_export]
169macro_rules! _getfn_get_self_tok {
170	(& $($lt:lifetime)? mut $t:tt) => ($t);
171	(& $($lt:lifetime)? $t:tt) => ($t);
172	($t:tt) => ($t);
173}
174
175#[macro_export]
176macro_rules! alias {
177	($name:ident) => ($crate::paste::expr!(crate:: [<__getfn_alias__ $name>] ::value()));
178}
179
180#[macro_export]
181macro_rules! def_alias {
182	() => {};
183	($name:ident = $val:expr; $($tt:tt)*) => {
184		$crate::paste::item! {
185			pub(crate) mod [<__getfn_alias__ $name>] {
186				pub fn ___value___() -> *mut () {
187					use super::*;
188					$val
189				}
190			}
191		}
192		$crate::paste::item! {
193			use crate:: [<__getfn_alias__ $name>] as _;
194		}
195	};
196	($name:ident: $t:ty = $val:expr; $($tt:tt)*) => {
197		$crate::paste::item! {
198			pub(crate) mod [<__getfn_alias__ $name>] {
199				pub fn ___value___() -> $t {
200					use super::*;
201					$val
202				}
203			}
204		}
205		$crate::paste::item! {
206			use crate:: [<__getfn_alias__ $name>] as _;
207		}
208	}
209}
210
211/// DSL for getting addresses
212#[macro_export]
213macro_rules! get_addr {
214	($custom:ident $($tt:tt)*) => {
215		$crate::_get_addr0!(
216			($crate::alias!($custom))
217			$($tt)*
218		)
219	};
220
221	(($e:expr) $($tt:tt)*) => {
222		$crate::_get_addr0!(
223			($e)
224			$($tt)*
225		)
226	};
227
228	($module:literal $($tt:tt)*) => {
229		$crate::_get_addr0!(
230			(crate::__getfn_winapi__::um::libloaderapi::GetModuleHandleA(concat!($module, "\0").as_ptr() as _).cast::<()>())
231			$($tt)*
232		)
233	};
234}
235
236#[doc(hidden)]
237#[macro_export]
238macro_rules! _get_addr0 {
239	(($v:expr)) => ($v);
240	(($v:expr) @ $sym:literal $($tt:tt)*) => {
241		$crate::_get_addr0!(
242			(::core::mem::transmute::<_, *mut ()>(crate::__getfn_winapi__::um::libloaderapi::GetProcAddress($v as *mut _, concat!($sym, "\0").as_ptr() as _)))
243			$($tt)*
244		)
245	};
246	(($v:expr) * $($tt:tt)*) => {
247		$crate::_get_addr0!(
248			(($v as *mut *mut ()).read())
249			$($tt)*
250		)
251	};
252	(($v:expr) + $e:literal $($tt:tt)*) => {
253		$crate::_get_addr0!(
254			($v.cast::<u8>().offset($e as isize).cast::<()>())
255			$($tt)*
256		)
257	};
258	(($v:expr) + ($e:expr) $($tt:tt)*) => {
259		$crate::_get_addr0!(
260			($v.cast::<u8>().offset($e as isize).cast::<()>())
261			$($tt)*
262		)
263	};
264	(($v:expr) - $e:literal $($tt:tt)*) => {
265		$crate::_get_addr0!(
266			($v.cast::<u8>().offset(-($e as isize)).cast::<()>())
267			$($tt)*
268		)
269	};
270	(($v:expr) - ($e:expr) $($tt:tt)*) => {
271		$crate::_get_addr0!(
272			($v.cast::<u8>().offset(-($e as isize)).cast::<()>())
273			$($tt)*
274		)
275	}
276}
277
278#[macro_export]
279macro_rules! symbol_fn {
280	() => {};
281	(
282		($($tt:tt)*) $vis:vis $(extern $cc:literal)? fn $name:ident($($arg:ident : $argtype:ty),* $(,)?) $(-> $ret:ty)?;
283		$($tta:tt)*
284	) => {
285		$crate::getfn! {
286			(#[allow(unused_unsafe)] unsafe { ::core::mem::transmute($crate::get_addr!($($tt)*)) }) $vis $(extern $cc)? fn $name($($arg : $argtype),*) $(-> $ret)?;
287		}
288
289		$crate::symbol_fn!($($tta)*);
290	};
291	(
292		($($tt:tt)*) $vis:vis unsafe $(extern $cc:literal)? fn $name:ident($($arg:ident : $argtype:ty),* $(,)?) $(-> $ret:ty)?;
293		$($tta:tt)*
294	) => {
295		$crate::getfn! {
296			(#[allow(unused_unsafe)] unsafe { ::core::mem::transmute($crate::get_addr!($($tt)*)) }) $vis unsafe $(extern $cc)? fn $name($($arg : $argtype),*) $(-> $ret)?;
297		}
298
299		$crate::symbol_fn!($($tta)*);
300	};
301	(
302		($($tt:tt)*) $vis:vis $(extern $cc:literal)? fn Self::$name:ident($($arg:ident : $argtype:ty),* $(,)?) $(-> $ret:ty)?;
303		$($tta:tt)*
304	) => {
305		$crate::getfn! {
306			(#[allow(unused_unsafe)] unsafe { ::core::mem::transmute($crate::get_addr!($($tt)*)) }) $vis $(extern $cc)? fn Self::$name($($arg : $argtype),*) $(-> $ret)?;
307		}
308
309		$crate::symbol_fn!($($tta)*);
310	};
311	(
312		($($tt:tt)*) $vis:vis unsafe $(extern $cc:literal)? fn Self::$name:ident($($arg:ident : $argtype:ty),* $(,)?) $(-> $ret:ty)?;
313		$($tta:tt)*
314	) => {
315		$crate::getfn! {
316			(#[allow(unused_unsafe)] unsafe { ::core::mem::transmute($crate::get_addr!($($tt)*)) }) $vis unsafe $(extern $cc)? fn Self::$name($($arg : $argtype),*) $(-> $ret)?;
317		}
318
319		$crate::symbol_fn!($($tta)*);
320	};
321	(
322		($($tt:tt)*) $vis:vis $(extern $cc:literal)? fn Self::$name:ident([$($self:tt)+] $($arg:ident : $argtype:ty),* $(,)?) $(-> $ret:ty)?;
323		$($tta:tt)*
324	) => {
325		$crate::getfn! {
326			(#[allow(unused_unsafe)] unsafe { ::core::mem::transmute($crate::get_addr!($($tt)*)) }) $vis $(extern $cc)? fn Self::$name([$($self)+] $($arg : $argtype),*) $(-> $ret)?;
327		}
328
329		$crate::symbol_fn!($($tta)*);
330	};
331	(
332		($($tt:tt)*) $vis:vis unsafe $(extern $cc:literal)? fn Self::$name:ident([$($self:tt)+] $($arg:ident : $argtype:ty),* $(,)?) $(-> $ret:ty)?;
333		$($tta:tt)*
334	) => {
335		$crate::getfn! {
336			(#[allow(unused_unsafe)] unsafe { ::core::mem::transmute($crate::get_addr!($($tt)*)) }) $vis unsafe $(extern $cc)? fn Self::$name([$($self)+] $($arg : $argtype),*) $(-> $ret)?;
337		}
338
339		$crate::symbol_fn!($($tta)*);
340	};
341}
342
343#[macro_export]
344macro_rules! symbol_static {
345	() => {};
346	(($($tt:tt)*) $vis:vis static $name:ident: $ty:ty; $($tta:tt)*) => {
347		$vis const $name: $crate::SymbolStatic<$ty> = unsafe { $crate::SymbolStatic::_new(|| {
348			$crate::get_addr!($($tt)*)
349		}) };
350		$crate::symbol_static!($($tta)*);
351	};
352	(($($tt:tt)*) $vis:vis static mut $name:ident: $ty:ty; $($tta:tt)*) => {
353		::core::compile_error!("static muts are unsupported. consider using atomics or `static X: UnsafeCell<T>`.");
354	}
355}
356
357
358// ============= //
359
360use core::marker::PhantomData;
361use core::ops::Deref;
362
363#[derive(Copy, Clone)]
364pub struct SymbolStatic<T: Sync>(PhantomData<T>, fn() -> *mut ());
365
366impl<T: Sync> Deref for SymbolStatic<T> {
367	type Target = T;
368	fn deref(&self) -> &T { unsafe { &*(self.1() as *const T) } }
369}
370
371impl<T: Sync> SymbolStatic<T> {
372	#[doc(hidden)]
373	pub const unsafe fn _new(x: fn() -> *mut ()) -> Self {
374		Self(PhantomData, x)
375	}
376}