|
| 1 | +//! Parses ELF auxiliary vectors. |
| 2 | +#![cfg_attr( |
| 3 | + any( |
| 4 | + target_arch = "aarch64", |
| 5 | + target_arch = "powerpc64", |
| 6 | + target_arch = "riscv64" |
| 7 | + ), |
| 8 | + allow(dead_code) |
| 9 | +)] |
| 10 | + |
| 11 | +/// Cache HWCAP bitfields of the ELF Auxiliary Vector. |
| 12 | +/// |
| 13 | +/// If an entry cannot be read all the bits in the bitfield are set to zero. |
| 14 | +/// This should be interpreted as all the features being disabled. |
| 15 | +#[derive(Debug, Copy, Clone)] |
| 16 | +pub(crate) struct AuxVec { |
| 17 | + pub hwcap: usize, |
| 18 | + pub hwcap2: usize, |
| 19 | +} |
| 20 | + |
| 21 | +/// ELF Auxiliary Vector |
| 22 | +/// |
| 23 | +/// The auxiliary vector is a memory region in a running ELF program's stack |
| 24 | +/// composed of (key: usize, value: usize) pairs. |
| 25 | +/// |
| 26 | +/// The keys used in the aux vector are platform dependent. For OpenBSD, they are |
| 27 | +/// defined in [machine/elf.h][elfh]. The hardware capabilities of a given CPU |
| 28 | +/// can be queried with the `AT_HWCAP` and `AT_HWCAP2` keys. |
| 29 | +/// |
| 30 | +/// Note that run-time feature detection is not invoked for features that can |
| 31 | +/// be detected at compile-time. |
| 32 | +/// |
| 33 | +/// [elf.h]: https://github.com/openbsd/src/blob/master/sys/arch/arm64/include/elf.h |
| 34 | +/// [elf.h]: https://github.com/openbsd/src/blob/master/sys/arch/powerpc64/include/elf.h |
| 35 | +pub(crate) fn auxv() -> Result<AuxVec, ()> { |
| 36 | + let hwcap = archauxv(libc::AT_HWCAP); |
| 37 | + let hwcap2 = archauxv(libc::AT_HWCAP2); |
| 38 | + // Zero could indicate that no features were detected, but it's also used to |
| 39 | + // indicate an error. In particular, on many platforms AT_HWCAP2 will be |
| 40 | + // legitimately zero, since it contains the most recent feature flags. |
| 41 | + if hwcap != 0 || hwcap2 != 0 { |
| 42 | + return Ok(AuxVec { hwcap, hwcap2 }); |
| 43 | + } |
| 44 | + Err(()) |
| 45 | +} |
| 46 | + |
| 47 | +/// Tries to read the `key` from the auxiliary vector. |
| 48 | +fn archauxv(key: libc::c_int) -> usize { |
| 49 | + const OUT_LEN: libc::c_int = core::mem::size_of::<libc::c_ulong>() as libc::c_int; |
| 50 | + let mut out: libc::c_ulong = 0; |
| 51 | + unsafe { |
| 52 | + let res = |
| 53 | + libc::elf_aux_info(key, &mut out as *mut libc::c_ulong as *mut libc::c_void, OUT_LEN); |
| 54 | + // If elf_aux_info fails, `out` will be left at zero (which is the proper default value). |
| 55 | + debug_assert!(res == 0 || out == 0); |
| 56 | + } |
| 57 | + out as usize |
| 58 | +} |
0 commit comments