From ee5b62196eec271d542776413d388ecea48f1b87 Mon Sep 17 00:00:00 2001 From: Marshall Pierce Date: Fri, 13 Jan 2017 19:12:25 -0800 Subject: [PATCH] Get rid of getauxval error detection and just return 0. Inline top level of feature detection into init. I agree to license my contributions to each file under the terms given at the top of each file I changed. --- crypto/cpu-arm-linux.c | 28 ++++-------- src/cpu_feature/arm_linux/arm_linux.rs | 62 ++++++++------------------ src/cpu_feature/arm_linux/auxv.rs | 46 +++++-------------- src/init.rs | 17 ++++++- 4 files changed, 55 insertions(+), 98 deletions(-) diff --git a/crypto/cpu-arm-linux.c b/crypto/cpu-arm-linux.c index 0c8f473641..c33369ab6e 100644 --- a/crypto/cpu-arm-linux.c +++ b/crypto/cpu-arm-linux.c @@ -9,37 +9,25 @@ unsigned long getauxval(unsigned long type) __attribute__((weak)); /* - * getauxval() may or may not be available. In addition, it may not find - * the type requested. - * - If getauxval() is not available, this returns -1. - * - If getauxval() is available but the requested type is not found or another - * error occurs, this returns 0. - * - If getauxval() is available but a different error occurs, this returns -2. - * - If getauxval() is available and the requested type is found, this returns - * 1 and also writes to the result pointer param. + * If getauxval is not available, or an error occurs, return 0. + * Otherwise, return the value found. */ -int32_t getauxval_wrapper(unsigned long type, unsigned long *result); +unsigned long getauxval_wrapper(unsigned long type); #include -int32_t getauxval_wrapper(unsigned long type, unsigned long *result) { +unsigned long getauxval_wrapper(unsigned long type) { if (getauxval == NULL) { - return -1; + return 0; } unsigned long auxval = getauxval(type); - if (errno == ENOENT) { - // as of glibc 2.19, errno is ENOENT if the type is not found. + // map errors to a zero value + if (errno != 0) { errno = 0; return 0; - } else if (errno != 0) { - // as of glibc 2.23 the only error is enoent, but more errors - // may be added - errno = 0; - return -2; } - *result = auxval; - return 1; + return auxval; } #endif diff --git a/src/cpu_feature/arm_linux/arm_linux.rs b/src/cpu_feature/arm_linux/arm_linux.rs index 3982f52de2..df205ca998 100644 --- a/src/cpu_feature/arm_linux/arm_linux.rs +++ b/src/cpu_feature/arm_linux/arm_linux.rs @@ -1,15 +1,10 @@ -use self::auxv::Type; -#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_os="linux"))] -use self::auxv::NativeProvider; -use self::auxv::{AT_HWCAP, AT_HWCAP2, Provider}; - // See /usr/include/asm/hwcap.h on an ARM installation for the source of these values -const ARM_HWCAP2_AES: Type = 1 << 0; -const ARM_HWCAP2_PMULL: Type = 1 << 1; -const ARM_HWCAP2_SHA1: Type = 1 << 2; -const ARM_HWCAP2_SHA2: Type = 1 << 3; +const ARM_HWCAP2_AES: auxv::Type = 1 << 0; +const ARM_HWCAP2_PMULL: auxv::Type = 1 << 1; +const ARM_HWCAP2_SHA1: auxv::Type = 1 << 2; +const ARM_HWCAP2_SHA2: auxv::Type = 1 << 3; -const ARM_HWCAP_NEON: Type = 1 << 12; +const ARM_HWCAP_NEON: auxv::Type = 1 << 12; // Constants used in GFp_armcap_P // Keep in sync with include/openssl/arm_arch.h @@ -20,33 +15,16 @@ const ARMV8_SHA1: u32 = 1 << 3; const ARMV8_SHA256: u32 = 1 << 4; const ARMV8_PMULL: u32 = 1 << 5; -extern "C" { - #[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), - target_os="linux"))] - #[allow(non_upper_case_globals)] - pub static mut GFp_armcap_P: u32; -} - -#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), - target_os="linux"))] -pub fn arm_linux_set_cpu_features() { - let getauxval = NativeProvider {}; - - unsafe { - GFp_armcap_P |= armcap_from_features(getauxval); - } -} - /// returns a u32 with bits set for use in GFp_armcap_P -fn armcap_from_features (getauxval: G) -> u32 { - let hwcap = getauxval.getauxval(AT_HWCAP).unwrap_or(0); +pub fn armcap_from_features (getauxval: G) -> u32 { + let hwcap = getauxval.getauxval(auxv::AT_HWCAP); // Matching OpenSSL, only report other features if NEON is present. let mut armcap: u32 = 0; if hwcap & ARM_HWCAP_NEON != 0 { armcap |= ARMV7_NEON; - let hwcap2 = getauxval.getauxval(AT_HWCAP2).unwrap_or(0); + let hwcap2 = getauxval.getauxval(auxv::AT_HWCAP2); armcap |= armcap_for_hwcap2(hwcap2); } @@ -54,7 +32,7 @@ fn armcap_from_features (getauxval: G) -> u32 { return armcap; } -fn armcap_for_hwcap2(hwcap2: Type) -> u32 { +fn armcap_for_hwcap2(hwcap2: auxv::Type) -> u32 { let mut ret: u32 = 0; if hwcap2 & ARM_HWCAP2_AES != 0 { ret |= ARMV8_AES; @@ -82,17 +60,15 @@ mod tests { ARMV8_AES, ARMV8_PMULL, ARMV8_SHA1, ARMV8_SHA256, ARM_HWCAP2_AES, ARM_HWCAP2_PMULL, ARM_HWCAP2_SHA1, ARM_HWCAP2_SHA2, ARM_HWCAP_NEON}; - use super::auxv::{Type, GetauxvalError, - Provider, AT_HWCAP, AT_HWCAP2}; + use super::auxv; struct StubGetauxval { - auxv: HashMap + auxv: HashMap } - impl Provider for StubGetauxval { - fn getauxval(&self, auxv_type: Type) - -> Result { - self.auxv.get(&auxv_type).map(|v| *v).ok_or(GetauxvalError::NotFound) + impl auxv::Provider for StubGetauxval { + fn getauxval(&self, auxv_type: auxv::Type) -> auxv::Type { + self.auxv.get(&auxv_type).map(|v| *v).unwrap_or(0) } } @@ -104,8 +80,8 @@ mod tests { #[test] fn armcap_bits_arm_8_with_neon_only_getauxv_hwcap_and_all_getauxv_hwcap2_yields_all_features_armcap() { let mut auxv = HashMap::new(); - let _ = auxv.insert(AT_HWCAP, ARM_HWCAP_NEON); - let _ = auxv.insert(AT_HWCAP2, ARM_HWCAP2_AES | ARM_HWCAP2_PMULL | ARM_HWCAP2_SHA1 | ARM_HWCAP2_SHA2); + let _ = auxv.insert(auxv::AT_HWCAP, ARM_HWCAP_NEON); + let _ = auxv.insert(auxv::AT_HWCAP2, ARM_HWCAP2_AES | ARM_HWCAP2_PMULL | ARM_HWCAP2_SHA1 | ARM_HWCAP2_SHA2); let getauxv = StubGetauxval { auxv: auxv }; @@ -117,8 +93,8 @@ mod tests { #[test] fn armcap_bits_arm_8_with_neon_only_getauxv_hwcap_and_aes_getauxv_hwcap2_yields_only_neon_aes_armcap() { let mut auxv = HashMap::new(); - let _ = auxv.insert(AT_HWCAP, ARM_HWCAP_NEON); - let _ = auxv.insert(AT_HWCAP2, ARM_HWCAP2_AES); + let _ = auxv.insert(auxv::AT_HWCAP, ARM_HWCAP_NEON); + let _ = auxv.insert(auxv::AT_HWCAP2, ARM_HWCAP2_AES); let getauxv = StubGetauxval { auxv: auxv }; @@ -143,7 +119,7 @@ mod tests { fn hwcap_neon_getauxv() -> StubGetauxval { let mut auxv = HashMap::new(); - let _ = auxv.insert(AT_HWCAP, + let _ = auxv.insert(auxv::AT_HWCAP, ARM_HWCAP_NEON); StubGetauxval { diff --git a/src/cpu_feature/arm_linux/auxv.rs b/src/cpu_feature/arm_linux/auxv.rs index ea6abe6c02..ed0169deca 100644 --- a/src/cpu_feature/arm_linux/auxv.rs +++ b/src/cpu_feature/arm_linux/auxv.rs @@ -7,50 +7,28 @@ pub type Type = u64; extern "C" { /// Invoke getauxval(3) if available. If it's not linked, or if invocation - /// fails or the type is not found, sets success to false and returns 0. - #[cfg(target_os="linux")] - pub fn getauxval_wrapper(auxv_type: Type, success: *mut Type) -> i32; -} - -#[derive(Debug, PartialEq)] -pub enum GetauxvalError { - /// getauxval() is not available at runtime - #[cfg(target_os="linux")] - FunctionNotAvailable, - /// getauxval() could not find the requested type - NotFound, - /// getauxval() encountered a different error - #[cfg(target_os="linux")] - UnknownError + /// fails or the type is not found, returns 0. + #[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), + target_os = "linux"))] + pub fn getauxval_wrapper(auxv_type: Type) -> Type; } pub trait Provider { /// Look up an entry in the auxiliary vector. See getauxval(3) in glibc. - /// Unfortunately, prior to glibc 2.19, getauxval() returns 0 without - /// setting `errno` if the type is not found, so on such old systems - /// this will return `Ok(0)` rather than `Err(GetauxvalError::NotFound)`. - fn getauxval(&self, auxv_type: Type) -> Result; + /// If the requested type is not found, 0 will be returned. + fn getauxval(&self, auxv_type: Type) -> Type; } -#[cfg(target_os="linux")] +#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), + target_os = "linux"))] pub struct NativeProvider {} -#[cfg(target_os="linux")] +#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), + target_os = "linux"))] impl Provider for NativeProvider { - /// Returns Some if the native invocation succeeds and the requested type was - /// found, otherwise None. - fn getauxval(&self, auxv_type: Type) - -> Result { - - let mut result = 0; + fn getauxval(&self, auxv_type: Type) -> Type { unsafe { - return match getauxval_wrapper(auxv_type, &mut result) { - 1 => Ok(result), - 0 => Err(GetauxvalError::NotFound), - -1 => Err(GetauxvalError::FunctionNotAvailable), - -2 => Err(GetauxvalError::UnknownError), - x => panic!("getauxval_wrapper returned an unexpected value: {}", x) - } + return getauxval_wrapper(auxv_type); } } } diff --git a/src/init.rs b/src/init.rs index bace06833d..cce3babb9a 100644 --- a/src/init.rs +++ b/src/init.rs @@ -12,6 +12,10 @@ // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +#[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), + target_os = "linux"))] +use cpu_feature::arm_linux::auxv; + #[inline(always)] pub fn init_once() { #[cfg(not(all(target_arch = "aarch64", target_os = "ios")))] @@ -27,7 +31,18 @@ pub fn init_once() { #[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), target_os = "linux"))] fn set_cpu_features() { - cpu_feature::arm_linux::arm_linux_set_cpu_features(); + let getauxval = auxv::NativeProvider {}; + + unsafe { + GFp_armcap_P |= armcap_from_features(getauxval); + } +} + +extern "C" { + #[cfg(all(any(target_arch = "arm", target_arch = "aarch64"), + target_os="linux"))] + #[allow(non_upper_case_globals)] + pub static mut GFp_armcap_P: u32; } // On other platforms (excluding iOS aarch64), use C feature detection