diff options
Diffstat (limited to '')
| -rw-r--r-- | process.c | 42 | 
1 files changed, 39 insertions, 3 deletions
| @@ -1,5 +1,6 @@  /* See LICENSE file for copyright and license details. */  #include "common.h" +#include <stdatomic.h>  #if defined(__SSE4_1__) && defined(__SSSE3__) && defined(__SSE2__) && defined(__SHA__)  # define HAVE_X86_SHA_INTRINSICS @@ -260,20 +261,55 @@ process_x86_sha(struct libsha1_state *restrict state, const unsigned char *restr  		abcd_orig = _mm_add_epi32(abcd, abcd_orig);  	} -	abcd_orig = _mm_shuffle_epi32(abcd_orig, 32 - 5); +	_mm_storeu_si128((__m128i *)&state->h[0], _mm_shuffle_epi32(abcd_orig, 32 - 5));  	state->h[4] = (uint_least32_t)_mm_extract_epi32(e000_orig, 3); -	_mm_storeu_si128((__m128i *)&state->h[0], abcd_orig);  	return off;  } +# if defined(__GNUC__) +__attribute__((__constructor__)) +# endif +static int +have_sha_intrinsics(void) +{ +        static volatile int ret = -1; +        static volatile atomic_flag spinlock = ATOMIC_FLAG_INIT; + +	if (ret != -1) +		return ret; + +        while (atomic_flag_test_and_set(&spinlock)); + +	if (ret != -1) +		goto out; + +	int a = 7, b, c = 0, d; +	__asm__ volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(a), "c"(c)); +	if (!(b & (1 << 29))) { +		ret = 0; +		goto out; +	} +	a = 1; +	__asm__ volatile("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "a"(a), "c"(c)); +	if (!(c & (1 << 19)) || !(c & (1 << 0)) || !(d & (1 << 26))) { +		ret = 0; +		goto out; +	} +	ret = 1; + +out: +	atomic_flag_clear(&spinlock); +	return ret; +} +  #endif  size_t  libsha1_process(struct libsha1_state *restrict state, const unsigned char *restrict data, size_t len)  {  #ifdef HAVE_X86_SHA_INTRINSICS -	if (state->algorithm == LIBSHA1_1) +	if (state->algorithm == LIBSHA1_1 && have_sha_intrinsics())  		return process_x86_sha(state, data, len);  #endif  	return process_portable(state, data, len); | 
