summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs')
-rw-r--r--vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs159
1 files changed, 159 insertions, 0 deletions
diff --git a/vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs b/vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs
new file mode 100644
index 000000000..e9b89b500
--- /dev/null
+++ b/vendor/rustix/src/backend/linux_raw/param/mustang_auxv.rs
@@ -0,0 +1,159 @@
+//! Linux auxv support, for Mustang.
+//!
+//! # Safety
+//!
+//! This uses raw pointers to locate and read the kernel-provided auxv array.
+#![allow(unsafe_code)]
+
+use super::super::c;
+use super::super::elf::*;
+#[cfg(feature = "param")]
+use crate::ffi::CStr;
+use core::ffi::c_void;
+use core::mem::size_of;
+use core::ptr::{null, read};
+#[cfg(feature = "runtime")]
+use core::slice;
+use linux_raw_sys::general::{
+ AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_PHDR, AT_PHENT, AT_PHNUM,
+ AT_SYSINFO_EHDR,
+};
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn page_size() -> usize {
+ // Safety: This is initialized during program startup.
+ unsafe { PAGE_SIZE }
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn clock_ticks_per_second() -> u64 {
+ // Safety: This is initialized during program startup.
+ unsafe { CLOCK_TICKS_PER_SECOND as u64 }
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn linux_hwcap() -> (usize, usize) {
+ // Safety: This is initialized during program startup.
+ unsafe { (HWCAP, HWCAP2) }
+}
+
+#[cfg(feature = "param")]
+#[inline]
+pub(crate) fn linux_execfn() -> &'static CStr {
+ // Safety: This is initialized during program startup. And we
+ // assume it's a valid pointer to a NUL-terminated string.
+ unsafe { CStr::from_ptr(EXECFN.0.cast()) }
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(crate) fn exe_phdrs() -> (*const c_void, usize) {
+ // Safety: This is initialized during program startup.
+ unsafe { (PHDR.0.cast(), PHNUM) }
+}
+
+#[cfg(feature = "runtime")]
+#[inline]
+pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] {
+ let (phdr, phnum) = exe_phdrs();
+
+ // Safety: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the
+ // kernel form a valid slice.
+ unsafe { slice::from_raw_parts(phdr.cast(), phnum) }
+}
+
+/// `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 {
+ // Safety: This is initialized during program startup.
+ unsafe { SYSINFO_EHDR.0 }
+}
+
+/// A const pointer to `T` that implements [`Sync`].
+#[repr(transparent)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct SyncConstPtr<T>(*const T);
+unsafe impl<T> Sync for SyncConstPtr<T> {}
+
+impl<T> SyncConstPtr<T> {
+ /// Creates a `SyncConstPointer` from a raw pointer.
+ ///
+ /// Behavior is undefined if `ptr` is actually not
+ /// safe to share across threads.
+ pub const unsafe fn new(ptr: *const T) -> Self {
+ Self(ptr)
+ }
+}
+
+static mut PAGE_SIZE: usize = 0;
+static mut CLOCK_TICKS_PER_SECOND: usize = 0;
+static mut HWCAP: usize = 0;
+static mut HWCAP2: usize = 0;
+static mut SYSINFO_EHDR: SyncConstPtr<Elf_Ehdr> = unsafe { SyncConstPtr::new(null()) };
+static mut PHDR: SyncConstPtr<Elf_Phdr> = unsafe { SyncConstPtr::new(null()) };
+static mut PHNUM: usize = 0;
+static mut EXECFN: SyncConstPtr<c::c_char> = unsafe { SyncConstPtr::new(null()) };
+
+/// On mustang, 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 = a_val as usize,
+ AT_CLKTCK => CLOCK_TICKS_PER_SECOND = a_val as usize,
+ AT_HWCAP => HWCAP = a_val as usize,
+ AT_HWCAP2 => HWCAP2 = a_val as usize,
+ AT_PHDR => PHDR = SyncConstPtr::new(a_val.cast::<Elf_Phdr>()),
+ AT_PHNUM => PHNUM = a_val as usize,
+ AT_PHENT => assert_eq!(a_val as usize, size_of::<Elf_Phdr>()),
+ AT_EXECFN => EXECFN = SyncConstPtr::new(a_val.cast::<c::c_char>()),
+ AT_SYSINFO_EHDR => SYSINFO_EHDR = SyncConstPtr::new(a_val.cast::<Elf_Ehdr>()),
+ AT_NULL => break,
+ _ => (),
+ }
+ auxp = auxp.add(1);
+ }
+}
+
+// ELF ABI
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct Elf_auxv_t {
+ a_type: usize,
+
+ // Some of the values in the auxv array are pointers, so we make `a_val` a
+ // pointer, in order to preserve their provenance. For the values which are
+ // integers, we cast this to `usize`.
+ a_val: *const c_void,
+}