use dlopen::symbor::Library;
use std::ffi::CStr;
use std::os::raw::c_char;
use std::ptr::NonNull;
#[macro_export]
macro_rules! c_str {
($s:expr) => {{
#[allow(unused_unsafe)]
const RESULT: &'static ::std::ffi::CStr = unsafe {
::std::ffi::CStr::from_bytes_with_nul_unchecked(::std::concat!($s, "\0").as_bytes())
};
RESULT
}};
}
#[macro_export]
macro_rules! c_ptr {
($s:expr) => {
$crate::c_str!($s).as_ptr()
};
}
#[macro_export]
macro_rules! offset_of {
($type:ty, $field:tt) => {{
const RESULT: usize = unsafe {
let dummy = ::core::mem::MaybeUninit::<$type>::uninit();
let dummy_ptr = dummy.as_ptr();
let field_ptr = ::std::ptr::addr_of!((*dummy_ptr).$field);
let field_ptr = field_ptr.cast::<u8>();
let dummy_ptr = dummy_ptr.cast::<u8>();
field_ptr.offset_from(dummy_ptr) as usize
};
RESULT
}};
}
#[macro_export]
macro_rules! static_assert {
($e:expr $(,)?) => {
const _: () = assert!($e);
};
($e:expr, $msg:expr $(,)?) => {
const _: () = assert!($e, $msg);
};
}
#[macro_export]
macro_rules! define_dlsym_reloc {
(
$(
$(#[$meta:meta])*
pub $(($where:tt))? fn $sym:ident ( $( $args:ident: $types:ty ),* $(,)? ) $( -> $ret:ty )?;
)+
) => {
$(
$(#[$meta])*
#[inline(always)]
pub $(($where))? unsafe fn $sym($($args: $types),*) $(-> $ret)? {
return RELOC_FN($($args),*);
type SymType = unsafe fn($($args: $types),*) $(-> $ret)?;
static mut RELOC_FN: SymType = init;
unsafe fn init($($args: $types),*) $(-> $ret)? {
let sym_name = $crate::c_str!(::std::stringify!($sym));
let impl_fn: SymType = $crate::ffi::helper::get_any_symbol(sym_name)
.unwrap();
RELOC_FN = impl_fn;
RELOC_FN($($args),*)
}
}
)+
};
}
#[inline]
pub unsafe fn tnt_internal_symbol<T>(name: &CStr) -> Option<T> {
if std::mem::size_of::<T>() != std::mem::size_of::<*mut ()>() {
return None;
}
let ptr = (RELOC_FN?)(name.as_ptr())?;
return Some(std::mem::transmute_copy(&ptr));
type SymType = unsafe fn(*const c_char) -> Option<NonNull<()>>;
static mut RELOC_FN: Option<SymType> = Some(init);
unsafe fn init(name: *const c_char) -> Option<NonNull<()>> {
let lib = Library::open_self().ok()?;
match lib.symbol_cstr(c_str!("tnt_internal_symbol")) {
Ok(sym) => {
RELOC_FN = Some(*sym);
(RELOC_FN.unwrap())(name)
}
Err(_) => {
RELOC_FN = None;
None
}
}
}
}
#[inline]
pub unsafe fn has_dyn_symbol(name: &CStr) -> bool {
get_dyn_symbol::<*const ()>(name).is_ok()
}
#[inline]
pub unsafe fn get_dyn_symbol<T: Copy>(name: &CStr) -> Result<T, dlopen::Error> {
let lib = Library::open_self()?;
let sym = lib.symbol_cstr(name)?;
Ok(*sym)
}
#[inline]
pub unsafe fn get_any_symbol<T: Copy>(name: &CStr) -> Result<T, dlopen::Error> {
if let Some(sym) = tnt_internal_symbol(name) {
return Ok(sym);
}
let lib = Library::open_self()?;
let sym = lib.symbol_cstr(name)?;
Ok(*sym)
}