Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

detect: Use elf_aux_info instead of mrs on aarch64 FreeBSD #77

Merged
merged 1 commit into from
Feb 23, 2023
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
1 change: 1 addition & 0 deletions .github/.cspell/project-dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ sbcs
seqlock
sete
sifive
SIGILL
SIGINT
simavr
skiboot
Expand Down
16 changes: 10 additions & 6 deletions src/imp/atomic128/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,22 @@ include!("macros.rs");

#[cfg(not(portable_atomic_no_outline_atomics))]
#[cfg_attr(
any(all(target_os = "linux", target_env = "gnu"), target_os = "android"),
any(
all(target_os = "linux", target_env = "gnu"),
target_os = "android",
target_os = "freebsd",
),
path = "detect/aarch64_auxv.rs"
)]
#[cfg_attr(target_os = "openbsd", path = "detect/aarch64_aa64reg.rs")]
#[cfg_attr(target_os = "windows", path = "detect/aarch64_windows.rs")]
#[cfg_attr(any(target_os = "freebsd", target_os = "openbsd"), path = "detect/aarch64_aa64reg.rs")]
#[cfg_attr(
not(any(
all(target_os = "linux", target_env = "gnu"),
target_os = "android",
target_os = "windows",
target_os = "freebsd",
target_os = "openbsd",
target_os = "windows",
)),
path = "detect/aarch64_std.rs"
)]
Expand All @@ -70,7 +74,7 @@ mod detect;
#[cfg(test)]
#[cfg(not(qemu))]
#[cfg(not(valgrind))]
#[cfg(any(target_os = "linux", target_os = "android"))]
#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))]
#[path = "detect/aarch64_aa64reg.rs"]
mod detect_aa64reg;
#[cfg(test)]
Expand Down Expand Up @@ -306,9 +310,9 @@ unsafe fn atomic_compare_exchange(
feature = "std",
target_os = "linux",
target_os = "android",
target_os = "windows",
target_os = "freebsd",
target_os = "openbsd",
target_os = "windows",
),
)))]
#[cfg(not(any(target_feature = "lse", portable_atomic_target_feature = "lse")))]
Expand All @@ -321,9 +325,9 @@ unsafe fn atomic_compare_exchange(
feature = "std",
target_os = "linux",
target_os = "android",
target_os = "windows",
target_os = "freebsd",
target_os = "openbsd",
target_os = "windows",
),
))]
#[cfg(not(any(target_feature = "lse", portable_atomic_target_feature = "lse")))]
Expand Down
10 changes: 7 additions & 3 deletions src/imp/atomic128/detect/aarch64_aa64reg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@
// - OpenBSD 7.1+ (through sysctl)
// https://github.com/openbsd/src/commit/d335af936b9d7dd9cf655cae1ce19560c45de6c8
//
// For now, this module is only used on FreeBSD/OpenBSD.
// For now, this module is only used on OpenBSD.
// - On Linux, this module is test-only because this approach requires a higher
// kernel version than Rust supports, and also does not work with qemu-user
// (as of QEMU 7.2) and Valgrind. (Looking into HWCAP_CPUID in auxvec, it appears
// that Valgrind is setting it to false correctly, but qemu-user is setting it to true.)
// (as of QEMU 7.2) and Valgrind. (Looking into HWCAP_CPUID in auxvec, it
// appears that Valgrind is setting it to false correctly, but qemu-user is
// setting it to true.)
// - On FreeBSD, this module is test-only because this approach does not work on
// FreeBSD 12 on QEMU (confirmed on FreeBSD 12.{2,3,4}), and we got SIGILL
// (worked on FreeBSD 13 and 14).

#![cfg_attr(
any(
Expand Down
110 changes: 109 additions & 1 deletion src/imp/atomic128/detect/aarch64_auxv.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// Run-time feature detection on aarch64 Linux/Android by parsing ELF auxiliary vectors.
// Run-time feature detection on aarch64 Linux/Android/FreeBSD by parsing ELF auxiliary vectors.
//
// # Linux/Android
//
// As of nightly-2023-01-23, is_aarch64_feature_detected always uses dlsym by default
// on aarch64 Linux/Android, but on the following platforms, so we can safely assume
Expand All @@ -24,6 +26,24 @@
// - On Picolibc, [Picolibc 1.4.6 added getauxval stub](https://github.com/picolibc/picolibc#picolibc-version-146).
//
// See also https://github.com/rust-lang/stdarch/pull/1375
//
// # FreeBSD
//
// As of nightly-2023-01-23, is_aarch64_feature_detected always uses mrs on
// aarch64 FreeBSD. However, they do not work on FreeBSD 12 on QEMU (confirmed
// on FreeBSD 12.{2,3,4}), and we got SIGILL (worked on FreeBSD 13 and 14).
//
// So use elf_aux_info instead of mrs like compiler-rt does.
// https://man.freebsd.org/elf_aux_info(3)
// https://reviews.llvm.org/D109330
//
// elf_aux_info is available on FreeBSD 12.0+ and 11.4+:
// https://github.com/freebsd/freebsd-src/commit/0b08ae2120cdd08c20a2b806e2fcef4d0a36c470
// https://github.com/freebsd/freebsd-src/blob/release/11.4.0/sys/sys/auxv.h
// On FreeBSD, [aarch64 support is available on FreeBSD 11.0+](https://www.freebsd.org/releases/11.0R/relnotes/#hardware-arm),
// but FreeBSD 11 (11.4) was EoL on 2021-09-30, and FreeBSD 11.3 was EoL on 2020-09-30:
// https://www.freebsd.org/security/unsupported
// See also https://github.com/rust-lang/stdarch/pull/611#issuecomment-445464613

#![cfg_attr(
any(
Expand Down Expand Up @@ -142,6 +162,67 @@ mod imp {
AuxVec { hwcap }
}
}
#[cfg(target_os = "freebsd")]
mod imp {
use super::AuxVec;

// core::ffi::c_* (except c_void) requires Rust 1.64
#[allow(non_camel_case_types)]
pub(super) mod ffi {
pub(crate) use core::ffi::c_void;
// c_{,u}int is {i,u}32 on non-16-bit architectures
// https://github.com/rust-lang/rust/blob/1.67.0/library/core/src/ffi/mod.rs#L159-L173
pub(crate) type c_int = i32;
// c_{,u}long is {i,u}64 on non-windows 64-bit targets, otherwise is {i,u}32
// https://github.com/rust-lang/rust/blob/1.67.0/library/core/src/ffi/mod.rs#L175-L190
#[cfg(target_pointer_width = "64")]
pub(crate) type c_ulong = u64;
#[cfg(target_pointer_width = "32")]
pub(crate) type c_ulong = u32;

// Defined in sys/elf_common.h.
// https://github.com/freebsd/freebsd-src/blob/deb63adf945d446ed91a9d84124c71f15ae571d1/sys/sys/elf_common.h
pub(crate) const AT_HWCAP: c_int = 25;

// Defined in machine/elf.h.
// https://github.com/freebsd/freebsd-src/blob/deb63adf945d446ed91a9d84124c71f15ae571d1/sys/arm64/include/elf.h
// available on FreeBSD 13.0+ and 12.2+
// https://github.com/freebsd/freebsd-src/blob/release/13.0.0/sys/arm64/include/elf.h
// https://github.com/freebsd/freebsd-src/blob/release/12.2.0/sys/arm64/include/elf.h
pub(crate) const HWCAP_ATOMICS: c_ulong = 0x0000_0100;
#[cfg(test)]
pub(crate) const HWCAP_USCAT: c_ulong = 0x0200_0000;

extern "C" {
// Defined in sys/auxv.h.
// https://man.freebsd.org/elf_aux_info(3)
// https://github.com/freebsd/freebsd-src/blob/deb63adf945d446ed91a9d84124c71f15ae571d1/sys/sys/auxv.h
pub(crate) fn elf_aux_info(aux: c_int, buf: *mut c_void, buf_len: c_int) -> c_int;
}
}

#[inline]
fn getauxval(aux: ffi::c_int) -> ffi::c_ulong {
#[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)]
const OUT_LEN: ffi::c_int = core::mem::size_of::<ffi::c_ulong>() as ffi::c_int;
let mut out: ffi::c_ulong = 0;
// SAFETY:
// - the pointer is valid because we got it from a reference.
// - `OUT_LEN` is the same as the size of `out`.
// - `elf_aux_info` is thread-safe.
// If elf_aux_info fails, `out` will be left at zero (which is the proper default value).
unsafe {
ffi::elf_aux_info(aux, (&mut out as *mut ffi::c_ulong).cast::<ffi::c_void>(), OUT_LEN);
}
out
}

#[inline]
pub(super) fn auxv() -> AuxVec {
let hwcap = getauxval(ffi::AT_HWCAP);
AuxVec { hwcap }
}
}

#[allow(
clippy::alloc_instead_of_core,
Expand Down Expand Up @@ -222,4 +303,31 @@ mod tests {
#[cfg(target_os = "android")]
static_assert!(ffi::PROP_VALUE_MAX == libc::PROP_VALUE_MAX);
};
#[cfg(target_os = "freebsd")]
#[allow(
clippy::cast_possible_wrap,
clippy::cast_sign_loss,
clippy::cast_possible_truncation,
clippy::no_effect_underscore_binding
)]
const _: fn() = || {
use test_helper::{libc, sys};
let _: ffi::c_int = 0 as libc::c_int;
let _: ffi::c_ulong = 0 as std::os::raw::c_ulong;
let _: ffi::c_ulong = 0 as libc::c_ulong;
let mut _elf_aux_info: unsafe extern "C" fn(
ffi::c_int,
*mut ffi::c_void,
ffi::c_int,
) -> ffi::c_int = ffi::elf_aux_info;
// libc has this, but unreleased as of 0.2.139: https://github.com/rust-lang/libc/commit/a4fd9d32c854417afa1acdbc922eeafac5fcbbfd
// _elf_aux_info = libc::elf_aux_info;
_elf_aux_info = sys::elf_aux_info;
// static_assert!(ffi::AT_HWCAP == libc::AT_HWCAP); // libc doesn't have this
static_assert!(ffi::AT_HWCAP == sys::AT_HWCAP as ffi::c_int);
// static_assert!(ffi::HWCAP_ATOMICS == libc::HWCAP_ATOMICS); // libc doesn't have this
static_assert!(ffi::HWCAP_ATOMICS == sys::HWCAP_ATOMICS as ffi::c_ulong);
// static_assert!(ffi::HWCAP_USCAT == libc::HWCAP_USCAT); // libc doesn't have this
static_assert!(ffi::HWCAP_USCAT == sys::HWCAP_USCAT as ffi::c_ulong);
};
}
4 changes: 2 additions & 2 deletions src/imp/atomic128/detect/aarch64_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
feature = "std",
target_os = "linux",
target_os = "android",
target_os = "windows",
// target_os = "freebsd",
// target_os = "openbsd",
target_os = "windows",
)),
any(target_feature = "lse", portable_atomic_target_feature = "lse"),
),
Expand Down Expand Up @@ -36,9 +36,9 @@ pub(crate) fn has_lse() -> bool {
feature = "std",
all(target_os = "linux", any(target_env = "gnu", target_env = "musl")),
target_os = "android",
target_os = "windows",
// target_os = "freebsd",
// target_os = "openbsd",
target_os = "windows",
),
))]
{
Expand Down
10 changes: 10 additions & 0 deletions src/imp/atomic128/detect/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ mod tests_aarch64_common {
}
} else {
assert!(!detect().test(CpuInfo::HAS_LSE));
// is_aarch64_feature_detected uses mrs on FreeBSD
#[cfg(not(target_os = "freebsd"))]
#[cfg(not(any(
portable_atomic_no_aarch64_target_feature,
portable_atomic_unstable_aarch64_target_feature,
Expand All @@ -212,6 +214,8 @@ mod tests_aarch64_common {
}
} else {
assert!(!detect().test(CpuInfo::HAS_LSE2));
// // is_aarch64_feature_detected uses mrs on FreeBSD
// #[cfg(not(target_os = "freebsd"))]
// #[cfg(not(any(
// portable_atomic_no_aarch64_target_feature,
// portable_atomic_unstable_aarch64_target_feature,
Expand All @@ -229,6 +233,9 @@ mod tests_aarch64_common {
assert!(detect().test(CpuInfo::HAS_LSE128));
} else {
assert!(!detect().test(CpuInfo::HAS_LSE128));
// is_aarch64_feature_detected doesn't support lse128
// // is_aarch64_feature_detected uses mrs on FreeBSD
// #[cfg(not(target_os = "freebsd"))]
// #[cfg(not(any(
// portable_atomic_no_aarch64_target_feature,
// portable_atomic_unstable_aarch64_target_feature,
Expand All @@ -241,6 +248,9 @@ mod tests_aarch64_common {
assert!(detect().test(CpuInfo::HAS_RCPC3));
} else {
assert!(!detect().test(CpuInfo::HAS_RCPC3));
// is_aarch64_feature_detected doesn't support rcpc3
// // is_aarch64_feature_detected uses mrs on FreeBSD
// #[cfg(not(target_os = "freebsd"))]
// #[cfg(not(any(
// portable_atomic_no_aarch64_target_feature,
// portable_atomic_unstable_aarch64_target_feature,
Expand Down
54 changes: 54 additions & 0 deletions tests/helper/src/gen/sys/aarch64_freebsd/machine_elf.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions tests/helper/src/gen/sys/aarch64_freebsd/mod.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions tests/helper/src/gen/sys/aarch64_freebsd/sys_auxv.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions tests/helper/src/gen/sys/aarch64_freebsd/sys_elf_common.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions tests/helper/src/gen/sys/mod.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions tools/codegen/patches/freebsd.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h
--- a/sys/sys/elf_common.h
+++ b/sys/sys/elf_common.h
@@ -33,6 +33,8 @@
#ifndef _SYS_ELF_COMMON_H_
#define _SYS_ELF_COMMON_H_ 1

+#include <sys/types.h>
+
/*
* ELF definitions that are independent of architecture or word size.
*/
Loading