|
49 | 49 | //! * call any Rust function or CRT function that touches any static |
50 | 50 | //! (global) state. |
51 | 51 |
|
52 | | -macro_rules! compat_fn { |
53 | | - ($module:literal: $( |
| 52 | +use crate::ffi::{c_void, CStr}; |
| 53 | +use crate::ptr::NonNull; |
| 54 | +use crate::sys::c; |
| 55 | + |
| 56 | +/// Helper macro for creating CStrs from literals and symbol names. |
| 57 | +macro_rules! ansi_str { |
| 58 | + (sym $ident:ident) => {{ |
| 59 | + #[allow(unused_unsafe)] |
| 60 | + crate::sys::compat::const_cstr_from_bytes(concat!(stringify!($ident), "\0").as_bytes()) |
| 61 | + }}; |
| 62 | + ($lit:literal) => {{ crate::sys::compat::const_cstr_from_bytes(concat!($lit, "\0").as_bytes()) }}; |
| 63 | +} |
| 64 | + |
| 65 | +/// Creates a C string wrapper from a byte slice, in a constant context. |
| 66 | +/// |
| 67 | +/// This is a utility function used by the [`ansi_str`] macro. |
| 68 | +/// |
| 69 | +/// # Panics |
| 70 | +/// |
| 71 | +/// Panics if the slice is not null terminated or contains nulls, except as the last item |
| 72 | +pub(crate) const fn const_cstr_from_bytes(bytes: &'static [u8]) -> &'static CStr { |
| 73 | + if !matches!(bytes.last(), Some(&0)) { |
| 74 | + panic!("A CStr must be null terminated"); |
| 75 | + } |
| 76 | + let mut i = 0; |
| 77 | + // At this point `len()` is at least 1. |
| 78 | + while i < bytes.len() - 1 { |
| 79 | + if bytes[i] == 0 { |
| 80 | + panic!("A CStr must not have interior nulls") |
| 81 | + } |
| 82 | + i += 1; |
| 83 | + } |
| 84 | + // SAFETY: The safety is ensured by the above checks. |
| 85 | + unsafe { crate::ffi::CStr::from_bytes_with_nul_unchecked(bytes) } |
| 86 | +} |
| 87 | + |
| 88 | +#[used] |
| 89 | +#[link_section = ".CRT$XCU"] |
| 90 | +static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init; |
| 91 | + |
| 92 | +/// This is where the magic preloading of symbols happens. |
| 93 | +/// |
| 94 | +/// Note that any functions included here will be unconditionally included in |
| 95 | +/// the final binary, regardless of whether or not they're actually used. |
| 96 | +/// |
| 97 | +/// Therefore, this is limited to `compat_fn_optional` functions which must be |
| 98 | +/// preloaded and any functions which may be more time sensitive, even for the first call. |
| 99 | +unsafe extern "C" fn init() { |
| 100 | + // There is no locking here. This code is executed before main() is entered, and |
| 101 | + // is guaranteed to be single-threaded. |
| 102 | + // |
| 103 | + // DO NOT do anything interesting or complicated in this function! DO NOT call |
| 104 | + // any Rust functions or CRT functions if those functions touch any global state, |
| 105 | + // because this function runs during global initialization. For example, DO NOT |
| 106 | + // do any dynamic allocation, don't call LoadLibrary, etc. |
| 107 | + |
| 108 | + if let Some(synch) = Module::new(c::SYNCH_API) { |
| 109 | + // These are optional and so we must manually attempt to load them |
| 110 | + // before they can be used. |
| 111 | + c::WaitOnAddress::preload(synch); |
| 112 | + c::WakeByAddressSingle::preload(synch); |
| 113 | + } |
| 114 | + |
| 115 | + if let Some(kernel32) = Module::new(c::KERNEL32) { |
| 116 | + // Preloading this means getting a precise time will be as fast as possible. |
| 117 | + c::GetSystemTimePreciseAsFileTime::preload(kernel32); |
| 118 | + } |
| 119 | +} |
| 120 | + |
| 121 | +/// Represents a loaded module. |
| 122 | +/// |
| 123 | +/// Note that the modules std depends on must not be unloaded. |
| 124 | +/// Therefore a `Module` is always valid for the lifetime of std. |
| 125 | +#[derive(Copy, Clone)] |
| 126 | +pub(in crate::sys) struct Module(NonNull<c_void>); |
| 127 | +impl Module { |
| 128 | + /// Try to get a handle to a loaded module. |
| 129 | + /// |
| 130 | + /// # SAFETY |
| 131 | + /// |
| 132 | + /// This should only be use for modules that exist for the lifetime of std |
| 133 | + /// (e.g. kernel32 and ntdll). |
| 134 | + pub unsafe fn new(name: &CStr) -> Option<Self> { |
| 135 | + // SAFETY: A CStr is always null terminated. |
| 136 | + let module = c::GetModuleHandleA(name.as_ptr()); |
| 137 | + NonNull::new(module).map(Self) |
| 138 | + } |
| 139 | + |
| 140 | + // Try to get the address of a function. |
| 141 | + pub fn proc_address(self, name: &CStr) -> Option<NonNull<c_void>> { |
| 142 | + // SAFETY: |
| 143 | + // `self.0` will always be a valid module. |
| 144 | + // A CStr is always null terminated. |
| 145 | + let proc = unsafe { c::GetProcAddress(self.0.as_ptr(), name.as_ptr()) }; |
| 146 | + NonNull::new(proc) |
| 147 | + } |
| 148 | +} |
| 149 | + |
| 150 | +/// Load a function or use a fallback implementation if that fails. |
| 151 | +macro_rules! compat_fn_with_fallback { |
| 152 | + (pub static $module:ident: &CStr = $name:expr; $( |
54 | 153 | $(#[$meta:meta])* |
55 | 154 | pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block |
56 | | - )*) => ($( |
| 155 | + )*) => ( |
| 156 | + pub static $module: &CStr = $name; |
| 157 | + $( |
57 | 158 | $(#[$meta])* |
58 | 159 | pub mod $symbol { |
59 | 160 | #[allow(unused_imports)] |
60 | 161 | use super::*; |
61 | 162 | use crate::mem; |
| 163 | + use crate::ffi::CStr; |
| 164 | + use crate::sync::atomic::{AtomicPtr, Ordering}; |
| 165 | + use crate::sys::compat::Module; |
62 | 166 |
|
63 | 167 | type F = unsafe extern "system" fn($($argtype),*) -> $rettype; |
64 | 168 |
|
65 | | - /// Points to the DLL import, or the fallback function. |
66 | | - /// |
67 | | - /// This static can be an ordinary, unsynchronized, mutable static because |
68 | | - /// we guarantee that all of the writes finish during CRT initialization, |
69 | | - /// and all of the reads occur after CRT initialization. |
70 | | - static mut PTR: Option<F> = None; |
71 | | - |
72 | | - /// This symbol is what allows the CRT to find the `init` function and call it. |
73 | | - /// It is marked `#[used]` because otherwise Rust would assume that it was not |
74 | | - /// used, and would remove it. |
75 | | - #[used] |
76 | | - #[link_section = ".CRT$XCU"] |
77 | | - static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init; |
78 | | - |
79 | | - unsafe extern "C" fn init() { |
80 | | - PTR = get_f(); |
| 169 | + /// `PTR` contains a function pointer to one of three functions. |
| 170 | + /// It starts with the `load` function. |
| 171 | + /// When that is called it attempts to load the requested symbol. |
| 172 | + /// If it succeeds, `PTR` is set to the address of that symbol. |
| 173 | + /// If it fails, then `PTR` is set to `fallback`. |
| 174 | + static PTR: AtomicPtr<c_void> = AtomicPtr::new(load as *mut _); |
| 175 | + |
| 176 | + unsafe extern "system" fn load($($argname: $argtype),*) -> $rettype { |
| 177 | + let func = load_from_module(Module::new($module)); |
| 178 | + func($($argname),*) |
81 | 179 | } |
82 | 180 |
|
83 | | - unsafe extern "C" fn get_f() -> Option<F> { |
84 | | - // There is no locking here. This code is executed before main() is entered, and |
85 | | - // is guaranteed to be single-threaded. |
86 | | - // |
87 | | - // DO NOT do anything interesting or complicated in this function! DO NOT call |
88 | | - // any Rust functions or CRT functions, if those functions touch any global state, |
89 | | - // because this function runs during global initialization. For example, DO NOT |
90 | | - // do any dynamic allocation, don't call LoadLibrary, etc. |
91 | | - let module_name: *const u8 = concat!($module, "\0").as_ptr(); |
92 | | - let symbol_name: *const u8 = concat!(stringify!($symbol), "\0").as_ptr(); |
93 | | - let module_handle = $crate::sys::c::GetModuleHandleA(module_name as *const i8); |
94 | | - if !module_handle.is_null() { |
95 | | - let ptr = $crate::sys::c::GetProcAddress(module_handle, symbol_name as *const i8); |
96 | | - if !ptr.is_null() { |
97 | | - // Transmute to the right function pointer type. |
98 | | - return Some(mem::transmute(ptr)); |
| 181 | + fn load_from_module(module: Option<Module>) -> F { |
| 182 | + unsafe { |
| 183 | + static symbol_name: &CStr = ansi_str!(sym $symbol); |
| 184 | + if let Some(f) = module.and_then(|m| m.proc_address(symbol_name)) { |
| 185 | + PTR.store(f.as_ptr(), Ordering::Relaxed); |
| 186 | + mem::transmute(f) |
| 187 | + } else { |
| 188 | + PTR.store(fallback as *mut _, Ordering::Relaxed); |
| 189 | + fallback |
99 | 190 | } |
100 | 191 | } |
101 | | - return None; |
102 | 192 | } |
103 | 193 |
|
104 | | - #[allow(dead_code)] |
| 194 | + #[allow(unused_variables)] |
| 195 | + unsafe extern "system" fn fallback($($argname: $argtype),*) -> $rettype { |
| 196 | + $fallback_body |
| 197 | + } |
| 198 | + |
| 199 | + #[allow(unused)] |
| 200 | + pub(in crate::sys) fn preload(module: Module) { |
| 201 | + load_from_module(Some(module)); |
| 202 | + } |
| 203 | + |
| 204 | + #[inline(always)] |
| 205 | + pub unsafe fn call($($argname: $argtype),*) -> $rettype { |
| 206 | + let func: F = mem::transmute(PTR.load(Ordering::Relaxed)); |
| 207 | + func($($argname),*) |
| 208 | + } |
| 209 | + } |
| 210 | + $(#[$meta])* |
| 211 | + pub use $symbol::call as $symbol; |
| 212 | + )*) |
| 213 | +} |
| 214 | + |
| 215 | +/// A function that either exists or doesn't. |
| 216 | +/// |
| 217 | +/// NOTE: Optional functions must be preloaded in the `init` function above, or they will always be None. |
| 218 | +macro_rules! compat_fn_optional { |
| 219 | + (pub static $module:ident: &CStr = $name:expr; $( |
| 220 | + $(#[$meta:meta])* |
| 221 | + pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty; |
| 222 | + )*) => ( |
| 223 | + pub static $module: &CStr = $name; |
| 224 | + $( |
| 225 | + $(#[$meta])* |
| 226 | + pub mod $symbol { |
| 227 | + #[allow(unused_imports)] |
| 228 | + use super::*; |
| 229 | + use crate::mem; |
| 230 | + use crate::sync::atomic::{AtomicPtr, Ordering}; |
| 231 | + use crate::sys::compat::Module; |
| 232 | + use crate::ptr::{self, NonNull}; |
| 233 | + |
| 234 | + type F = unsafe extern "system" fn($($argtype),*) -> $rettype; |
| 235 | + |
| 236 | + /// `PTR` will either be `null()` or set to the loaded function. |
| 237 | + static PTR: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut()); |
| 238 | + |
| 239 | + /// Only allow access to the function if it has loaded successfully. |
105 | 240 | #[inline(always)] |
| 241 | + #[cfg(not(miri))] |
106 | 242 | pub fn option() -> Option<F> { |
107 | 243 | unsafe { |
108 | | - if cfg!(miri) { |
109 | | - // Miri does not run `init`, so we just call `get_f` each time. |
110 | | - get_f() |
111 | | - } else { |
112 | | - PTR |
113 | | - } |
| 244 | + NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| mem::transmute(f)) |
114 | 245 | } |
115 | 246 | } |
116 | 247 |
|
117 | | - #[allow(dead_code)] |
118 | | - pub unsafe fn call($($argname: $argtype),*) -> $rettype { |
119 | | - if let Some(ptr) = option() { |
120 | | - return ptr($($argname),*); |
| 248 | + // Miri does not understand the way we do preloading |
| 249 | + // therefore load the function here instead. |
| 250 | + #[cfg(miri)] |
| 251 | + pub fn option() -> Option<F> { |
| 252 | + let mut func = NonNull::new(PTR.load(Ordering::Relaxed)); |
| 253 | + if func.is_none() { |
| 254 | + Module::new($module).map(preload); |
| 255 | + func = NonNull::new(PTR.load(Ordering::Relaxed)); |
| 256 | + } |
| 257 | + unsafe { |
| 258 | + func.map(|f| mem::transmute(f)) |
121 | 259 | } |
122 | | - $fallback_body |
123 | 260 | } |
124 | | - } |
125 | 261 |
|
126 | | - $(#[$meta])* |
127 | | - pub use $symbol::call as $symbol; |
| 262 | + #[allow(unused)] |
| 263 | + pub(in crate::sys) fn preload(module: Module) { |
| 264 | + unsafe { |
| 265 | + let symbol_name = ansi_str!(sym $symbol); |
| 266 | + if let Some(f) = module.proc_address(symbol_name) { |
| 267 | + PTR.store(f.as_ptr(), Ordering::Relaxed); |
| 268 | + } |
| 269 | + } |
| 270 | + } |
| 271 | + } |
128 | 272 | )*) |
129 | 273 | } |
0 commit comments