rustix/backend/linux_raw/param/
libc_auxv.rs

1//! Linux auxv support, using libc.
2//!
3//! # Safety
4//!
5//! This uses raw pointers to locate and read the kernel-provided auxv array.
6#![allow(unsafe_code)]
7
8use crate::backend::c;
9#[cfg(feature = "param")]
10use crate::ffi::CStr;
11#[cfg(not(feature = "runtime"))]
12use core::ptr::null;
13use linux_raw_sys::elf::*;
14
15// `getauxval` wasn't supported in glibc until 2.16. Also this lets us use
16// `*mut` as the return type to preserve strict provenance.
17#[cfg(not(feature = "runtime"))]
18weak!(fn getauxval(c::c_ulong) -> *mut c::c_void);
19
20// With the "runtime" feature, go ahead and depend on `getauxval` existing so
21// that we never fail.
22#[cfg(feature = "runtime")]
23extern "C" {
24    fn getauxval(type_: c::c_ulong) -> *mut c::c_void;
25}
26
27#[cfg(feature = "runtime")]
28const AT_PHDR: c::c_ulong = 3;
29#[cfg(feature = "runtime")]
30const AT_PHENT: c::c_ulong = 4;
31#[cfg(feature = "runtime")]
32const AT_PHNUM: c::c_ulong = 5;
33#[cfg(feature = "runtime")]
34const AT_ENTRY: c::c_ulong = 9;
35const AT_HWCAP: c::c_ulong = 16;
36#[cfg(feature = "runtime")]
37const AT_RANDOM: c::c_ulong = 25;
38const AT_HWCAP2: c::c_ulong = 26;
39const AT_SECURE: c::c_ulong = 23;
40const AT_EXECFN: c::c_ulong = 31;
41const AT_SYSINFO_EHDR: c::c_ulong = 33;
42const AT_MINSIGSTKSZ: c::c_ulong = 51;
43
44// Declare `sysconf` ourselves so that we don't depend on all of libc just for
45// this.
46extern "C" {
47    fn sysconf(name: c::c_int) -> c::c_long;
48}
49
50#[cfg(target_os = "android")]
51const _SC_PAGESIZE: c::c_int = 39;
52#[cfg(target_os = "linux")]
53const _SC_PAGESIZE: c::c_int = 30;
54#[cfg(target_os = "android")]
55const _SC_CLK_TCK: c::c_int = 6;
56#[cfg(target_os = "linux")]
57const _SC_CLK_TCK: c::c_int = 2;
58
59#[test]
60fn test_abi() {
61    const_assert_eq!(self::_SC_PAGESIZE, ::libc::_SC_PAGESIZE);
62    const_assert_eq!(self::_SC_CLK_TCK, ::libc::_SC_CLK_TCK);
63    const_assert_eq!(self::AT_HWCAP, ::libc::AT_HWCAP);
64    const_assert_eq!(self::AT_HWCAP2, ::libc::AT_HWCAP2);
65    const_assert_eq!(self::AT_EXECFN, ::libc::AT_EXECFN);
66    const_assert_eq!(self::AT_SECURE, ::libc::AT_SECURE);
67    const_assert_eq!(self::AT_SYSINFO_EHDR, ::libc::AT_SYSINFO_EHDR);
68    const_assert_eq!(self::AT_MINSIGSTKSZ, ::libc::AT_MINSIGSTKSZ);
69    #[cfg(feature = "runtime")]
70    const_assert_eq!(self::AT_PHDR, ::libc::AT_PHDR);
71    #[cfg(feature = "runtime")]
72    const_assert_eq!(self::AT_PHNUM, ::libc::AT_PHNUM);
73    #[cfg(feature = "runtime")]
74    const_assert_eq!(self::AT_ENTRY, ::libc::AT_ENTRY);
75    #[cfg(feature = "runtime")]
76    const_assert_eq!(self::AT_RANDOM, ::libc::AT_RANDOM);
77}
78
79#[cfg(feature = "param")]
80#[inline]
81pub(crate) fn page_size() -> usize {
82    unsafe { sysconf(_SC_PAGESIZE) as usize }
83}
84
85#[cfg(feature = "param")]
86#[inline]
87pub(crate) fn clock_ticks_per_second() -> u64 {
88    unsafe { sysconf(_SC_CLK_TCK) as u64 }
89}
90
91#[cfg(feature = "param")]
92#[inline]
93pub(crate) fn linux_hwcap() -> (usize, usize) {
94    #[cfg(not(feature = "runtime"))]
95    unsafe {
96        if let Some(libc_getauxval) = getauxval.get() {
97            let hwcap = libc_getauxval(AT_HWCAP) as usize;
98            let hwcap2 = libc_getauxval(AT_HWCAP2) as usize;
99            (hwcap, hwcap2)
100        } else {
101            (0, 0)
102        }
103    }
104
105    #[cfg(feature = "runtime")]
106    unsafe {
107        let hwcap = getauxval(AT_HWCAP) as usize;
108        let hwcap2 = getauxval(AT_HWCAP2) as usize;
109        (hwcap, hwcap2)
110    }
111}
112
113#[cfg(feature = "param")]
114#[inline]
115pub(crate) fn linux_minsigstksz() -> usize {
116    #[cfg(not(feature = "runtime"))]
117    if let Some(libc_getauxval) = getauxval.get() {
118        unsafe { libc_getauxval(AT_MINSIGSTKSZ) as usize }
119    } else {
120        0
121    }
122
123    #[cfg(feature = "runtime")]
124    unsafe {
125        getauxval(AT_MINSIGSTKSZ) as usize
126    }
127}
128
129#[cfg(feature = "param")]
130#[inline]
131pub(crate) fn linux_execfn() -> &'static CStr {
132    #[cfg(not(feature = "runtime"))]
133    unsafe {
134        if let Some(libc_getauxval) = getauxval.get() {
135            CStr::from_ptr(libc_getauxval(AT_EXECFN).cast())
136        } else {
137            cstr!("")
138        }
139    }
140
141    #[cfg(feature = "runtime")]
142    unsafe {
143        CStr::from_ptr(getauxval(AT_EXECFN).cast())
144    }
145}
146
147#[cfg(feature = "runtime")]
148#[inline]
149pub(crate) fn linux_secure() -> bool {
150    unsafe { getauxval(AT_SECURE) as usize != 0 }
151}
152
153#[cfg(feature = "runtime")]
154#[inline]
155pub(crate) fn exe_phdrs() -> (*const c::c_void, usize, usize) {
156    unsafe {
157        let phdr = getauxval(AT_PHDR) as *const c::c_void;
158        let phent = getauxval(AT_PHENT) as usize;
159        let phnum = getauxval(AT_PHNUM) as usize;
160        (phdr, phent, phnum)
161    }
162}
163
164/// `AT_SYSINFO_EHDR` isn't present on all platforms in all configurations, so
165/// if we don't see it, this function returns a null pointer.
166#[inline]
167pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr {
168    #[cfg(not(feature = "runtime"))]
169    unsafe {
170        if let Some(libc_getauxval) = getauxval.get() {
171            libc_getauxval(AT_SYSINFO_EHDR) as *const Elf_Ehdr
172        } else {
173            null()
174        }
175    }
176
177    #[cfg(feature = "runtime")]
178    unsafe {
179        getauxval(AT_SYSINFO_EHDR) as *const Elf_Ehdr
180    }
181}
182
183#[cfg(feature = "runtime")]
184#[inline]
185pub(crate) fn entry() -> usize {
186    unsafe { getauxval(AT_ENTRY) as usize }
187}
188
189#[cfg(feature = "runtime")]
190#[inline]
191pub(crate) fn random() -> *const [u8; 16] {
192    unsafe { getauxval(AT_RANDOM) as *const [u8; 16] }
193}