| 1 | //! The configure builtins provides runtime support compiler-builtin features |
| 2 | //! which require dynamic initialization to work as expected, e.g. aarch64 |
| 3 | //! outline-atomics. |
| 4 | |
| 5 | /// Enable LSE atomic operations at startup, if supported. |
| 6 | /// |
| 7 | /// Linker sections are based on what [`ctor`] does, with priorities to run slightly before user |
| 8 | /// code: |
| 9 | /// |
| 10 | /// - Apple uses the section `__mod_init_func`, `mod_init_funcs` is needed to set |
| 11 | /// `S_MOD_INIT_FUNC_POINTERS`. There doesn't seem to be a way to indicate priorities. |
| 12 | /// - Windows uses `.CRT$XCT`, which is run before user constructors (these should use `.CRT$XCU`). |
| 13 | /// - ELF uses `.init_array` with a priority of 90, which runs before our `ARGV_INIT_ARRAY` |
| 14 | /// initializer (priority 99). Both are within the 0-100 implementation-reserved range, per docs |
| 15 | /// for the [`prio-ctor-dtor`] warning, and this matches compiler-rt's `CONSTRUCTOR_PRIORITY`. |
| 16 | /// |
| 17 | /// To save startup time, the initializer is only run if outline atomic routines from |
| 18 | /// compiler-builtins may be used. If LSE is known to be available then the calls are never |
| 19 | /// emitted, and if we build the C intrinsics then it has its own initializer using the symbol |
| 20 | /// `__aarch64_have_lse_atomics`. |
| 21 | /// |
| 22 | /// Initialization is done in a global constructor to so we get the same behavior regardless of |
| 23 | /// whether Rust's `init` is used, or if we are in a `dylib` or `no_main` situation (as opposed |
| 24 | /// to doing it as part of pre-main startup). This also matches C implementations. |
| 25 | /// |
| 26 | /// Ideally `core` would have something similar, but detecting the CPU features requires the |
| 27 | /// auxiliary vector from the OS. We do the initialization in `std` rather than as part of |
| 28 | /// `compiler-builtins` because a builtins->std dependency isn't possible, and inlining parts of |
| 29 | /// `std-detect` would be much messier. |
| 30 | /// |
| 31 | /// [`ctor`]: https://github.com/mmastrac/rust-ctor/blob/63382b833ddcbfb8b064f4e86bfa1ed4026ff356/shared/src/macros/mod.rs#L522-L534 |
| 32 | /// [`prio-ctor-dtor`]: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html |
| 33 | #[cfg (all( |
| 34 | target_arch = "aarch64" , |
| 35 | target_feature = "outline-atomics" , |
| 36 | not(target_feature = "lse" ), |
| 37 | not(feature = "compiler-builtins-c" ), |
| 38 | ))] |
| 39 | #[used ] |
| 40 | #[cfg_attr (target_vendor = "apple" , unsafe(link_section = "__DATA,__mod_init_func,mod_init_funcs" ))] |
| 41 | #[cfg_attr (target_os = "windows" , unsafe(link_section = ".CRT$XCT" ))] |
| 42 | #[cfg_attr ( |
| 43 | not(any(target_vendor = "apple" , target_os = "windows" )), |
| 44 | unsafe(link_section = ".init_array.90" ) |
| 45 | )] |
| 46 | static RUST_LSE_INIT: extern "C" fn() = { |
| 47 | extern "C" fn init_lse() { |
| 48 | use crate::arch; |
| 49 | |
| 50 | // This is provided by compiler-builtins::aarch64_outline_atomics. |
| 51 | unsafe extern "C" { |
| 52 | fn __rust_enable_lse(); |
| 53 | } |
| 54 | |
| 55 | if arch::is_aarch64_feature_detected!("lse" ) { |
| 56 | unsafe { |
| 57 | __rust_enable_lse(); |
| 58 | } |
| 59 | } |
| 60 | } |
| 61 | init_lse |
| 62 | }; |
| 63 | |