Skip to content

Commit 5231fbc

Browse files
committed
std_detect: Support run-time detection on OpenBSD using elf_aux_info
1 parent caccb4d commit 5231fbc

File tree

6 files changed

+111
-5
lines changed

6 files changed

+111
-5
lines changed

library/std_detect/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,12 @@ crate from working on applications in which `std` is not available.
6666

6767
* FreeBSD:
6868
* `arm32`, `powerpc64`: `std_detect` supports these on FreeBSD by querying ELF
69-
auxiliary vectors using `sysctl`.
69+
auxiliary vectors using `elf_aux_info`.
7070
* `arm64`: run-time feature detection is implemented by directly querying `mrs`.
7171

7272
* OpenBSD:
73+
* `powerpc64`: `std_detect` supports these on OpenBSD by querying ELF auxiliary
74+
vectors using `elf_aux_info`.
7375
* `arm64`: run-time feature detection is implemented by querying `sysctl`.
7476

7577
* Windows:

library/std_detect/src/detect/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,12 @@ cfg_select! {
6161
#[path = "os/freebsd/mod.rs"]
6262
mod os;
6363
}
64-
all(target_os = "openbsd", target_arch = "aarch64", feature = "libc") => {
64+
all(target_os = "openbsd", feature = "libc") => {
6565
#[allow(dead_code)] // we don't use code that calls the mrs instruction.
66+
#[cfg(target_arch = "aarch64")]
6667
#[path = "os/aarch64.rs"]
6768
mod aarch64;
68-
#[path = "os/openbsd/aarch64.rs"]
69+
#[path = "os/openbsd/mod.rs"]
6970
mod os;
7071
}
7172
all(target_os = "windows", any(target_arch = "aarch64", target_arch = "arm64ec")) => {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//! Run-time feature detection on OpenBSD
2+
3+
mod auxvec;
4+
5+
cfg_select! {
6+
target_arch = "aarch64" => {
7+
mod aarch64;
8+
pub(crate) use self::aarch64::detect_features;
9+
}
10+
target_arch = "powerpc64" => {
11+
mod powerpc;
12+
pub(crate) use self::powerpc::detect_features;
13+
}
14+
_ => {
15+
use crate::detect::cache;
16+
/// Performs run-time feature detection.
17+
pub(crate) fn detect_features() -> cache::Initializer {
18+
cache::Initializer::default()
19+
}
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//! Run-time feature detection for PowerPC on OpenBSD.
2+
3+
use super::auxvec;
4+
use crate::detect::{Feature, cache};
5+
6+
pub(crate) fn detect_features() -> cache::Initializer {
7+
let mut value = cache::Initializer::default();
8+
let enable_feature = |value: &mut cache::Initializer, f, enable| {
9+
if enable {
10+
value.set(f as u32);
11+
}
12+
};
13+
14+
if let Ok(auxv) = auxvec::auxv() {
15+
enable_feature(&mut value, Feature::altivec, auxv.hwcap & 0x10000000 != 0);
16+
enable_feature(&mut value, Feature::vsx, auxv.hwcap & 0x00000080 != 0);
17+
enable_feature(&mut value, Feature::power8, auxv.hwcap2 & 0x80000000 != 0);
18+
return value;
19+
}
20+
value
21+
}

library/std_detect/tests/cpu-detection.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,8 +320,11 @@ fn powerpc_linux() {
320320
}
321321

322322
#[test]
323-
#[cfg(all(target_arch = "powerpc64", any(target_os = "linux", target_os = "freebsd"),))]
324-
fn powerpc64_linux_or_freebsd() {
323+
#[cfg(all(
324+
target_arch = "powerpc64",
325+
any(target_os = "linux", target_os = "freebsd", target_os = "openbsd"),
326+
))]
327+
fn powerpc64_linux_or_bsd() {
325328
println!("altivec: {}", is_powerpc64_feature_detected!("altivec"));
326329
println!("vsx: {}", is_powerpc64_feature_detected!("vsx"));
327330
println!("power8: {}", is_powerpc64_feature_detected!("power8"));

0 commit comments

Comments
 (0)