[compiler-rt] r318859 - [scudo] Overhaul hardware CRC32 feature detection

Kostya Kortchinsky via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 22 10:30:44 PST 2017


Author: cryptoad
Date: Wed Nov 22 10:30:44 2017
New Revision: 318859

URL: http://llvm.org/viewvc/llvm-project?rev=318859&view=rev
Log:
[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

Modified:
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_getauxval.h
    compiler-rt/trunk/lib/scudo/scudo_allocator.cpp
    compiler-rt/trunk/lib/scudo/scudo_utils.cpp
    compiler-rt/trunk/lib/scudo/scudo_utils.h

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_getauxval.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_getauxval.h?rev=318859&r1=318858&r2=318859&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_getauxval.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_getauxval.h Wed Nov 22 10:30:44 2017
@@ -20,21 +20,27 @@
 
 #if SANITIZER_LINUX
 
-#include <features.h>
+# 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
+# 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
 

Modified: compiler-rt/trunk/lib/scudo/scudo_allocator.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_allocator.cpp?rev=318859&r1=318858&r2=318859&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_allocator.cpp (original)
+++ compiler-rt/trunk/lib/scudo/scudo_allocator.cpp Wed Nov 22 10:30:44 2017
@@ -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);

Modified: compiler-rt/trunk/lib/scudo/scudo_utils.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_utils.cpp?rev=318859&r1=318858&r2=318859&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_utils.cpp (original)
+++ compiler-rt/trunk/lib/scudo/scudo_utils.cpp Wed Nov 22 10:30:44 2017
@@ -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 buf
 
 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
 #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

Modified: compiler-rt/trunk/lib/scudo/scudo_utils.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_utils.h?rev=318859&r1=318858&r2=318859&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_utils.h (original)
+++ compiler-rt/trunk/lib/scudo/scudo_utils.h Wed Nov 22 10:30:44 2017
@@ -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& sourc
 
 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));




More information about the llvm-commits mailing list