diff --git a/cpu.cpp b/cpu.cpp
index 8ce4cb13..fba59220 100644
--- a/cpu.cpp
+++ b/cpu.cpp
@@ -319,8 +319,8 @@ void DetectX86Features()
// http://community.arm.com/groups/android-community/blog/2014/10/10/runtime-detection-of-cpu-features-on-an-armv8-a-cpu
//
bool CRYPTOPP_SECTION_INIT g_ArmDetectionDone = false;
-bool CRYPTOPP_SECTION_INIT g_hasNEON = false, CRYPTOPP_SECTION_INIT g_hasCRC32 = false, CRYPTOPP_SECTION_INIT g_hasAES = false, CRYPTOPP_SECTION_INIT g_hasSHA1 = false;
-bool CRYPTOPP_SECTION_INIT g_hasSHA2 = false;
+bool CRYPTOPP_SECTION_INIT g_hasNEON = false, CRYPTOPP_SECTION_INIT g_hasPMULL = false, CRYPTOPP_SECTION_INIT g_hasCRC32 = false;
+bool CRYPTOPP_SECTION_INIT g_hasAES = false, CRYPTOPP_SECTION_INIT g_hasSHA1 = false, CRYPTOPP_SECTION_INIT g_hasSHA2 = false;
word32 CRYPTOPP_SECTION_INIT g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
#ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
@@ -332,6 +332,12 @@ extern "C"
longjmp(s_jmpNoNEON, 1);
}
+ static jmp_buf s_jmpNoPMULL;
+ static void SigIllHandlerPMULL(int)
+ {
+ longjmp(s_jmpNoPMULL, 1);
+ }
+
static jmp_buf s_jmpNoCRC32;
static void SigIllHandlerCRC32(int)
{
@@ -426,6 +432,59 @@ static bool TryNEON()
#endif // CRYPTOPP_BOOL_NEON_INTRINSICS_AVAILABLE
}
+static bool TryPMULL()
+{
+#if (CRYPTOPP_BOOL_ARM_CRYPTO_INTRINSICS_AVAILABLE)
+# if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
+ volatile bool result = true;
+ __try
+ {
+ const poly64_t a1={1}, b1={2};
+ const poly64x2_t a2={1}, b2={2};
+ const poly128_t r1 = vmull_p64(a1, b1);
+ const poly128_t r2 = vmull_high_p64(a2, b2);
+
+ result = (r1 != r2);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return false;
+ }
+ return result;
+# else
+ // longjmp and clobber warnings. Volatile is required.
+ // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
+ volatile bool result = true;
+
+ volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerPMULL);
+ if (oldHandler == SIG_ERR)
+ return false;
+
+ volatile sigset_t oldMask;
+ if (sigprocmask(0, NULL, (sigset_t*)&oldMask))
+ return false;
+
+ if (setjmp(s_jmpNoPMULL))
+ result = false;
+ else
+ {
+ const poly64_t a1={1}, b1={2};
+ const poly64x2_t a2={1}, b2={2};
+ const poly128_t r1 = vmull_p64(a1, b1);
+ const poly128_t r2 = vmull_high_p64(a2, b2);
+
+ result = (r1 != r2);
+ }
+
+ sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULL);
+ signal(SIGILL, oldHandler);
+ return result;
+# endif
+#else
+ return false;
+#endif // CRYPTOPP_BOOL_CRYPTO_INTRINSICS_AVAILABLE
+}
+
static bool TryCRC32()
{
#if (CRYPTOPP_BOOL_ARM_CRC32_INTRINSICS_AVAILABLE)
@@ -660,6 +719,7 @@ void DetectArmFeatures()
#endif
{
g_hasNEON = TryNEON();
+ g_hasPMULL = TryPMULL();
g_hasCRC32 = TryCRC32();
g_hasAES = TryAES();
g_hasSHA1 = TrySHA1();
diff --git a/cpu.h b/cpu.h
index 3fe5d4f2..55f1a12b 100644
--- a/cpu.h
+++ b/cpu.h
@@ -364,7 +364,7 @@ inline int GetCacheLineSize()
#elif (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64)
extern bool g_ArmDetectionDone;
-extern bool g_hasNEON, g_hasCRC32, g_hasAES, g_hasSHA1, g_hasSHA2;
+extern bool g_hasNEON, g_hasPMULL, g_hasCRC32, g_hasAES, g_hasSHA1, g_hasSHA2;
void CRYPTOPP_API DetectArmFeatures();
//! \brief Determine if an ARM processor has Advanced SIMD available
@@ -380,6 +380,19 @@ inline bool HasNEON()
return g_hasNEON;
}
+//! \brief Determine if an ARM processor provides Polynomial Multiplication (long)
+//! \returns true if the hardware is capable of polynomial multiplications at runtime, false otherwise.
+//! \details The multiplication instructions are available under Aarch64 (ARM-64) and Aarch32 (ARM-32).
+//! \details Runtime support requires compile time support. When compiling with GCC, you may
+//! need to compile with -march=armv8-a+crypto; while Apple requires
+//! -arch arm64. Also see ARM's __ARM_FEATURE_CRYPTO preprocessor macro.
+inline bool HasPMULL()
+{
+ if (!g_ArmDetectionDone)
+ DetectArmFeatures();
+ return g_hasPMULL;
+}
+
//! \brief Determine if an ARM processor has CRC32 available
//! \returns true if the hardware is capable of CRC32 at runtime, false otherwise.
//! \details CRC32 instructions provide access to the processor's CRC32 and CRC32-C intructions.
@@ -485,20 +498,6 @@ inline int GetCacheLineSize()
#else
#define CRYPTOPP_GNU_STYLE_INLINE_ASSEMBLY
-#if defined(CRYPTOPP_LLVM_CLANG_VERSION) || defined(CRYPTOPP_APPLE_CLANG_VERSION) || defined(CRYPTOPP_CLANG_INTEGRATED_ASSEMBLER)
- #define NEW_LINE "\n"
- #define INTEL_PREFIX ".intel_syntax;"
- #define INTEL_NOPREFIX ".intel_syntax;"
- #define ATT_PREFIX ".att_syntax;"
- #define ATT_NOPREFIX ".att_syntax;"
-#else
- #define NEW_LINE
- #define INTEL_PREFIX ".intel_syntax prefix;"
- #define INTEL_NOPREFIX ".intel_syntax noprefix;"
- #define ATT_PREFIX ".att_syntax prefix;"
- #define ATT_NOPREFIX ".att_syntax noprefix;"
-#endif
-
// define these in two steps to allow arguments to be expanded
#define GNU_AS1(x) #x ";" NEW_LINE
#define GNU_AS2(x, y) #x ", " #y ";" NEW_LINE
@@ -519,21 +518,6 @@ inline int GetCacheLineSize()
#define IF0(y)
#define IF1(y) y
-// Should be confined to GCC, but its used to help manage Clang 3.4 compiler error.
-// Also see LLVM Bug 24232, http://llvm.org/bugs/show_bug.cgi?id=24232 .
-#ifndef INTEL_PREFIX
- #define INTEL_PREFIX
-#endif
-#ifndef INTEL_NOPREFIX
- #define INTEL_NOPREFIX
-#endif
-#ifndef ATT_PREFIX
- #define ATT_PREFIX
-#endif
-#ifndef ATT_NOPREFIX
- #define ATT_NOPREFIX
-#endif
-
#ifdef CRYPTOPP_GENERATE_X64_MASM
#define ASM_MOD(x, y) ((x) MOD (y))
#define XMMWORD_PTR XMMWORD PTR
@@ -666,6 +650,21 @@ inline int GetCacheLineSize()
#endif // X86/X32/X64
+// Applies to both X86/X32/X64 and ARM32/ARM64
+#if defined(CRYPTOPP_LLVM_CLANG_VERSION) || defined(CRYPTOPP_APPLE_CLANG_VERSION) || defined(CRYPTOPP_CLANG_INTEGRATED_ASSEMBLER)
+ #define NEW_LINE "\n"
+ #define INTEL_PREFIX ".intel_syntax;"
+ #define INTEL_NOPREFIX ".intel_syntax;"
+ #define ATT_PREFIX ".att_syntax;"
+ #define ATT_NOPREFIX ".att_syntax;"
+#else
+ #define NEW_LINE
+ #define INTEL_PREFIX ".intel_syntax prefix;"
+ #define INTEL_NOPREFIX ".intel_syntax noprefix;"
+ #define ATT_PREFIX ".att_syntax prefix;"
+ #define ATT_NOPREFIX ".att_syntax noprefix;"
+#endif
+
NAMESPACE_END
#endif // CRYPTOPP_CPU_H
diff --git a/validat1.cpp b/validat1.cpp
index a6115e5e..44e2779f 100644
--- a/validat1.cpp
+++ b/validat1.cpp
@@ -315,13 +315,14 @@ bool TestSettings()
#elif (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64)
bool hasNEON = HasNEON();
+ bool hasPMULL = HasPMULL();
bool hasCRC32 = HasCRC32();
bool hasAES = HasAES();
bool hasSHA1 = HasSHA1();
bool hasSHA2 = HasSHA2();
cout << "passed: ";
- cout << "hasNEON == " << hasNEON << ", hasCRC32 == " << hasCRC32 << ", hasAES == " << hasAES << ", hasSHA1 == " << hasSHA1 << ", hasSHA2 == " << hasSHA2 << endl;
+ cout << "hasNEON == " << hasNEON << ", hasPMULL == " << hasPMULL << ", hasCRC32 == " << hasCRC32 << ", hasAES == " << hasAES << ", hasSHA1 == " << hasSHA1 << ", hasSHA2 == " << hasSHA2 << endl;
#endif
if (!pass)