|
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