summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKostya Kortchinsky <kostyak@google.com>2017-11-22 18:30:44 +0000
committerKostya Kortchinsky <kostyak@google.com>2017-11-22 18:30:44 +0000
commitbe283f57de0037c7e19f0b1b75471f137efdfa1e (patch)
tree9141b89ff4cb19b288cc96a051b7efbe89daf0f0 /lib
parent8d1ef4a759edc138efdfab9c86047739fab8a536 (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.h36
-rw-r--r--lib/scudo/scudo_allocator.cpp2
-rw-r--r--lib/scudo/scudo_utils.cpp140
-rw-r--r--lib/scudo/scudo_utils.h8
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));