Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions library/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,6 @@ debug_refcell = ["core/debug_refcell"]

llvm_enzyme = ["core/llvm_enzyme"]

# Enable std_detect features:
std_detect_file_io = ["std_detect/std_detect_file_io"]
std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"]

# Enable using raw-dylib for Windows imports.
# This will eventually be the default.
windows_raw_dylib = ["windows-targets/windows_raw_dylib"]
Expand Down
12 changes: 2 additions & 10 deletions library/std_detect/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ authors = [
"Gonzalo Brito Gadeschi <[email protected]>",
]
description = "`std::detect` - Rust's standard library run-time CPU feature detection."
homepage = "https://github.com/rust-lang/stdarch"
repository = "https://github.com/rust-lang/stdarch"
readme = "README.md"
keywords = ["std", "run-time", "feature", "detection"]
categories = ["hardware-support"]
license = "MIT OR Apache-2.0"
edition = "2024"

Expand All @@ -25,10 +20,7 @@ core = { version = "1.0.0", package = 'rustc-std-workspace-core' }
alloc = { version = "1.0.0", package = 'rustc-std-workspace-alloc' }

[target.'cfg(not(windows))'.dependencies]
libc = { version = "0.2.0", optional = true, default-features = false }
libc = { version = "0.2.0", default-features = false }

[features]
default = []
std_detect_file_io = [ "libc" ]
std_detect_dlsym_getauxval = [ "libc" ]
std_detect_env_override = [ "libc" ]
std_detect_env_override = []
26 changes: 0 additions & 26 deletions library/std_detect/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,6 @@ run-time feature detection support than the one offered by Rust's standard
library. We intend to make `std_detect` more flexible and configurable in this
regard to better serve the needs of `#[no_std]` targets.

# Features

* `std_detect_dlsym_getauxval` (enabled by default, requires `libc`): Enable to
use `libc::dlsym` to query whether [`getauxval`] is linked into the binary. When
this is not the case, this feature allows other fallback methods to perform
run-time feature detection. When this feature is disabled, `std_detect` assumes
that [`getauxval`] is linked to the binary. If that is not the case the behavior
is undefined.

Note: This feature is ignored on `*-linux-{gnu,musl,ohos}*` and `*-android*` targets
because we can safely assume `getauxval` is linked to the binary.
* `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html))
have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html).
* `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15))
use musl newer than [musl 1.1.0 that added `getauxval`](https://git.musl-libc.org/cgit/musl/tree/WHATSNEW?h=v1.1.0#n1197)
* `*-linux-ohos*` targets use a [fork of musl 1.2](https://gitee.com/openharmony/docs/blob/master/en/application-dev/reference/native-lib/musl.md)
* `*-android*` targets ([since Rust 1.68](https://blog.rust-lang.org/2023/01/09/android-ndk-update-r25.html))
have the minimum supported API level higher than [Android 4.3 (API level 18) that added `getauxval`](https://github.com/aosp-mirror/platform_bionic/blob/d3ebc2f7c49a9893b114124d4a6b315f3a328764/libc/include/sys/auxv.h#L49).

* `std_detect_file_io` (enabled by default, requires `std`): Enable to perform run-time feature
detection using file APIs (e.g. `/proc/self/auxv`, etc.) if other more performant
methods fail. This feature requires `libstd` as a dependency, preventing the
crate from working on applications in which `std` is not available.

[`getauxval`]: https://man7.org/linux/man-pages/man3/getauxval.3.html

# Platform support

* All `x86`/`x86_64` targets are supported on all platforms by querying the
Expand Down
8 changes: 4 additions & 4 deletions library/std_detect/src/detect/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,21 @@ cfg_select! {
#[path = "os/x86.rs"]
mod os;
}
all(any(target_os = "linux", target_os = "android"), feature = "libc") => {
any(target_os = "linux", target_os = "android") => {
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
#[path = "os/riscv.rs"]
mod riscv;
#[path = "os/linux/mod.rs"]
mod os;
}
all(target_os = "freebsd", feature = "libc") => {
target_os = "freebsd" => {
#[cfg(target_arch = "aarch64")]
#[path = "os/aarch64.rs"]
mod aarch64;
#[path = "os/freebsd/mod.rs"]
mod os;
}
all(target_os = "openbsd", feature = "libc") => {
target_os = "openbsd" => {
#[allow(dead_code)] // we don't use code that calls the mrs instruction.
#[cfg(target_arch = "aarch64")]
#[path = "os/aarch64.rs"]
Expand All @@ -73,7 +73,7 @@ cfg_select! {
#[path = "os/windows/aarch64.rs"]
mod os;
}
all(target_vendor = "apple", target_arch = "aarch64", feature = "libc") => {
all(target_vendor = "apple", target_arch = "aarch64") => {
#[path = "os/darwin/aarch64.rs"]
mod os;
}
Expand Down
137 changes: 65 additions & 72 deletions library/std_detect/src/detect/os/linux/aarch64/tests.rs
Original file line number Diff line number Diff line change
@@ -1,77 +1,70 @@
use super::auxvec::auxv_from_file;
use super::*;
// The baseline hwcaps used in the (artificial) auxv test files.
fn baseline_hwcaps() -> AtHwcap {
AtHwcap {
fp: true,
asimd: true,
aes: true,
pmull: true,
sha1: true,
sha2: true,
crc32: true,
atomics: true,
fphp: true,
asimdhp: true,
asimdrdm: true,
lrcpc: true,
dcpop: true,
asimddp: true,
ssbs: true,
..AtHwcap::default()
}
}

#[cfg(feature = "std_detect_file_io")]
mod auxv_from_file {
use super::auxvec::auxv_from_file;
use super::*;
// The baseline hwcaps used in the (artificial) auxv test files.
fn baseline_hwcaps() -> AtHwcap {
#[test]
fn linux_empty_hwcap2_aarch64() {
let file = concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv"
);
println!("file: {file}");
let v = auxv_from_file(file).unwrap();
println!("HWCAP : 0x{:0x}", v.hwcap);
println!("HWCAP2: 0x{:0x}", v.hwcap2);
assert_eq!(AtHwcap::from(v), baseline_hwcaps());
}
#[test]
fn linux_no_hwcap2_aarch64() {
let file =
concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-no-hwcap2-aarch64.auxv");
println!("file: {file}");
let v = auxv_from_file(file).unwrap();
println!("HWCAP : 0x{:0x}", v.hwcap);
println!("HWCAP2: 0x{:0x}", v.hwcap2);
assert_eq!(AtHwcap::from(v), baseline_hwcaps());
}
#[test]
fn linux_hwcap2_aarch64() {
let file =
concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-hwcap2-aarch64.auxv");
println!("file: {file}");
let v = auxv_from_file(file).unwrap();
println!("HWCAP : 0x{:0x}", v.hwcap);
println!("HWCAP2: 0x{:0x}", v.hwcap2);
assert_eq!(
AtHwcap::from(v),
AtHwcap {
fp: true,
asimd: true,
aes: true,
pmull: true,
sha1: true,
sha2: true,
crc32: true,
atomics: true,
fphp: true,
asimdhp: true,
asimdrdm: true,
lrcpc: true,
dcpop: true,
asimddp: true,
ssbs: true,
..AtHwcap::default()
// Some other HWCAP bits.
paca: true,
pacg: true,
// HWCAP2-only bits.
dcpodp: true,
frint: true,
rng: true,
bti: true,
mte: true,
..baseline_hwcaps()
}
}

#[test]
fn linux_empty_hwcap2_aarch64() {
let file = concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/detect/test_data/linux-empty-hwcap2-aarch64.auxv"
);
println!("file: {file}");
let v = auxv_from_file(file).unwrap();
println!("HWCAP : 0x{:0x}", v.hwcap);
println!("HWCAP2: 0x{:0x}", v.hwcap2);
assert_eq!(AtHwcap::from(v), baseline_hwcaps());
}
#[test]
fn linux_no_hwcap2_aarch64() {
let file = concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/detect/test_data/linux-no-hwcap2-aarch64.auxv"
);
println!("file: {file}");
let v = auxv_from_file(file).unwrap();
println!("HWCAP : 0x{:0x}", v.hwcap);
println!("HWCAP2: 0x{:0x}", v.hwcap2);
assert_eq!(AtHwcap::from(v), baseline_hwcaps());
}
#[test]
fn linux_hwcap2_aarch64() {
let file =
concat!(env!("CARGO_MANIFEST_DIR"), "/src/detect/test_data/linux-hwcap2-aarch64.auxv");
println!("file: {file}");
let v = auxv_from_file(file).unwrap();
println!("HWCAP : 0x{:0x}", v.hwcap);
println!("HWCAP2: 0x{:0x}", v.hwcap2);
assert_eq!(
AtHwcap::from(v),
AtHwcap {
// Some other HWCAP bits.
paca: true,
pacg: true,
// HWCAP2-only bits.
dcpodp: true,
frint: true,
rng: true,
bti: true,
mte: true,
..baseline_hwcaps()
}
);
}
);
}
44 changes: 15 additions & 29 deletions library/std_detect/src/detect/os/linux/auxvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,16 @@ pub(crate) struct AuxVec {
///
/// There is no perfect way of reading the auxiliary vector.
///
/// - If the `std_detect_dlsym_getauxval` cargo feature is enabled, this will use
/// `getauxval` if its linked to the binary, and otherwise proceed to a fallback implementation.
/// When `std_detect_dlsym_getauxval` is disabled, this will assume that `getauxval` is
/// linked to the binary - if that is not the case the behavior is undefined.
/// - Otherwise, if the `std_detect_file_io` cargo feature is enabled, it will
/// - If [`getauxval`] is linked to the binary we use it, and otherwise it will
/// try to read `/proc/self/auxv`.
/// - If that fails, this function returns an error.
///
/// Note that run-time feature detection is not invoked for features that can
/// be detected at compile-time.
///
/// Note: The `std_detect_dlsym_getauxval` cargo feature is ignored on
/// `*-linux-{gnu,musl,ohos}*` and `*-android*` targets because we can safely assume `getauxval`
/// is linked to the binary.
/// Note: We always directly use `getauxval` on `*-linux-{gnu,musl,ohos}*` and
/// `*-android*` targets rather than `dlsym` it because we can safely assume
/// `getauxval` is linked to the binary.
/// - `*-linux-gnu*` targets ([since Rust 1.64](https://blog.rust-lang.org/2022/08/01/Increasing-glibc-kernel-requirements.html))
/// have glibc requirements higher than [glibc 2.16 that added `getauxval`](https://sourceware.org/legacy-ml/libc-announce/2012/msg00000.html).
/// - `*-linux-musl*` targets ([at least since Rust 1.15](https://github.com/rust-lang/rust/blob/1.15.0/src/ci/docker/x86_64-musl/build-musl.sh#L15))
Expand All @@ -71,6 +67,7 @@ pub(crate) struct AuxVec {
///
/// [auxvec_h]: https://github.com/torvalds/linux/blob/master/include/uapi/linux/auxvec.h
/// [auxv_docs]: https://docs.rs/auxv/0.3.3/auxv/
/// [`getauxval`]: https://man7.org/linux/man-pages/man3/getauxval.3.html
pub(crate) fn auxv() -> Result<AuxVec, ()> {
// Try to call a getauxval function.
if let Ok(hwcap) = getauxval(AT_HWCAP) {
Expand Down Expand Up @@ -115,31 +112,26 @@ pub(crate) fn auxv() -> Result<AuxVec, ()> {
let _ = hwcap;
}

#[cfg(feature = "std_detect_file_io")]
{
// If calling getauxval fails, try to read the auxiliary vector from
// its file:
auxv_from_file("/proc/self/auxv").map_err(|_| ())
}
#[cfg(not(feature = "std_detect_file_io"))]
{
Err(())
}
// If calling getauxval fails, try to read the auxiliary vector from
// its file:
auxv_from_file("/proc/self/auxv").map_err(|_| ())
}

/// Tries to read the `key` from the auxiliary vector by calling the
/// `getauxval` function. If the function is not linked, this function return `Err`.
fn getauxval(key: usize) -> Result<usize, ()> {
type F = unsafe extern "C" fn(libc::c_ulong) -> libc::c_ulong;
cfg_select! {
all(
feature = "std_detect_dlsym_getauxval",
not(all(
any(
all(
target_os = "linux",
any(target_env = "gnu", target_env = "musl", target_env = "ohos"),
)),
not(target_os = "android"),
),
target_os = "android",
) => {
let ffi_getauxval: F = libc::getauxval;
}
_ => {
let ffi_getauxval: F = unsafe {
let ptr = libc::dlsym(libc::RTLD_DEFAULT, c"getauxval".as_ptr());
if ptr.is_null() {
Expand All @@ -148,23 +140,18 @@ fn getauxval(key: usize) -> Result<usize, ()> {
core::mem::transmute(ptr)
};
}
_ => {
let ffi_getauxval: F = libc::getauxval;
}
}
Ok(unsafe { ffi_getauxval(key as libc::c_ulong) as usize })
}

/// Tries to read the auxiliary vector from the `file`. If this fails, this
/// function returns `Err`.
#[cfg(feature = "std_detect_file_io")]
pub(super) fn auxv_from_file(file: &str) -> Result<AuxVec, alloc::string::String> {
let file = super::read_file(file)?;
auxv_from_file_bytes(&file)
}

/// Read auxiliary vector from a slice of bytes.
#[cfg(feature = "std_detect_file_io")]
pub(super) fn auxv_from_file_bytes(bytes: &[u8]) -> Result<AuxVec, alloc::string::String> {
// See <https://github.com/torvalds/linux/blob/v5.15/include/uapi/linux/auxvec.h>.
//
Expand All @@ -181,7 +168,6 @@ pub(super) fn auxv_from_file_bytes(bytes: &[u8]) -> Result<AuxVec, alloc::string

/// Tries to interpret the `buffer` as an auxiliary vector. If that fails, this
/// function returns `Err`.
#[cfg(feature = "std_detect_file_io")]
fn auxv_from_buf(buf: &[usize]) -> Result<AuxVec, alloc::string::String> {
// Targets with only AT_HWCAP:
#[cfg(any(
Expand Down
3 changes: 0 additions & 3 deletions library/std_detect/src/detect/os/linux/auxvec/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ fn auxv_dump() {
}
}

#[cfg(feature = "std_detect_file_io")]
cfg_select! {
target_arch = "arm" => {
// The tests below can be executed under qemu, where we do not have access to the test
Expand Down Expand Up @@ -86,7 +85,6 @@ cfg_select! {
}

#[test]
#[cfg(feature = "std_detect_file_io")]
fn auxv_dump_procfs() {
if let Ok(auxvec) = auxv_from_file("/proc/self/auxv") {
println!("{:?}", auxvec);
Expand All @@ -103,7 +101,6 @@ fn auxv_dump_procfs() {
target_arch = "s390x",
))]
#[test]
#[cfg(feature = "std_detect_file_io")]
fn auxv_crate_procfs() {
if let Ok(procfs_auxv) = auxv_from_file("/proc/self/auxv") {
assert_eq!(auxv().unwrap(), procfs_auxv);
Expand Down
4 changes: 1 addition & 3 deletions library/std_detect/src/detect/os/linux/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
//! Run-time feature detection on Linux
//!
#[cfg(feature = "std_detect_file_io")]

use alloc::vec::Vec;

mod auxvec;

#[cfg(feature = "std_detect_file_io")]
fn read_file(orig_path: &str) -> Result<Vec<u8>, alloc::string::String> {
use alloc::format;

Expand Down
3 changes: 1 addition & 2 deletions library/std_detect/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@
extern crate std;

// rust-lang/rust#83888: removing `extern crate` gives an error that `vec_spare>
#[cfg_attr(feature = "std_detect_file_io", allow(unused_extern_crates))]
#[cfg(feature = "std_detect_file_io")]
#[allow(unused_extern_crates)]
extern crate alloc;

#[doc(hidden)]
Expand Down
Loading
Loading