diff options
author | Kostya Kortchinsky <kostyak@google.com> | 2017-11-22 18:30:44 +0000 |
---|---|---|
committer | Kostya Kortchinsky <kostyak@google.com> | 2017-11-22 18:30:44 +0000 |
commit | be283f57de0037c7e19f0b1b75471f137efdfa1e (patch) | |
tree | 9141b89ff4cb19b288cc96a051b7efbe89daf0f0 /lib | |
parent | 8d1ef4a759edc138efdfab9c86047739fab8a536 (diff) |
[scudo] Overhaul hardware CRC32 feature detection
Summary:
This patch aims at condensing the hardware CRC32 feature detection and making
it slightly more effective on Android.
The following changes are included:
- remove the `CPUFeature` enum, and get rid of one level of nesting of
functions: we only used CRC32, so we just implement and use
`hasHardwareCRC32`;
- allow for a weak `getauxval`: the Android toolchain is compiled at API level
14 for Android ARM, meaning no `getauxval` at compile time, yet we will run
on API level 27+ devices. The `/proc/self/auxv` fallback can work but is
worthless for a process like `init` where the proc filesystem doesn't exist
yet. If a weak `getauxval` doesn't exist, then fallback.
- couple of extra corrections.
Reviewers: alekseyshl
Reviewed By: alekseyshl
Subscribers: kubamracek, aemerson, srhines, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D40322
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@318859 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/sanitizer_common/sanitizer_getauxval.h | 36 | ||||
-rw-r--r-- | lib/scudo/scudo_allocator.cpp | 2 | ||||
-rw-r--r-- | lib/scudo/scudo_utils.cpp | 140 | ||||
-rw-r--r-- | lib/scudo/scudo_utils.h | 8 |
4 files changed, 70 insertions, 116 deletions
diff --git a/lib/sanitizer_common/sanitizer_getauxval.h b/lib/sanitizer_common/sanitizer_getauxval.h index 7b255c60b..934e311a7 100644 --- a/lib/sanitizer_common/sanitizer_getauxval.h +++ b/lib/sanitizer_common/sanitizer_getauxval.h @@ -20,21 +20,27 @@ #if SANITIZER_LINUX -#include <features.h> - -#ifndef __GLIBC_PREREQ -#define __GLIBC_PREREQ(x, y) 0 -#endif - -#if __GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) -# define SANITIZER_USE_GETAUXVAL 1 -#else -# define SANITIZER_USE_GETAUXVAL 0 -#endif - -#if SANITIZER_USE_GETAUXVAL -#include <sys/auxv.h> -#endif +# include <features.h> + +# ifndef __GLIBC_PREREQ +# define __GLIBC_PREREQ(x, y) 0 +# endif + +# if __GLIBC_PREREQ(2, 16) || (SANITIZER_ANDROID && __ANDROID_API__ >= 21) +# define SANITIZER_USE_GETAUXVAL 1 +# else +# define SANITIZER_USE_GETAUXVAL 0 +# endif + +# if SANITIZER_USE_GETAUXVAL +# include <sys/auxv.h> +# else +// The weak getauxval definition allows to check for the function at runtime. +// This is useful for Android, when compiled at a lower API level yet running +// on a more recent platform that offers the function. +extern "C" SANITIZER_WEAK_ATTRIBUTE +unsigned long getauxval(unsigned long type); // NOLINT +# endif #endif // SANITIZER_LINUX diff --git a/lib/scudo/scudo_allocator.cpp b/lib/scudo/scudo_allocator.cpp index 66870d581..27de04030 100644 --- a/lib/scudo/scudo_allocator.cpp +++ b/lib/scudo/scudo_allocator.cpp @@ -271,7 +271,7 @@ struct ScudoAllocator { // Check if hardware CRC32 is supported in the binary and by the platform, // if so, opt for the CRC32 hardware version of the checksum. - if (computeHardwareCRC32 && testCPUFeature(CRC32CPUFeature)) + if (&computeHardwareCRC32 && hasHardwareCRC32()) atomic_store_relaxed(&HashAlgorithm, CRC32Hardware); SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); diff --git a/lib/scudo/scudo_utils.cpp b/lib/scudo/scudo_utils.cpp index fb082a475..75be2fc73 100644 --- a/lib/scudo/scudo_utils.cpp +++ b/lib/scudo/scudo_utils.cpp @@ -13,49 +13,18 @@ #include "scudo_utils.h" -#include <stdarg.h> #if defined(__x86_64__) || defined(__i386__) # include <cpuid.h> -#endif -#if defined(__arm__) || defined(__aarch64__) -# if SANITIZER_ANDROID && __ANDROID_API__ < 21 -// getauxval() was introduced with API level 18 for ARM and 21 for AArch64. -// Emulate it using /proc/self/auxv for lower API levels. +#elif defined(__arm__) || defined(__aarch64__) +# include "sanitizer_common/sanitizer_getauxval.h" +# if SANITIZER_POSIX # include "sanitizer_common/sanitizer_posix.h" - # include <fcntl.h> - -# define AT_HWCAP 16 - -namespace __sanitizer { - -uptr getauxval(uptr Type) { - uptr F = internal_open("/proc/self/auxv", O_RDONLY); - if (internal_iserror(F)) - return 0; - struct { uptr Tag; uptr Value; } Entry; - uptr Result = 0; - for (;;) { - uptr N = internal_read(F, &Entry, sizeof(Entry)); - if (internal_iserror(N)) - break; - if (N == 0 || N != sizeof(Entry) || (Entry.Tag == 0 && Entry.Value == 0)) - break; - if (Entry.Tag == Type) { - Result = Entry.Value; - break; - } - } - internal_close(F); - return Result; -} - -} // namespace __sanitizer -# else -# include <sys/auxv.h> # endif #endif +#include <stdarg.h> + // TODO(kostyak): remove __sanitizer *Printf uses in favor for our own less // complicated string formatting code. The following is a // temporary workaround to be able to use __sanitizer::VSNPrintf. @@ -68,13 +37,12 @@ extern int VSNPrintf(char *buff, int buff_length, const char *format, namespace __scudo { -FORMAT(1, 2) -void NORETURN dieWithMessage(const char *Format, ...) { +FORMAT(1, 2) void NORETURN dieWithMessage(const char *Format, ...) { // Our messages are tiny, 256 characters is more than enough. char Message[256]; va_list Args; va_start(Args, Format); - __sanitizer::VSNPrintf(Message, sizeof(Message), Format, Args); + VSNPrintf(Message, sizeof(Message), Format, Args); va_end(Args); RawWrite(Message); Die(); @@ -83,74 +51,58 @@ void NORETURN dieWithMessage(const char *Format, ...) { #if defined(__x86_64__) || defined(__i386__) // i386 and x86_64 specific code to detect CRC32 hardware support via CPUID. // CRC32 requires the SSE 4.2 instruction set. -typedef struct { - u32 Eax; - u32 Ebx; - u32 Ecx; - u32 Edx; -} CPUIDRegs; - -static void getCPUID(CPUIDRegs *Regs, u32 Level) { - __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx); -} - -CPUIDRegs getCPUFeatures() { - CPUIDRegs VendorRegs = {}; - getCPUID(&VendorRegs, 0); - bool IsIntel = - (VendorRegs.Ebx == signature_INTEL_ebx) && - (VendorRegs.Edx == signature_INTEL_edx) && - (VendorRegs.Ecx == signature_INTEL_ecx); - bool IsAMD = - (VendorRegs.Ebx == signature_AMD_ebx) && - (VendorRegs.Edx == signature_AMD_edx) && - (VendorRegs.Ecx == signature_AMD_ecx); - // Default to an empty feature set if not on a supported CPU. - CPUIDRegs FeaturesRegs = {}; - if (IsIntel || IsAMD) { - getCPUID(&FeaturesRegs, 1); - } - return FeaturesRegs; -} - # ifndef bit_SSE4_2 # define bit_SSE4_2 bit_SSE42 // clang and gcc have different defines. # endif - -bool testCPUFeature(CPUFeature Feature) { - CPUIDRegs FeaturesRegs = getCPUFeatures(); - - switch (Feature) { - case CRC32CPUFeature: // CRC32 is provided by SSE 4.2. - return !!(FeaturesRegs.Ecx & bit_SSE4_2); - default: - break; - } - return false; +bool hasHardwareCRC32() { + u32 Eax, Ebx, Ecx, Edx; + __get_cpuid(0, &Eax, &Ebx, &Ecx, &Edx); + const bool IsIntel = (Ebx == signature_INTEL_ebx) && + (Edx == signature_INTEL_edx) && + (Ecx == signature_INTEL_ecx); + const bool IsAMD = (Ebx == signature_AMD_ebx) && + (Edx == signature_AMD_edx) && + (Ecx == signature_AMD_ecx); + if (!IsIntel && !IsAMD) + return false; + __get_cpuid(1, &Eax, &Ebx, &Ecx, &Edx); + return !!(Ecx & bit_SSE4_2); } #elif defined(__arm__) || defined(__aarch64__) -// For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWVAL +// For ARM and AArch64, hardware CRC32 support is indicated in the AT_HWCAP // auxiliary vector. - +# ifndef AT_HWCAP +# define AT_HWCAP 16 +# endif # ifndef HWCAP_CRC32 # define HWCAP_CRC32 (1 << 7) // HWCAP_CRC32 is missing on older platforms. # endif - -bool testCPUFeature(CPUFeature Feature) { - uptr HWCap = getauxval(AT_HWCAP); - - switch (Feature) { - case CRC32CPUFeature: - return !!(HWCap & HWCAP_CRC32); - default: +# if SANITIZER_POSIX +bool hasHardwareCRC32ARMPosix() { + uptr F = internal_open("/proc/self/auxv", O_RDONLY); + if (internal_iserror(F)) + return false; + struct { uptr Tag; uptr Value; } Entry = { 0, 0 }; + for (;;) { + uptr N = internal_read(F, &Entry, sizeof(Entry)); + if (internal_iserror(N) || N != sizeof(Entry) || + (Entry.Tag == 0 && Entry.Value == 0) || Entry.Tag == AT_HWCAP) break; } - return false; + internal_close(F); + return (Entry.Tag == AT_HWCAP && (Entry.Value & HWCAP_CRC32) != 0); } -#else -bool testCPUFeature(CPUFeature Feature) { - return false; +# else +bool hasHardwareCRC32ARMPosix() { return false; } +# endif // SANITIZER_POSIX + +bool hasHardwareCRC32() { + if (&getauxval) + return !!(getauxval(AT_HWCAP) & HWCAP_CRC32); + return hasHardwareCRC32ARMPosix(); } +#else +bool hasHardwareCRC32() { return false; } #endif // defined(__x86_64__) || defined(__i386__) } // namespace __scudo diff --git a/lib/scudo/scudo_utils.h b/lib/scudo/scudo_utils.h index cb7300db9..33798194d 100644 --- a/lib/scudo/scudo_utils.h +++ b/lib/scudo/scudo_utils.h @@ -21,7 +21,7 @@ namespace __scudo { template <class Dest, class Source> -inline Dest bit_cast(const Source& source) { +INLINE Dest bit_cast(const Source& source) { static_assert(sizeof(Dest) == sizeof(Source), "Sizes are not equal!"); Dest dest; memcpy(&dest, &source, sizeof(dest)); @@ -30,11 +30,7 @@ inline Dest bit_cast(const Source& source) { void NORETURN dieWithMessage(const char *Format, ...); -enum CPUFeature { - CRC32CPUFeature = 0, - MaxCPUFeature, -}; -bool testCPUFeature(CPUFeature Feature); +bool hasHardwareCRC32(); INLINE u64 rotl(const u64 X, int K) { return (X << K) | (X >> (64 - K)); |