Revision control
Copy as Markdown
Other Tools
//! 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_MINSIGSTKSZ, 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_minsigstksz() -> usize {
unsafe { MINSIGSTKSZ.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 MINSIGSTKSZ: AtomicUsize = AtomicUsize::new(0);
static mut SYSINFO_EHDR: AtomicPtr<Elf_Ehdr> = 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<c::c_char> = 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<Elf_Phdr> = 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_MINSIGSTKSZ => MINSIGSTKSZ.store(a_val as usize, Ordering::Relaxed),
AT_EXECFN => EXECFN.store(a_val.cast::<c::c_char>(), Ordering::Relaxed),
AT_SYSINFO_EHDR => SYSINFO_EHDR.store(a_val.cast::<Elf_Ehdr>(), 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::<Elf_Phdr>(), 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);
}
}