diff --git a/ChangeLog b/ChangeLog index c5f0b5638f10eca471e5344ed6544d86e132c71f..de1bc50d9d0a61720d06d82479b4bd5e7eae5089 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2015-01-17 Niels Möller <nisse@lysator.liu.se> + * fat-x86_64.c (DECLARE_FAT_FUNC, DEFINE_FAT_FUNC) + (DECLARE_FAT_FUNC_VAR): New macros, to define needed resolver and + wrapper functions. + * config.m4.in (SYMBOL_PREFIX): Define from from autoconf ASM_SYMBOL_PREFIX. (C_NAMS): move definition to... diff --git a/fat-x86_64.c b/fat-x86_64.c index 61d622395656c648e45437d9cae476164a9e9505..cd67f366ab87c8836852facf683363b91bdad2e0 100644 --- a/fat-x86_64.c +++ b/fat-x86_64.c @@ -49,7 +49,7 @@ threads. The fat_init function checks the cpuid flags, and sets function - pointers, e.g, _aes_encrypt_vec, to point to the appropriate + pointers, e.g, _nettle_aes_encrypt_vec, to point to the appropriate implementation. To get everything hooked in, we use a belt-and-suspenders approach. @@ -62,31 +62,92 @@ If ifunc support is available, function pointers are statically initialized to NULL, and we register resolver functions, e.g., - _aes_encrypt_resolve, which call fat_init, and then return the - function pointer, e.g., the value of _aes_encrypt_vec. + _nettle_aes_encrypt_resolve, which call fat_init, and then return + the function pointer, e.g., the value of _nettle_aes_encrypt_vec. If ifunc is not available, we have to define a wrapper function to jump via the function pointer. (FIXME: For internal calls, we could do this as a macro). We statically initialize each function pointer to point to a special initialization function, e.g., - _aes_encrypt_init, which calls fat_init, and then invokes the right - function. This way, all pointers are setup correctly at the first - call to any fat function. + _nettle_aes_encrypt_init, which calls fat_init, and then invokes + the right function. This way, all pointers are setup correctly at + the first call to any fat function. */ #if HAVE_LINK_IFUNC # define IFUNC(resolve) __attribute__ ((ifunc (resolve))) +# define vec_init(f) NULL +# define FAT_BOILERPLATE() #else # define IFUNC(resolve) +# define vec_init(f) f##_init #endif #if HAVE_GCC_ATTRIBUTE # define CONSTRUCTOR __attribute__ ((constructor)) -#elif defined (__sun) -# pragma init(fat_init) +#else # define CONSTRUCTOR +# if defined (__sun) +# pragma init(fat_init) +# endif #endif +/* DECLARE_FAT_FUNC(name, ftype) + * + * name is the public function, e.g., _nettle_aes_encrypt. + * ftype is its type, e.g., aes_crypt_internal_func. + * + * DECLARE_FAT_VAR(name, type, var) + * + * name is name without _nettle prefix. + * type is its type. + * var is the variant, used as a suffix on the symbol name. + * + * DEFINE_FAT_FUNC(name, rtype, prototype, args) + * + * name is the public function. + * rtype its return type. + * prototype is the list of formal arguments, with types. + * args contain the argument list without any types. + */ + +#if HAVE_LINK_IFUNC +#define DECLARE_FAT_FUNC(name, ftype) \ + ftype name IFUNC(#name"_resolve"); \ + static ftype *name##_vec = NULL; + +#define DEFINE_FAT_FUNC(name, rtype, prototype, args) \ + static void_func * name##_resolve(void) \ + { \ + if (getenv ("NETTLE_FAT_VERBOSE")) \ + fprintf (stderr, "libnettle: "#name"_resolve\n"); \ + fat_init(); \ + return (void_func *) name##_vec; \ + } + +#else /* !HAVE_LINK_IFUNC */ +#define DECLARE_FAT_FUNC(name, ftype) \ + ftype name; \ + static ftype name##_init; \ + static ftype *name##_vec = name##_init; + +#define DEFINE_FAT_FUNC(name, rtype, prototype, args) \ + rtype name prototype \ + { \ + return name##_vec args; \ + } \ + static rtype name##_init prototype { \ + if (getenv ("NETTLE_FAT_VERBOSE")) \ + fprintf (stderr, "libnettle: "#name"_init\n"); \ + fat_init(); \ + assert (name##_vec != name##_init); \ + return name##_vec args; \ + } +#endif /* !HAVE_LINK_IFUNC */ + +#define DECLARE_FAT_FUNC_VAR(name, type, var) \ + type _nettle_##name##_##var; + void _nettle_cpuid (uint32_t input, uint32_t regs[4]); typedef void void_func (void); @@ -95,31 +156,19 @@ typedef void aes_crypt_internal_func (unsigned rounds, const uint32_t *keys, const struct aes_table *T, size_t length, uint8_t *dst, const uint8_t *src); -aes_crypt_internal_func _aes_encrypt IFUNC ("_aes_encrypt_resolve"); -aes_crypt_internal_func _nettle_aes_encrypt_x86_64; -aes_crypt_internal_func _nettle_aes_encrypt_aesni; +DECLARE_FAT_FUNC(_nettle_aes_encrypt, aes_crypt_internal_func) +DECLARE_FAT_FUNC_VAR(aes_encrypt, aes_crypt_internal_func, x86_64) +DECLARE_FAT_FUNC_VAR(aes_encrypt, aes_crypt_internal_func, aesni) -aes_crypt_internal_func _aes_decrypt IFUNC ("_aes_decrypt_resolve"); -aes_crypt_internal_func _nettle_aes_decrypt_x86_64; -aes_crypt_internal_func _nettle_aes_decrypt_aesni; +DECLARE_FAT_FUNC(_nettle_aes_decrypt, aes_crypt_internal_func) +DECLARE_FAT_FUNC_VAR(aes_decrypt, aes_crypt_internal_func, x86_64) +DECLARE_FAT_FUNC_VAR(aes_decrypt, aes_crypt_internal_func, aesni) -typedef void *(memxor_func)(void *dst_in, const void *src_in, size_t n); +typedef void *(memxor_func)(void *dst, const void *src, size_t n); -memxor_func nettle_memxor IFUNC ("_memxor_resolve"); -memxor_func _nettle_memxor_x86_64; -memxor_func _nettle_memxor_sse2; - -#if HAVE_LINK_IFUNC -#define _aes_encrypt_init NULL -#define _aes_decrypt_init NULL -#else -static aes_crypt_internal_func _aes_encrypt_init; -static aes_crypt_internal_func _aes_decrypt_init; -#endif - -static aes_crypt_internal_func *_aes_encrypt_vec = _aes_encrypt_init; -static aes_crypt_internal_func *_aes_decrypt_vec = _aes_decrypt_init; -static memxor_func *_memxor_vec = _nettle_memxor_x86_64; +DECLARE_FAT_FUNC(nettle_memxor, memxor_func) +DECLARE_FAT_FUNC_VAR(memxor, memxor_func, x86_64) +DECLARE_FAT_FUNC_VAR(memxor, memxor_func, sse2) /* This function should usually be called only once, at startup. But it is idempotent, and on x86, pointer updates are atomic, so @@ -148,15 +197,15 @@ fat_init (void) { if (verbose) fprintf (stderr, "libnettle: aes instructions available.\n"); - _aes_encrypt_vec = _nettle_aes_encrypt_aesni; - _aes_decrypt_vec = _nettle_aes_decrypt_aesni; + _nettle_aes_encrypt_vec = _nettle_aes_encrypt_aesni; + _nettle_aes_decrypt_vec = _nettle_aes_decrypt_aesni; } else { if (verbose) fprintf (stderr, "libnettle: aes instructions not available.\n"); - _aes_encrypt_vec = _nettle_aes_encrypt_x86_64; - _aes_decrypt_vec = _nettle_aes_decrypt_x86_64; + _nettle_aes_encrypt_vec = _nettle_aes_encrypt_x86_64; + _nettle_aes_decrypt_vec = _nettle_aes_decrypt_x86_64; } _nettle_cpuid (0, cpuid_data); @@ -166,13 +215,13 @@ fat_init (void) { if (verbose) fprintf (stderr, "libnettle: intel SSE2 will be used for XOR.\n"); - _memxor_vec = _nettle_memxor_sse2; + nettle_memxor_vec = _nettle_memxor_sse2; } else { if (verbose) fprintf (stderr, "libnettle: intel SSE2 will not be used for XOR.\n"); - _memxor_vec = _nettle_memxor_x86_64; + nettle_memxor_vec = _nettle_memxor_x86_64; } /* The x86_64 architecture should always make stores visible in the @@ -181,87 +230,20 @@ fat_init (void) initialized = 1; } -#if HAVE_LINK_IFUNC - -static void_func * -_aes_encrypt_resolve (void) -{ - if (getenv ("NETTLE_FAT_VERBOSE")) - fprintf (stderr, "libnettle: _aes_encrypt_resolve\n"); - fat_init (); - return (void_func *) _aes_encrypt_vec; -} - -static void_func * -_aes_decrypt_resolve (void) -{ - if (getenv ("NETTLE_FAT_VERBOSE")) - fprintf (stderr, "libnettle: _aes_decrypt_resolve\n"); - fat_init (); - return (void_func *) _aes_decrypt_vec; -} - -static void_func * -_memxor_resolve (void) -{ - if (getenv ("NETTLE_FAT_VERBOSE")) - fprintf (stderr, "libnettle: _memxor_resolve\n"); - fat_init (); - return (void_func *) _memxor_vec; -} - -#else /* !HAVE_LINK_IFUNC */ - -/* We need wrapper functions jumping via the function pointer. */ -void -_aes_encrypt (unsigned rounds, const uint32_t *keys, - const struct aes_table *T, - size_t length, uint8_t *dst, - const uint8_t *src) -{ - _aes_encrypt_vec (rounds, keys, T, length, dst, src); -} - -static void -_aes_encrypt_init (unsigned rounds, const uint32_t *keys, - const struct aes_table *T, - size_t length, uint8_t *dst, - const uint8_t *src) -{ - if (getenv ("NETTLE_FAT_VERBOSE")) - fprintf (stderr, "libnettle: _aes_encrypt_init\n"); - fat_init (); - assert (_aes_encrypt_vec != _aes_encrypt_init); - _aes_encrypt (rounds, keys, T, length, dst, src); -} - -void -_aes_decrypt (unsigned rounds, const uint32_t *keys, - const struct aes_table *T, - size_t length, uint8_t *dst, - const uint8_t *src) -{ - _aes_decrypt_vec (rounds, keys, T, length, dst, src); -} - -static void -_aes_decrypt_init (unsigned rounds, const uint32_t *keys, - const struct aes_table *T, - size_t length, uint8_t *dst, - const uint8_t *src) -{ - if (getenv ("NETTLE_FAT_VERBOSE")) - fprintf (stderr, "libnettle: _aes_decrypt_init\n"); - fat_init (); - assert (_aes_decrypt_vec != _aes_decrypt_init); - _aes_decrypt (rounds, keys, T, length, dst, src); -} - -/* FIXME: Missing _memxor_init. */ -void * -memxor(void *dst_in, const void *src_in, size_t n) -{ - return _memxor_vec (dst_in, src_in, n); -} - -#endif /* !HAVE_LINK_IFUNC */ +DEFINE_FAT_FUNC(_nettle_aes_encrypt, void, + (unsigned rounds, const uint32_t *keys, + const struct aes_table *T, + size_t length, uint8_t *dst, + const uint8_t *src), + (rounds, keys, T, length, dst, src)) + +DEFINE_FAT_FUNC(_nettle_aes_decrypt, void, + (unsigned rounds, const uint32_t *keys, + const struct aes_table *T, + size_t length, uint8_t *dst, + const uint8_t *src), + (rounds, keys, T, length, dst, src)) + +DEFINE_FAT_FUNC(nettle_memxor, void *, + (void *dst, const void *src, size_t n), + (dst, src, n))