Crypto++  5.6.3
Free C++ class library of cryptographic schemes
cpu.cpp
1 // cpu.cpp - written and placed in the public domain by Wei Dai
2 
3 #include "pch.h"
4 #include "config.h"
5 
6 #ifndef EXCEPTION_EXECUTE_HANDLER
7 # define EXCEPTION_EXECUTE_HANDLER 1
8 #endif
9 
10 #ifndef CRYPTOPP_IMPORTS
11 
12 #include "cpu.h"
13 #include "misc.h"
14 #include <algorithm>
15 
16 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
17 #include <signal.h>
18 #include <setjmp.h>
19 #endif
20 
21 #if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
22 #include <emmintrin.h>
23 #endif
24 
25 NAMESPACE_BEGIN(CryptoPP)
26 
27 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
28 
29 // MacPorts/GCC does not provide constructor(priority). Apple/GCC and Fink/GCC do provide it.
30 #define HAVE_GCC_CONSTRUCTOR1 (__GNUC__ && (CRYPTOPP_INIT_PRIORITY > 0) && ((CRYPTOPP_GCC_VERSION >= 40300) || (CRYPTOPP_LLVM_CLANG_VERSION >= 20900) || (_INTEL_COMPILER >= 300)) && !(MACPORTS_GCC_COMPILER > 0))
31 #define HAVE_GCC_CONSTRUCTOR0 (__GNUC__ && (CRYPTOPP_INIT_PRIORITY > 0) && !(MACPORTS_GCC_COMPILER > 0))
32 
33 extern "C" {
34  typedef void (*SigHandler)(int);
35 };
36 #endif // Not CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
37 
38 #ifdef CRYPTOPP_CPUID_AVAILABLE
39 
40 #if _MSC_VER >= 1400 && CRYPTOPP_BOOL_X64
41 
42 bool CpuId(word32 input, word32 output[4])
43 {
44  __cpuid((int *)output, input);
45  return true;
46 }
47 
48 #else
49 
50 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
51 extern "C"
52 {
53  static jmp_buf s_jmpNoCPUID;
54  static void SigIllHandlerCPUID(int)
55  {
56  longjmp(s_jmpNoCPUID, 1);
57  }
58 
59  static jmp_buf s_jmpNoSSE2;
60  static void SigIllHandlerSSE2(int)
61  {
62  longjmp(s_jmpNoSSE2, 1);
63  }
64 }
65 #endif
66 
67 bool CpuId(word32 input, word32 output[4])
68 {
69 #if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
70  __try
71  {
72  __asm
73  {
74  mov eax, input
75  mov ecx, 0
76  cpuid
77  mov edi, output
78  mov [edi], eax
79  mov [edi+4], ebx
80  mov [edi+8], ecx
81  mov [edi+12], edx
82  }
83  }
84  // GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION
85  __except (EXCEPTION_EXECUTE_HANDLER)
86  {
87  return false;
88  }
89 
90  // function 0 returns the highest basic function understood in EAX
91  if(input == 0)
92  return !!output[0];
93 
94  return true;
95 #else
96  // longjmp and clobber warnings. Volatile is required.
97  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
98  volatile bool result = true;
99 
100  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerCPUID);
101  if (oldHandler == SIG_ERR)
102  return false;
103 
104  volatile sigset_t oldMask;
105  if (sigprocmask(0, NULL, (sigset_t*)&oldMask))
106  return false;
107 
108  if (setjmp(s_jmpNoCPUID))
109  result = false;
110  else
111  {
112  asm volatile
113  (
114  // save ebx in case -fPIC is being used
115  // TODO: this might need an early clobber on EDI.
116 # if CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
117  "pushq %%rbx; cpuid; mov %%ebx, %%edi; popq %%rbx"
118 # else
119  "push %%ebx; cpuid; mov %%ebx, %%edi; pop %%ebx"
120 # endif
121  : "=a" (output[0]), "=D" (output[1]), "=c" (output[2]), "=d" (output[3])
122  : "a" (input), "c" (0)
123  );
124  }
125 
126  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULL);
127  signal(SIGILL, oldHandler);
128  return result;
129 #endif
130 }
131 
132 #endif
133 
134 static bool TrySSE2()
135 {
136 #if CRYPTOPP_BOOL_X64
137  return true;
138 #elif defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
139  __try
140  {
141 #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
142  AS2(por xmm0, xmm0) // executing SSE2 instruction
143 #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
144  __m128i x = _mm_setzero_si128();
145  return _mm_cvtsi128_si32(x) == 0;
146 #endif
147  }
148  // GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION
149  __except (EXCEPTION_EXECUTE_HANDLER)
150  {
151  return false;
152  }
153  return true;
154 #else
155  // longjmp and clobber warnings. Volatile is required.
156  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
157  volatile bool result = true;
158 
159  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerSSE2);
160  if (oldHandler == SIG_ERR)
161  return false;
162 
163  volatile sigset_t oldMask;
164  if (sigprocmask(0, NULL, (sigset_t*)&oldMask))
165  return false;
166 
167  if (setjmp(s_jmpNoSSE2))
168  result = false;
169  else
170  {
171 #if CRYPTOPP_BOOL_SSE2_ASM_AVAILABLE
172  __asm __volatile ("por %xmm0, %xmm0");
173 #elif CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE
174  __m128i x = _mm_setzero_si128();
175  result = _mm_cvtsi128_si32(x) == 0;
176 #endif
177  }
178 
179  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULL);
180  signal(SIGILL, oldHandler);
181  return result;
182 #endif
183 }
184 
185 bool g_x86DetectionDone = false;
186 bool g_hasMMX = false, g_hasISSE = false, g_hasSSE2 = false, g_hasSSSE3 = false, g_hasSSE4 = false, g_hasAESNI = false, g_hasCLMUL = false, g_isP4 = false, g_hasRDRAND = false, g_hasRDSEED = false;
187 bool g_hasPadlockRNG = false, g_hasPadlockACE = false, g_hasPadlockACE2 = false, g_hasPadlockPHE = false, g_hasPadlockPMM = false;
188 word32 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
189 
190 static inline bool IsIntel(const word32 output[4])
191 {
192  // This is the "GenuineIntel" string
193  return (output[1] /*EBX*/ == 0x756e6547) &&
194  (output[2] /*ECX*/ == 0x6c65746e) &&
195  (output[3] /*EDX*/ == 0x49656e69);
196 }
197 
198 static inline bool IsAMD(const word32 output[4])
199 {
200  // This is the "AuthenticAMD" string. Some early K5's can return "AMDisbetter!"
201  return (output[1] /*EBX*/ == 0x68747541) &&
202  (output[2] /*ECX*/ == 0x444D4163) &&
203  (output[3] /*EDX*/ == 0x69746E65);
204 }
205 
206 static inline bool IsVIA(const word32 output[4])
207 {
208  // This is the "CentaurHauls" string. Some non-PadLock can return "VIA VIA VIA ".
209  return (output[1] /*EBX*/ == 0x746e6543) &&
210  (output[2] /*ECX*/ == 0x736c7561) &&
211  (output[3] /*EDX*/ == 0x48727561);
212 }
213 
214 #if HAVE_GCC_CONSTRUCTOR1
215 void __attribute__ ((constructor (CRYPTOPP_INIT_PRIORITY + 50))) DetectX86Features()
216 #elif HAVE_GCC_CONSTRUCTOR0
217 void __attribute__ ((constructor)) DetectX86Features()
218 #else
219 void DetectX86Features()
220 #endif
221 {
222  word32 cpuid[4], cpuid1[4];
223  if (!CpuId(0, cpuid))
224  return;
225  if (!CpuId(1, cpuid1))
226  return;
227 
228  g_hasMMX = (cpuid1[3] & (1 << 23)) != 0;
229  if ((cpuid1[3] & (1 << 26)) != 0)
230  g_hasSSE2 = TrySSE2();
231  g_hasSSSE3 = g_hasSSE2 && (cpuid1[2] & (1<<9));
232  g_hasSSE4 = g_hasSSE2 && ((cpuid1[2] & (1<<19)) && (cpuid1[2] & (1<<20)));
233  g_hasAESNI = g_hasSSE2 && (cpuid1[2] & (1<<25));
234  g_hasCLMUL = g_hasSSE2 && (cpuid1[2] & (1<<1));
235 
236  if ((cpuid1[3] & (1 << 25)) != 0)
237  g_hasISSE = true;
238  else
239  {
240  word32 cpuid2[4];
241  CpuId(0x080000000, cpuid2);
242  if (cpuid2[0] >= 0x080000001)
243  {
244  CpuId(0x080000001, cpuid2);
245  g_hasISSE = (cpuid2[3] & (1 << 22)) != 0;
246  }
247  }
248 
249  if (IsIntel(cpuid))
250  {
251  static const unsigned int RDRAND_FLAG = (1 << 30);
252  static const unsigned int RDSEED_FLAG = (1 << 18);
253 
254  g_isP4 = ((cpuid1[0] >> 8) & 0xf) == 0xf;
255  g_cacheLineSize = 8 * GETBYTE(cpuid1[1], 1);
256  g_hasRDRAND = !!(cpuid1[2] /*ECX*/ & RDRAND_FLAG);
257 
258  if (cpuid[0] /*EAX*/ >= 7)
259  {
260  word32 cpuid3[4];
261  if (CpuId(7, cpuid3))
262  g_hasRDSEED = !!(cpuid3[1] /*EBX*/ & RDSEED_FLAG);
263  }
264  }
265  else if (IsAMD(cpuid))
266  {
267  static const unsigned int RDRAND_FLAG = (1 << 30);
268 
269  CpuId(0x01, cpuid);
270  g_hasRDRAND = !!(cpuid[2] /*ECX*/ & RDRAND_FLAG);
271 
272  CpuId(0x80000005, cpuid);
273  g_cacheLineSize = GETBYTE(cpuid[2], 0);
274  }
275  else if (IsVIA(cpuid))
276  {
277  static const unsigned int RNG_FLAGS = (0x3 << 2);
278  static const unsigned int ACE_FLAGS = (0x3 << 6);
279  static const unsigned int ACE2_FLAGS = (0x3 << 8);
280  static const unsigned int PHE_FLAGS = (0x3 << 10);
281  static const unsigned int PMM_FLAGS = (0x3 << 12);
282 
283  CpuId(0xC0000000, cpuid);
284  if (cpuid[0] < 0xC0000001)
285  {
286  // No extended features
287  g_hasPadlockRNG = false;
288  g_hasPadlockACE = false;
289  g_hasPadlockACE2 = false;
290  g_hasPadlockPHE = false;
291  g_hasPadlockPMM = false;
292  }
293  else
294  {
295  // Extended features available
296  CpuId(0xC0000001, cpuid);
297  g_hasPadlockRNG = !!(cpuid[3] /*EDX*/ & RNG_FLAGS);
298  g_hasPadlockACE = !!(cpuid[3] /*EDX*/ & ACE_FLAGS);
299  g_hasPadlockACE2 = !!(cpuid[3] /*EDX*/ & ACE2_FLAGS);
300  g_hasPadlockPHE = !!(cpuid[3] /*EDX*/ & PHE_FLAGS);
301  g_hasPadlockPMM = !!(cpuid[3] /*EDX*/ & PMM_FLAGS);
302  }
303  }
304 
305  if (!g_cacheLineSize)
306  g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
307 
308  *((volatile bool*)&g_x86DetectionDone) = true;
309 }
310 
311 #elif (CRYPTOPP_BOOL_ARM32 || CRYPTOPP_BOOL_ARM64)
312 
313 // The ARM equivalent of CPUID probing is reading a MSR. The code requires Exception Level 1 (EL1) and above, but user space runs at EL0.
314 // Attempting to run the code results in a SIGILL and termination.
315 //
316 // #if defined(__arm64__) || defined(__aarch64__)
317 // word64 caps = 0; // Read ID_AA64ISAR0_EL1
318 // __asm __volatile("mrs %0, " "id_aa64isar0_el1" : "=r" (caps));
319 // #elif defined(__arm__) || defined(__aarch32__)
320 // word32 caps = 0; // Read ID_ISAR5_EL1
321 // __asm __volatile("mrs %0, " "id_isar5_el1" : "=r" (caps));
322 // #endif
323 //
324 // The following does not work well either. Its appears to be missing constants, and it does not detect Aarch32 execution environments on Aarch64
325 // http://community.arm.com/groups/android-community/blog/2014/10/10/runtime-detection-of-cpu-features-on-an-armv8-a-cpu
326 //
327 bool g_ArmDetectionDone = false;
328 bool g_hasNEON = false, g_hasCRC32 = false, g_hasAES = false, g_hasSHA1 = false, g_hasSHA2 = false;
329 
330 word32 g_cacheLineSize = CRYPTOPP_L1_CACHE_LINE_SIZE;
331 
332 #ifndef CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
333 extern "C"
334 {
335  static jmp_buf s_jmpNoNEON;
336  static void SigIllHandlerNEON(int)
337  {
338  longjmp(s_jmpNoNEON, 1);
339  }
340 
341  static jmp_buf s_jmpNoCRC32;
342  static void SigIllHandlerCRC32(int)
343  {
344  longjmp(s_jmpNoCRC32, 1);
345  }
346 
347  static jmp_buf s_jmpNoAES;
348  static void SigIllHandlerAES(int)
349  {
350  longjmp(s_jmpNoAES, 1);
351  }
352 
353  static jmp_buf s_jmpNoSHA1;
354  static void SigIllHandlerSHA1(int)
355  {
356  longjmp(s_jmpNoSHA1, 1);
357  }
358 
359  static jmp_buf s_jmpNoSHA2;
360  static void SigIllHandlerSHA2(int)
361  {
362  longjmp(s_jmpNoSHA2, 1);
363  }
364 };
365 #endif // Not CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY
366 
367 static bool TryNEON()
368 {
369 #if (CRYPTOPP_BOOL_NEON_INTRINSICS_AVAILABLE)
370 # if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
371  volatile bool result = true;
372  __try
373  {
374  uint32_t v1[4] = {1,1,1,1};
375  uint32x4_t x1 = vld1q_u32(v1);
376  uint64_t v2[2] = {1,1};
377  uint64x2_t x2 = vld1q_u64(v2);
378 
379  uint32x4_t x3 = vdupq_n_u32(2);
380  x3 = vsetq_lane_u32(vgetq_lane_u32(x1,0),x3,0);
381  x3 = vsetq_lane_u32(vgetq_lane_u32(x1,3),x3,3);
382  uint64x2_t x4 = vdupq_n_u64(2);
383  x4 = vsetq_lane_u64(vgetq_lane_u64(x2,0),x4,0);
384  x4 = vsetq_lane_u64(vgetq_lane_u64(x2,1),x4,1);
385 
386  result = !!(vgetq_lane_u32(x3,0) | vgetq_lane_u64(x4,1));
387  }
388  __except (EXCEPTION_EXECUTE_HANDLER)
389  {
390  return false;
391  }
392  return result;
393 # else
394  // longjmp and clobber warnings. Volatile is required.
395  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
396  volatile bool result = true;
397 
398  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerNEON);
399  if (oldHandler == SIG_ERR)
400  return false;
401 
402  volatile sigset_t oldMask;
403  if (sigprocmask(0, NULL, (sigset_t*)&oldMask))
404  return false;
405 
406  if (setjmp(s_jmpNoNEON))
407  result = false;
408  else
409  {
410  uint32_t v1[4] = {1,1,1,1};
411  uint32x4_t x1 = vld1q_u32(v1);
412  uint64_t v2[2] = {1,1};
413  uint64x2_t x2 = vld1q_u64(v2);
414 
415  uint32x4_t x3 = {0,0,0,0};
416  x3 = vsetq_lane_u32(vgetq_lane_u32(x1,0),x3,0);
417  x3 = vsetq_lane_u32(vgetq_lane_u32(x1,3),x3,3);
418  uint64x2_t x4 = {0,0};
419  x4 = vsetq_lane_u64(vgetq_lane_u64(x2,0),x4,0);
420  x4 = vsetq_lane_u64(vgetq_lane_u64(x2,1),x4,1);
421 
422  // Hack... GCC optimizes away the code and returns true
423  result = !!(vgetq_lane_u32(x3,0) | vgetq_lane_u64(x4,1));
424  }
425 
426  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULL);
427  signal(SIGILL, oldHandler);
428  return result;
429 # endif
430 #else
431  return false;
432 #endif // CRYPTOPP_BOOL_NEON_INTRINSICS_AVAILABLE
433 }
434 
435 static bool TryCRC32()
436 {
437 #if (CRYPTOPP_BOOL_ARM_CRC32_INTRINSICS_AVAILABLE)
438 # if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
439  volatile bool result = true;
440  __try
441  {
442  word32 w=0, x=1; word16 y=2; byte z=3;
443  w = __crc32cw(w,x);
444  w = __crc32ch(w,y);
445  w = __crc32cb(w,z);
446 
447  result = !!w;
448  }
449  __except (EXCEPTION_EXECUTE_HANDLER)
450  {
451  return false;
452  }
453  return result;
454 # else
455  // longjmp and clobber warnings. Volatile is required.
456  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
457  volatile bool result = true;
458 
459  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerCRC32);
460  if (oldHandler == SIG_ERR)
461  return false;
462 
463  volatile sigset_t oldMask;
464  if (sigprocmask(0, NULL, (sigset_t*)&oldMask))
465  return false;
466 
467  if (setjmp(s_jmpNoCRC32))
468  result = false;
469  else
470  {
471  word32 w=0, x=1; word16 y=2; byte z=3;
472  w = __crc32cw(w,x);
473  w = __crc32ch(w,y);
474  w = __crc32cb(w,z);
475 
476  // Hack... GCC optimizes away the code and returns true
477  result = !!w;
478  }
479 
480  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULL);
481  signal(SIGILL, oldHandler);
482  return result;
483 # endif
484 #else
485  return false;
486 #endif // CRYPTOPP_BOOL_ARM_CRC32_INTRINSICS_AVAILABLE
487 }
488 
489 static bool TryAES()
490 {
491 #if (CRYPTOPP_BOOL_ARM_CRYPTO_INTRINSICS_AVAILABLE)
492 # if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
493  volatile bool result = true;
494  __try
495  {
496  // AES encrypt and decrypt
497  uint8x16_t data = vdupq_n_u8(0), key = vdupq_n_u8(0);
498  uint8x16_t r1 = vaeseq_u8(data, key);
499  uint8x16_t r2 = vaesdq_u8(data, key);
500 
501  result = !!(vgetq_lane_u8(r1,0) | vgetq_lane_u8(r2,7));
502  }
503  __except (EXCEPTION_EXECUTE_HANDLER)
504  {
505  return false;
506  }
507  return result;
508 # else
509  // longjmp and clobber warnings. Volatile is required.
510  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
511  volatile bool result = true;
512 
513  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerAES);
514  if (oldHandler == SIG_ERR)
515  return false;
516 
517  volatile sigset_t oldMask;
518  if (sigprocmask(0, NULL, (sigset_t*)&oldMask))
519  return false;
520 
521  if (setjmp(s_jmpNoAES))
522  result = false;
523  else
524  {
525  uint8x16_t data = vdupq_n_u8(0), key = vdupq_n_u8(0);
526  uint8x16_t r1 = vaeseq_u8(data, key);
527  uint8x16_t r2 = vaesdq_u8(data, key);
528 
529  // Hack... GCC optimizes away the code and returns true
530  result = !!(vgetq_lane_u8(r1,0) | vgetq_lane_u8(r2,7));
531  }
532 
533  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULL);
534  signal(SIGILL, oldHandler);
535  return result;
536 # endif
537 #else
538  return false;
539 #endif // CRYPTOPP_BOOL_ARM_CRYPTO_INTRINSICS_AVAILABLE
540 }
541 
542 static bool TrySHA1()
543 {
544 #if (CRYPTOPP_BOOL_ARM_CRYPTO_INTRINSICS_AVAILABLE)
545 # if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
546  volatile bool result = true;
547  __try
548  {
549  uint32x4_t data1 = {1,2,3,4}, data2 = {5,6,7,8}, data3 = {9,10,11,12};
550 
551  uint32x4_t r1 = vsha1cq_u32 (data1, 0, data2);
552  uint32x4_t r2 = vsha1mq_u32 (data1, 0, data2);
553  uint32x4_t r3 = vsha1pq_u32 (data1, 0, data2);
554  uint32x4_t r4 = vsha1su0q_u32 (data1, data2, data3);
555  uint32x4_t r5 = vsha1su1q_u32 (data1, data2);
556 
557  result = !!(vgetq_lane_u32(r1,0) | vgetq_lane_u32(r2,1) | vgetq_lane_u32(r3,2) | vgetq_lane_u32(r4,3) | vgetq_lane_u32(r5,0));
558  }
559  __except (EXCEPTION_EXECUTE_HANDLER)
560  {
561  return false;
562  }
563  return result;
564 # else
565  // longjmp and clobber warnings. Volatile is required.
566  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
567  volatile bool result = true;
568 
569  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerSHA1);
570  if (oldHandler == SIG_ERR)
571  return false;
572 
573  volatile sigset_t oldMask;
574  if (sigprocmask(0, NULL, (sigset_t*)&oldMask))
575  return false;
576 
577  if (setjmp(s_jmpNoSHA1))
578  result = false;
579  else
580  {
581  uint32x4_t data1 = {1,2,3,4}, data2 = {5,6,7,8}, data3 = {9,10,11,12};
582 
583  uint32x4_t r1 = vsha1cq_u32 (data1, 0, data2);
584  uint32x4_t r2 = vsha1mq_u32 (data1, 0, data2);
585  uint32x4_t r3 = vsha1pq_u32 (data1, 0, data2);
586  uint32x4_t r4 = vsha1su0q_u32 (data1, data2, data3);
587  uint32x4_t r5 = vsha1su1q_u32 (data1, data2);
588 
589  // Hack... GCC optimizes away the code and returns true
590  result = !!(vgetq_lane_u32(r1,0) | vgetq_lane_u32(r2,1) | vgetq_lane_u32(r3,2) | vgetq_lane_u32(r4,3) | vgetq_lane_u32(r5,0));
591  }
592 
593  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULL);
594  signal(SIGILL, oldHandler);
595  return result;
596 # endif
597 #else
598  return false;
599 #endif // CRYPTOPP_BOOL_ARM_CRYPTO_INTRINSICS_AVAILABLE
600 }
601 
602 static bool TrySHA2()
603 {
604 #if (CRYPTOPP_BOOL_ARM_CRYPTO_INTRINSICS_AVAILABLE)
605 # if defined(CRYPTOPP_MS_STYLE_INLINE_ASSEMBLY)
606  volatile bool result = true;
607  __try
608  {
609  uint32x4_t data1 = {1,2,3,4}, data2 = {5,6,7,8}, data3 = {9,10,11,12};
610 
611  uint32x4_t r1 = vsha256hq_u32 (data1, data2, data3);
612  uint32x4_t r2 = vsha256h2q_u32 (data1, data2, data3);
613  uint32x4_t r3 = vsha256su0q_u32 (data1, data2);
614  uint32x4_t r4 = vsha256su1q_u32 (data1, data2, data3);
615 
616  result = !!(vgetq_lane_u32(r1,0) | vgetq_lane_u32(r2,1) | vgetq_lane_u32(r3,2) | vgetq_lane_u32(r4,3));
617  }
618  __except (EXCEPTION_EXECUTE_HANDLER)
619  {
620  return false;
621  }
622  return result;
623 # else
624  // longjmp and clobber warnings. Volatile is required.
625  // http://github.com/weidai11/cryptopp/issues/24 and http://stackoverflow.com/q/7721854
626  volatile bool result = true;
627 
628  volatile SigHandler oldHandler = signal(SIGILL, SigIllHandlerSHA2);
629  if (oldHandler == SIG_ERR)
630  return false;
631 
632  volatile sigset_t oldMask;
633  if (sigprocmask(0, NULL, (sigset_t*)&oldMask))
634  return false;
635 
636  if (setjmp(s_jmpNoSHA2))
637  result = false;
638  else
639  {
640  uint32x4_t data1 = {1,2,3,4}, data2 = {5,6,7,8}, data3 = {9,10,11,12};
641 
642  uint32x4_t r1 = vsha256hq_u32 (data1, data2, data3);
643  uint32x4_t r2 = vsha256h2q_u32 (data1, data2, data3);
644  uint32x4_t r3 = vsha256su0q_u32 (data1, data2);
645  uint32x4_t r4 = vsha256su1q_u32 (data1, data2, data3);
646 
647  // Hack... GCC optimizes away the code and returns true
648  result = !!(vgetq_lane_u32(r1,0) | vgetq_lane_u32(r2,1) | vgetq_lane_u32(r3,2) | vgetq_lane_u32(r4,3));
649  }
650 
651  sigprocmask(SIG_SETMASK, (sigset_t*)&oldMask, NULL);
652  signal(SIGILL, oldHandler);
653  return result;
654 # endif
655 #else
656  return false;
657 #endif // CRYPTOPP_BOOL_ARM_CRYPTO_INTRINSICS_AVAILABLE
658 }
659 
660 #if HAVE_GCC_CONSTRUCTOR1
661 void __attribute__ ((constructor (CRYPTOPP_INIT_PRIORITY + 50))) DetectArmFeatures()
662 #elif HAVE_GCC_CONSTRUCTOR0
663 void __attribute__ ((constructor)) DetectArmFeatures()
664 #else
665 void DetectArmFeatures()
666 #endif
667 {
668  g_hasNEON = TryNEON();
669  g_hasCRC32 = TryCRC32();
670  g_hasAES = TryAES();
671  g_hasSHA1 = TrySHA1();
672  g_hasSHA2 = TrySHA2();
673 
674  *((volatile bool*)&g_ArmDetectionDone) = true;
675 }
676 
677 #endif
678 
679 NAMESPACE_END
680 
681 #endif
Utility functions for the Crypto++ library.
Library configuration file.
Functions for CPU features and intrinsics.
Crypto++ library namespace.