//! Linux auxv `init` function, for "use-explicitly-provided-auxv" mode. //! //! # Safety //! //! This uses raw pointers to locate and read the kernel-provided auxv array. #![allow(unsafe_code)] use crate::backend::c; #[cfg(feature = "param")] use crate::ffi::CStr; use core::ffi::c_void; use core::ptr::{null_mut, read, NonNull}; #[cfg(feature = "runtime")] use core::sync::atomic::AtomicBool; use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; use linux_raw_sys::elf::*; use linux_raw_sys::general::{ AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_SYSINFO_EHDR, }; #[cfg(feature = "runtime")] use linux_raw_sys::general::{AT_ENTRY, AT_PHDR, AT_PHENT, AT_PHNUM, AT_RANDOM, AT_SECURE}; #[cfg(feature = "param")] #[inline] pub(crate) fn page_size() -> usize { unsafe { PAGE_SIZE.load(Ordering::Relaxed) } } #[cfg(feature = "param")] #[inline] pub(crate) fn clock_ticks_per_second() -> u64 { unsafe { CLOCK_TICKS_PER_SECOND.load(Ordering::Relaxed) as u64 } } #[cfg(feature = "param")] #[inline] pub(crate) fn linux_hwcap() -> (usize, usize) { unsafe { ( HWCAP.load(Ordering::Relaxed), HWCAP2.load(Ordering::Relaxed), ) } } #[cfg(feature = "param")] #[inline] pub(crate) fn linux_execfn() -> &'static CStr { let execfn = unsafe { EXECFN.load(Ordering::Relaxed) }; // SAFETY: We initialize `EXECFN` to a valid `CStr` pointer, and we assume // the `AT_EXECFN` value provided by the kernel points to a valid C string. unsafe { CStr::from_ptr(execfn.cast()) } } #[cfg(feature = "runtime")] #[inline] pub(crate) fn linux_secure() -> bool { unsafe { SECURE.load(Ordering::Relaxed) } } #[cfg(feature = "runtime")] #[inline] pub(crate) fn exe_phdrs() -> (*const c_void, usize, usize) { unsafe { ( PHDR.load(Ordering::Relaxed).cast(), PHENT.load(Ordering::Relaxed), PHNUM.load(Ordering::Relaxed), ) } } /// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations, so /// if we don't see it, this function returns a null pointer. #[inline] pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr { unsafe { SYSINFO_EHDR.load(Ordering::Relaxed) } } #[cfg(feature = "runtime")] #[inline] pub(crate) fn entry() -> usize { unsafe { ENTRY.load(Ordering::Relaxed) } } #[cfg(feature = "runtime")] #[inline] pub(crate) fn random() -> *const [u8; 16] { unsafe { RANDOM.load(Ordering::Relaxed) } } static mut PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); static mut CLOCK_TICKS_PER_SECOND: AtomicUsize = AtomicUsize::new(0); static mut HWCAP: AtomicUsize = AtomicUsize::new(0); static mut HWCAP2: AtomicUsize = AtomicUsize::new(0); static mut SYSINFO_EHDR: AtomicPtr = AtomicPtr::new(null_mut()); // Initialize `EXECFN` to a valid `CStr` pointer so that we don't need to check // for null on every `execfn` call. static mut EXECFN: AtomicPtr = AtomicPtr::new(b"\0".as_ptr() as _); #[cfg(feature = "runtime")] static mut SECURE: AtomicBool = AtomicBool::new(false); // Use `dangling` so that we can always treat it like an empty slice. #[cfg(feature = "runtime")] static mut PHDR: AtomicPtr = AtomicPtr::new(NonNull::dangling().as_ptr()); #[cfg(feature = "runtime")] static mut PHENT: AtomicUsize = AtomicUsize::new(0); #[cfg(feature = "runtime")] static mut PHNUM: AtomicUsize = AtomicUsize::new(0); #[cfg(feature = "runtime")] static mut ENTRY: AtomicUsize = AtomicUsize::new(0); #[cfg(feature = "runtime")] static mut RANDOM: AtomicPtr<[u8; 16]> = AtomicPtr::new(NonNull::dangling().as_ptr()); /// When "use-explicitly-provided-auxv" is enabled, we export a function to be /// called during initialization, and passed a pointer to the original /// environment variable block set up by the OS. pub(crate) unsafe fn init(envp: *mut *mut u8) { init_from_envp(envp); } /// # Safety /// /// This must be passed a pointer to the environment variable buffer /// provided by the kernel, which is followed in memory by the auxv array. unsafe fn init_from_envp(mut envp: *mut *mut u8) { while !(*envp).is_null() { envp = envp.add(1); } init_from_auxp(envp.add(1).cast()) } /// Process auxv entries from the auxv array pointed to by `auxp`. /// /// # Safety /// /// This must be passed a pointer to an auxv array. /// /// The buffer contains `Elf_aux_t` elements, though it need not be aligned; /// function uses `read_unaligned` to read from it. unsafe fn init_from_auxp(mut auxp: *const Elf_auxv_t) { loop { let Elf_auxv_t { a_type, a_val } = read(auxp); match a_type as _ { AT_PAGESZ => PAGE_SIZE.store(a_val as usize, Ordering::Relaxed), AT_CLKTCK => CLOCK_TICKS_PER_SECOND.store(a_val as usize, Ordering::Relaxed), AT_HWCAP => HWCAP.store(a_val as usize, Ordering::Relaxed), AT_HWCAP2 => HWCAP2.store(a_val as usize, Ordering::Relaxed), AT_EXECFN => EXECFN.store(a_val.cast::(), Ordering::Relaxed), AT_SYSINFO_EHDR => SYSINFO_EHDR.store(a_val.cast::(), Ordering::Relaxed), #[cfg(feature = "runtime")] AT_SECURE => SECURE.store(a_val as usize != 0, Ordering::Relaxed), #[cfg(feature = "runtime")] AT_PHDR => PHDR.store(a_val.cast::(), Ordering::Relaxed), #[cfg(feature = "runtime")] AT_PHNUM => PHNUM.store(a_val as usize, Ordering::Relaxed), #[cfg(feature = "runtime")] AT_PHENT => PHENT.store(a_val as usize, Ordering::Relaxed), #[cfg(feature = "runtime")] AT_ENTRY => ENTRY.store(a_val as usize, Ordering::Relaxed), #[cfg(feature = "runtime")] AT_RANDOM => RANDOM.store(a_val.cast::<[u8; 16]>(), Ordering::Relaxed), AT_NULL => break, _ => (), } auxp = auxp.add(1); } }