]> git.proxmox.com Git - rustc.git/blame - vendor/rustix/src/imp/linux_raw/param/auxv.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / vendor / rustix / src / imp / linux_raw / param / auxv.rs
CommitLineData
064997fb
FG
1//! Linux auxv support.
2//!
3//! # Safety
4//!
5//! This uses raw pointers to locate and read the kernel-provided auxv array.
6#![allow(unsafe_code)]
7
8use super::super::c;
9use super::super::elf::{Elf_Ehdr, Elf_Phdr};
10#[cfg(feature = "param")]
11use crate::ffi::CStr;
12use core::mem::size_of;
13use core::ptr::null;
14#[cfg(feature = "runtime")]
15use core::slice;
16use linux_raw_sys::general::{
17 AT_CLKTCK, AT_EXECFN, AT_HWCAP, AT_HWCAP2, AT_NULL, AT_PAGESZ, AT_PHDR, AT_PHENT, AT_PHNUM,
18 AT_SYSINFO_EHDR,
19};
20
21#[cfg(feature = "param")]
22#[inline]
23pub(crate) fn page_size() -> usize {
24 auxv().page_size
25}
26
27#[cfg(feature = "param")]
28#[inline]
29pub(crate) fn clock_ticks_per_second() -> u64 {
30 auxv().clock_ticks_per_second as u64
31}
32
33#[cfg(feature = "param")]
34#[inline]
35pub(crate) fn linux_hwcap() -> (usize, usize) {
36 let auxv = auxv();
37 (auxv.hwcap, auxv.hwcap2)
38}
39
40#[cfg(feature = "param")]
41#[inline]
42pub(crate) fn linux_execfn() -> &'static CStr {
43 let execfn = auxv().execfn;
44
45 // Safety: We assume the `AT_EXECFN` value provided by the kernel is a
46 // valid pointer to a valid NUL-terminated array of bytes.
47 unsafe { CStr::from_ptr(execfn.cast()) }
48}
49
50#[cfg(feature = "runtime")]
51#[inline]
52pub(crate) fn exe_phdrs() -> (*const c::c_void, usize) {
53 let auxv = auxv();
54 (auxv.phdr.cast(), auxv.phnum)
55}
56
57#[cfg(feature = "runtime")]
58#[inline]
59pub(in super::super) fn exe_phdrs_slice() -> &'static [Elf_Phdr] {
60 let auxv = auxv();
61
62 // Safety: We assume the `AT_PHDR` and `AT_PHNUM` values provided by the
63 // kernel form a valid slice.
64 unsafe { slice::from_raw_parts(auxv.phdr, auxv.phnum) }
65}
66
67#[inline]
68pub(in super::super) fn sysinfo_ehdr() -> *const Elf_Ehdr {
69 auxv().sysinfo_ehdr
70}
71
72#[inline]
73fn auxv() -> &'static Auxv {
74 // Safety: `AUXV` is initialized from the `.init_array`, and we never
75 // mutate it thereafter, so it's effectively initialized read-only in all
76 // other code.
77 unsafe {
78 // Assert that the initialization has happened. On glibc and musl, this
79 // is handled automatically by `.init_array` functions. Otherwise,
80 // `rustix::process::init` must be called explicitly.
81 debug_assert_ne!(AUXV.page_size, 0);
82
83 &AUXV
84 }
85}
86
87/// A struct for holding fields obtained from the kernel-provided auxv array.
88struct Auxv {
89 page_size: usize,
90 clock_ticks_per_second: usize,
91 hwcap: usize,
92 hwcap2: usize,
93 sysinfo_ehdr: *const Elf_Ehdr,
94 phdr: *const Elf_Phdr,
95 phnum: usize,
96 execfn: *const c::c_char,
97}
98
99/// Data obtained from the kernel-provided auxv array. This is initialized at
100/// program startup below.
101static mut AUXV: Auxv = Auxv {
102 page_size: 0,
103 clock_ticks_per_second: 0,
104 hwcap: 0,
105 hwcap2: 0,
106 sysinfo_ehdr: null(),
107 phdr: null(),
108 phnum: 0,
109 execfn: null(),
110};
111
112/// GLIBC passes argc, argv, and envp to functions in .init_array, as a
113/// non-standard extension. Use priority 99 so that we run before any
114/// normal user-defined constructor functions.
115#[cfg(all(target_env = "gnu", not(target_vendor = "mustang")))]
116#[used]
117#[link_section = ".init_array.00099"]
118static INIT_ARRAY: unsafe extern "C" fn(c::c_int, *mut *mut u8, *mut *mut u8) = {
119 unsafe extern "C" fn function(_argc: c::c_int, _argv: *mut *mut u8, envp: *mut *mut u8) {
120 init_from_envp(envp);
121 }
122 function
123};
124
125/// For musl, assume that `__environ` is available and points to the original
126/// environment from the kernel, so we can find the auxv array in memory after
127/// it. Use priority 99 so that we run before any normal user-defined
128/// constructor functions.
129///
130/// <https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/baselib---environ.html>
131#[cfg(all(target_env = "musl", not(target_vendor = "mustang")))]
132#[used]
133#[link_section = ".init_array.00099"]
134static INIT_ARRAY: unsafe extern "C" fn() = {
135 unsafe extern "C" fn function() {
136 extern "C" {
137 static __environ: *mut *mut u8;
138 }
139
140 init_from_envp(__environ)
141 }
142 function
143};
144
145/// On mustang or any non-musl non-glibic platform where we don't know that we
146/// have `.init_array`, we export a function to be called during
147/// initialization, and passed a pointer to the original environment variable
148/// block set up by the OS.
149#[cfg(any(
150 target_vendor = "mustang",
151 not(any(target_env = "gnu", target_env = "musl")),
152))]
153#[inline]
154pub(crate) unsafe fn init(envp: *mut *mut u8) {
155 init_from_envp(envp);
156}
157
158/// # Safety
159///
160/// This must be passed a pointer to the environment variable buffer
161/// provided by the kernel, which is followed in memory by the auxv array.
162unsafe fn init_from_envp(mut envp: *mut *mut u8) {
163 while !(*envp).is_null() {
164 envp = envp.add(1);
165 }
166 init_from_auxp(envp.add(1).cast())
167}
168
169/// # Safety
170///
171/// This must be passed a pointer to the auxv array provided by the kernel.
172unsafe fn init_from_auxp(mut auxp: *const Elf_auxv_t) {
173 loop {
174 let Elf_auxv_t { a_type, a_val } = *auxp;
175 match a_type as _ {
176 AT_PAGESZ => AUXV.page_size = a_val as usize,
177 AT_CLKTCK => AUXV.clock_ticks_per_second = a_val as usize,
178 AT_HWCAP => AUXV.hwcap = a_val as usize,
179 AT_HWCAP2 => AUXV.hwcap2 = a_val as usize,
180 AT_SYSINFO_EHDR => AUXV.sysinfo_ehdr = a_val.cast(),
181 AT_PHDR => AUXV.phdr = a_val.cast(),
182 AT_PHNUM => AUXV.phnum = a_val as usize,
183 AT_PHENT => assert_eq!(a_val as usize, size_of::<Elf_Phdr>()),
184 AT_EXECFN => AUXV.execfn = a_val.cast(),
185 AT_NULL => break,
186 _ => (),
187 }
188 auxp = auxp.add(1);
189 }
190}
191
192// ELF ABI
193
194#[repr(C)]
195#[derive(Copy, Clone)]
196struct Elf_auxv_t {
197 a_type: usize,
198
199 // Some of the values in the auxv array are pointers, so we make `a_val` a
200 // pointer, in order to preserve their provenance. For the values which are
201 // integers, we cast this to `usize`.
202 a_val: *const (),
203}