1b8a62b91Sopenharmony_ci// Implementation derived from `weak` in Rust's 2b8a62b91Sopenharmony_ci// library/std/src/sys/unix/weak.rs at revision 3b8a62b91Sopenharmony_ci// fd0cb0cdc21dd9c06025277d772108f8d42cb25f. 4b8a62b91Sopenharmony_ci 5b8a62b91Sopenharmony_ci//! Support for "weak linkage" to symbols on Unix 6b8a62b91Sopenharmony_ci//! 7b8a62b91Sopenharmony_ci//! Some I/O operations we do in libstd require newer versions of OSes but we 8b8a62b91Sopenharmony_ci//! need to maintain binary compatibility with older releases for now. In order 9b8a62b91Sopenharmony_ci//! to use the new functionality when available we use this module for 10b8a62b91Sopenharmony_ci//! detection. 11b8a62b91Sopenharmony_ci//! 12b8a62b91Sopenharmony_ci//! One option to use here is weak linkage, but that is unfortunately only 13b8a62b91Sopenharmony_ci//! really workable on Linux. Hence, use dlsym to get the symbol value at 14b8a62b91Sopenharmony_ci//! runtime. This is also done for compatibility with older versions of glibc, 15b8a62b91Sopenharmony_ci//! and to avoid creating dependencies on `GLIBC_PRIVATE` symbols. It assumes 16b8a62b91Sopenharmony_ci//! that we've been dynamically linked to the library the symbol comes from, 17b8a62b91Sopenharmony_ci//! but that is currently always the case for things like libpthread/libc. 18b8a62b91Sopenharmony_ci//! 19b8a62b91Sopenharmony_ci//! A long time ago this used weak linkage for the `__pthread_get_minstack` 20b8a62b91Sopenharmony_ci//! symbol, but that caused Debian to detect an unnecessarily strict versioned 21b8a62b91Sopenharmony_ci//! dependency on libc6 (#23628). 22b8a62b91Sopenharmony_ci 23b8a62b91Sopenharmony_ci// There are a variety of `#[cfg]`s controlling which targets are involved in 24b8a62b91Sopenharmony_ci// each instance of `weak!` and `syscall!`. Rather than trying to unify all of 25b8a62b91Sopenharmony_ci// that, we'll just allow that some unix targets don't use this module at all. 26b8a62b91Sopenharmony_ci#![allow(dead_code, unused_macros)] 27b8a62b91Sopenharmony_ci#![allow(clippy::doc_markdown)] 28b8a62b91Sopenharmony_ci 29b8a62b91Sopenharmony_ciuse crate::ffi::CStr; 30b8a62b91Sopenharmony_ciuse core::ffi::c_void; 31b8a62b91Sopenharmony_ciuse core::ptr::null_mut; 32b8a62b91Sopenharmony_ciuse core::sync::atomic::{self, AtomicPtr, Ordering}; 33b8a62b91Sopenharmony_ciuse core::{marker, mem}; 34b8a62b91Sopenharmony_ci 35b8a62b91Sopenharmony_ciconst NULL: *mut c_void = null_mut(); 36b8a62b91Sopenharmony_ciconst INVALID: *mut c_void = 1 as *mut c_void; 37b8a62b91Sopenharmony_ci 38b8a62b91Sopenharmony_cimacro_rules! weak { 39b8a62b91Sopenharmony_ci ($vis:vis fn $name:ident($($t:ty),*) -> $ret:ty) => ( 40b8a62b91Sopenharmony_ci #[allow(non_upper_case_globals)] 41b8a62b91Sopenharmony_ci $vis static $name: $crate::backend::weak::Weak<unsafe extern fn($($t),*) -> $ret> = 42b8a62b91Sopenharmony_ci $crate::backend::weak::Weak::new(concat!(stringify!($name), '\0')); 43b8a62b91Sopenharmony_ci ) 44b8a62b91Sopenharmony_ci} 45b8a62b91Sopenharmony_ci 46b8a62b91Sopenharmony_cipub(crate) struct Weak<F> { 47b8a62b91Sopenharmony_ci name: &'static str, 48b8a62b91Sopenharmony_ci addr: AtomicPtr<c_void>, 49b8a62b91Sopenharmony_ci _marker: marker::PhantomData<F>, 50b8a62b91Sopenharmony_ci} 51b8a62b91Sopenharmony_ci 52b8a62b91Sopenharmony_ciimpl<F> Weak<F> { 53b8a62b91Sopenharmony_ci pub(crate) const fn new(name: &'static str) -> Self { 54b8a62b91Sopenharmony_ci Self { 55b8a62b91Sopenharmony_ci name, 56b8a62b91Sopenharmony_ci addr: AtomicPtr::new(INVALID), 57b8a62b91Sopenharmony_ci _marker: marker::PhantomData, 58b8a62b91Sopenharmony_ci } 59b8a62b91Sopenharmony_ci } 60b8a62b91Sopenharmony_ci 61b8a62b91Sopenharmony_ci pub(crate) fn get(&self) -> Option<F> { 62b8a62b91Sopenharmony_ci assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>()); 63b8a62b91Sopenharmony_ci unsafe { 64b8a62b91Sopenharmony_ci // Relaxed is fine here because we fence before reading through the 65b8a62b91Sopenharmony_ci // pointer (see the comment below). 66b8a62b91Sopenharmony_ci match self.addr.load(Ordering::Relaxed) { 67b8a62b91Sopenharmony_ci INVALID => self.initialize(), 68b8a62b91Sopenharmony_ci NULL => None, 69b8a62b91Sopenharmony_ci addr => { 70b8a62b91Sopenharmony_ci let func = mem::transmute_copy::<*mut c_void, F>(&addr); 71b8a62b91Sopenharmony_ci // The caller is presumably going to read through this value 72b8a62b91Sopenharmony_ci // (by calling the function we've dlsymed). This means we'd 73b8a62b91Sopenharmony_ci // need to have loaded it with at least C11's consume 74b8a62b91Sopenharmony_ci // ordering in order to be guaranteed that the data we read 75b8a62b91Sopenharmony_ci // from the pointer isn't from before the pointer was 76b8a62b91Sopenharmony_ci // stored. Rust has no equivalent to memory_order_consume, 77b8a62b91Sopenharmony_ci // so we use an acquire fence (sorry, ARM). 78b8a62b91Sopenharmony_ci // 79b8a62b91Sopenharmony_ci // Now, in practice this likely isn't needed even on CPUs 80b8a62b91Sopenharmony_ci // where relaxed and consume mean different things. The 81b8a62b91Sopenharmony_ci // symbols we're loading are probably present (or not) at 82b8a62b91Sopenharmony_ci // init, and even if they aren't the runtime dynamic loader 83b8a62b91Sopenharmony_ci // is extremely likely have sufficient barriers internally 84b8a62b91Sopenharmony_ci // (possibly implicitly, for example the ones provided by 85b8a62b91Sopenharmony_ci // invoking `mprotect`). 86b8a62b91Sopenharmony_ci // 87b8a62b91Sopenharmony_ci // That said, none of that's *guaranteed*, and so we fence. 88b8a62b91Sopenharmony_ci atomic::fence(Ordering::Acquire); 89b8a62b91Sopenharmony_ci Some(func) 90b8a62b91Sopenharmony_ci } 91b8a62b91Sopenharmony_ci } 92b8a62b91Sopenharmony_ci } 93b8a62b91Sopenharmony_ci } 94b8a62b91Sopenharmony_ci 95b8a62b91Sopenharmony_ci // Cold because it should only happen during first-time initialization. 96b8a62b91Sopenharmony_ci #[cold] 97b8a62b91Sopenharmony_ci unsafe fn initialize(&self) -> Option<F> { 98b8a62b91Sopenharmony_ci let val = fetch(self.name); 99b8a62b91Sopenharmony_ci // This synchronizes with the acquire fence in `get`. 100b8a62b91Sopenharmony_ci self.addr.store(val, Ordering::Release); 101b8a62b91Sopenharmony_ci 102b8a62b91Sopenharmony_ci match val { 103b8a62b91Sopenharmony_ci NULL => None, 104b8a62b91Sopenharmony_ci addr => Some(mem::transmute_copy::<*mut c_void, F>(&addr)), 105b8a62b91Sopenharmony_ci } 106b8a62b91Sopenharmony_ci } 107b8a62b91Sopenharmony_ci} 108b8a62b91Sopenharmony_ci 109b8a62b91Sopenharmony_ciunsafe fn fetch(name: &str) -> *mut c_void { 110b8a62b91Sopenharmony_ci let name = match CStr::from_bytes_with_nul(name.as_bytes()) { 111b8a62b91Sopenharmony_ci Ok(c_str) => c_str, 112b8a62b91Sopenharmony_ci Err(..) => return null_mut(), 113b8a62b91Sopenharmony_ci }; 114b8a62b91Sopenharmony_ci libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr().cast()) 115b8a62b91Sopenharmony_ci} 116b8a62b91Sopenharmony_ci 117b8a62b91Sopenharmony_ci#[cfg(not(any(target_os = "android", target_os = "linux")))] 118b8a62b91Sopenharmony_cimacro_rules! syscall { 119b8a62b91Sopenharmony_ci (fn $name:ident($($arg_name:ident: $t:ty),*) via $_sys_name:ident -> $ret:ty) => ( 120b8a62b91Sopenharmony_ci unsafe fn $name($($arg_name: $t),*) -> $ret { 121b8a62b91Sopenharmony_ci weak! { fn $name($($t),*) -> $ret } 122b8a62b91Sopenharmony_ci 123b8a62b91Sopenharmony_ci if let Some(fun) = $name.get() { 124b8a62b91Sopenharmony_ci fun($($arg_name),*) 125b8a62b91Sopenharmony_ci } else { 126b8a62b91Sopenharmony_ci libc_errno::set_errno(libc_errno::Errno(libc::ENOSYS)); 127b8a62b91Sopenharmony_ci -1 128b8a62b91Sopenharmony_ci } 129b8a62b91Sopenharmony_ci } 130b8a62b91Sopenharmony_ci ) 131b8a62b91Sopenharmony_ci} 132b8a62b91Sopenharmony_ci 133b8a62b91Sopenharmony_ci#[cfg(any(target_os = "android", target_os = "linux"))] 134b8a62b91Sopenharmony_cimacro_rules! syscall { 135b8a62b91Sopenharmony_ci (fn $name:ident($($arg_name:ident: $t:ty),*) via $sys_name:ident -> $ret:ty) => ( 136b8a62b91Sopenharmony_ci unsafe fn $name($($arg_name:$t),*) -> $ret { 137b8a62b91Sopenharmony_ci // This looks like a hack, but concat_idents only accepts idents 138b8a62b91Sopenharmony_ci // (not paths). 139b8a62b91Sopenharmony_ci use libc::*; 140b8a62b91Sopenharmony_ci 141b8a62b91Sopenharmony_ci trait AsSyscallArg { 142b8a62b91Sopenharmony_ci type SyscallArgType; 143b8a62b91Sopenharmony_ci fn into_syscall_arg(self) -> Self::SyscallArgType; 144b8a62b91Sopenharmony_ci } 145b8a62b91Sopenharmony_ci 146b8a62b91Sopenharmony_ci // Pass pointer types as pointers, to preserve provenance. 147b8a62b91Sopenharmony_ci impl<T> AsSyscallArg for *mut T { 148b8a62b91Sopenharmony_ci type SyscallArgType = *mut T; 149b8a62b91Sopenharmony_ci fn into_syscall_arg(self) -> Self::SyscallArgType { self } 150b8a62b91Sopenharmony_ci } 151b8a62b91Sopenharmony_ci impl<T> AsSyscallArg for *const T { 152b8a62b91Sopenharmony_ci type SyscallArgType = *const T; 153b8a62b91Sopenharmony_ci fn into_syscall_arg(self) -> Self::SyscallArgType { self } 154b8a62b91Sopenharmony_ci } 155b8a62b91Sopenharmony_ci 156b8a62b91Sopenharmony_ci // Pass `BorrowedFd` values as the integer value. 157b8a62b91Sopenharmony_ci impl AsSyscallArg for $crate::fd::BorrowedFd<'_> { 158b8a62b91Sopenharmony_ci type SyscallArgType = c::c_long; 159b8a62b91Sopenharmony_ci fn into_syscall_arg(self) -> Self::SyscallArgType { 160b8a62b91Sopenharmony_ci $crate::fd::AsRawFd::as_raw_fd(&self) as _ 161b8a62b91Sopenharmony_ci } 162b8a62b91Sopenharmony_ci } 163b8a62b91Sopenharmony_ci 164b8a62b91Sopenharmony_ci // Coerce integer values into `c_long`. 165b8a62b91Sopenharmony_ci impl AsSyscallArg for i32 { 166b8a62b91Sopenharmony_ci type SyscallArgType = c::c_long; 167b8a62b91Sopenharmony_ci fn into_syscall_arg(self) -> Self::SyscallArgType { self as _ } 168b8a62b91Sopenharmony_ci } 169b8a62b91Sopenharmony_ci impl AsSyscallArg for u32 { 170b8a62b91Sopenharmony_ci type SyscallArgType = c::c_long; 171b8a62b91Sopenharmony_ci fn into_syscall_arg(self) -> Self::SyscallArgType { self as _ } 172b8a62b91Sopenharmony_ci } 173b8a62b91Sopenharmony_ci impl AsSyscallArg for usize { 174b8a62b91Sopenharmony_ci type SyscallArgType = c::c_long; 175b8a62b91Sopenharmony_ci fn into_syscall_arg(self) -> Self::SyscallArgType { self as _ } 176b8a62b91Sopenharmony_ci } 177b8a62b91Sopenharmony_ci 178b8a62b91Sopenharmony_ci // `concat_idents is unstable, so we take an extra `sys_name` 179b8a62b91Sopenharmony_ci // parameter and have our users do the concat for us for now. 180b8a62b91Sopenharmony_ci /* 181b8a62b91Sopenharmony_ci syscall( 182b8a62b91Sopenharmony_ci concat_idents!(SYS_, $name), 183b8a62b91Sopenharmony_ci $($arg_name.into_syscall_arg()),* 184b8a62b91Sopenharmony_ci ) as $ret 185b8a62b91Sopenharmony_ci */ 186b8a62b91Sopenharmony_ci 187b8a62b91Sopenharmony_ci syscall($sys_name, $($arg_name.into_syscall_arg()),*) as $ret 188b8a62b91Sopenharmony_ci } 189b8a62b91Sopenharmony_ci ) 190b8a62b91Sopenharmony_ci} 191b8a62b91Sopenharmony_ci 192b8a62b91Sopenharmony_cimacro_rules! weakcall { 193b8a62b91Sopenharmony_ci ($vis:vis fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( 194b8a62b91Sopenharmony_ci $vis unsafe fn $name($($arg_name: $t),*) -> $ret { 195b8a62b91Sopenharmony_ci weak! { fn $name($($t),*) -> $ret } 196b8a62b91Sopenharmony_ci 197b8a62b91Sopenharmony_ci // Use a weak symbol from libc when possible, allowing `LD_PRELOAD` 198b8a62b91Sopenharmony_ci // interposition, but if it's not found just fail. 199b8a62b91Sopenharmony_ci if let Some(fun) = $name.get() { 200b8a62b91Sopenharmony_ci fun($($arg_name),*) 201b8a62b91Sopenharmony_ci } else { 202b8a62b91Sopenharmony_ci libc_errno::set_errno(libc_errno::Errno(libc::ENOSYS)); 203b8a62b91Sopenharmony_ci -1 204b8a62b91Sopenharmony_ci } 205b8a62b91Sopenharmony_ci } 206b8a62b91Sopenharmony_ci ) 207b8a62b91Sopenharmony_ci} 208b8a62b91Sopenharmony_ci 209b8a62b91Sopenharmony_ci/// A combination of `weakcall` and `syscall`. Use the libc function if it's 210b8a62b91Sopenharmony_ci/// available, and fall back to `libc::syscall` otherwise. 211b8a62b91Sopenharmony_cimacro_rules! weak_or_syscall { 212b8a62b91Sopenharmony_ci ($vis:vis fn $name:ident($($arg_name:ident: $t:ty),*) via $sys_name:ident -> $ret:ty) => ( 213b8a62b91Sopenharmony_ci $vis unsafe fn $name($($arg_name: $t),*) -> $ret { 214b8a62b91Sopenharmony_ci weak! { fn $name($($t),*) -> $ret } 215b8a62b91Sopenharmony_ci 216b8a62b91Sopenharmony_ci // Use a weak symbol from libc when possible, allowing `LD_PRELOAD` 217b8a62b91Sopenharmony_ci // interposition, but if it's not found just fail. 218b8a62b91Sopenharmony_ci if let Some(fun) = $name.get() { 219b8a62b91Sopenharmony_ci fun($($arg_name),*) 220b8a62b91Sopenharmony_ci } else { 221b8a62b91Sopenharmony_ci syscall! { fn $name($($arg_name: $t),*) via $sys_name -> $ret } 222b8a62b91Sopenharmony_ci $name($($arg_name),*) 223b8a62b91Sopenharmony_ci } 224b8a62b91Sopenharmony_ci } 225b8a62b91Sopenharmony_ci ) 226b8a62b91Sopenharmony_ci} 227