| //! Parses ELF auxiliary vectors. |
| #![cfg_attr( |
| any(target_arch = "aarch64", target_arch = "powerpc64", target_arch = "riscv64"), |
| allow(dead_code) |
| )] |
| |
| /// Cache HWCAP bitfields of the ELF Auxiliary Vector. |
| /// |
| /// If an entry cannot be read all the bits in the bitfield are set to zero. |
| /// This should be interpreted as all the features being disabled. |
| #[derive(Debug, Copy, Clone)] |
| pub(crate) struct AuxVec { |
| pub hwcap: usize, |
| pub hwcap2: usize, |
| } |
| |
| /// ELF Auxiliary Vector |
| /// |
| /// The auxiliary vector is a memory region in a running ELF program's stack |
| /// composed of (key: usize, value: usize) pairs. |
| /// |
| /// The keys used in the aux vector are platform dependent. For OpenBSD, they are |
| /// defined in [machine/elf.h][elfh]. The hardware capabilities of a given CPU |
| /// can be queried with the `AT_HWCAP` and `AT_HWCAP2` keys. |
| /// |
| /// Note that run-time feature detection is not invoked for features that can |
| /// be detected at compile-time. |
| /// |
| /// [elf.h]: https://github.com/openbsd/src/blob/master/sys/arch/arm64/include/elf.h |
| /// [elf.h]: https://github.com/openbsd/src/blob/master/sys/arch/powerpc64/include/elf.h |
| pub(crate) fn auxv() -> Result<AuxVec, ()> { |
| let hwcap = archauxv(libc::AT_HWCAP); |
| let hwcap2 = archauxv(libc::AT_HWCAP2); |
| // Zero could indicate that no features were detected, but it's also used to |
| // indicate an error. In particular, on many platforms AT_HWCAP2 will be |
| // legitimately zero, since it contains the most recent feature flags. |
| if hwcap != 0 || hwcap2 != 0 { |
| return Ok(AuxVec { hwcap, hwcap2 }); |
| } |
| Err(()) |
| } |
| |
| /// Tries to read the `key` from the auxiliary vector. |
| fn archauxv(key: libc::c_int) -> usize { |
| const OUT_LEN: libc::c_int = core::mem::size_of::<libc::c_ulong>() as libc::c_int; |
| let mut out: libc::c_ulong = 0; |
| unsafe { |
| let res = |
| libc::elf_aux_info(key, &mut out as *mut libc::c_ulong as *mut libc::c_void, OUT_LEN); |
| // If elf_aux_info fails, `out` will be left at zero (which is the proper default value). |
| debug_assert!(res == 0 || out == 0); |
| } |
| out as usize |
| } |