Commit 48d320c0 authored by Niels Möller's avatar Niels Möller

New macros to help define resolver and wrappers for fat functions.

parent 0149d937
2015-01-17 Niels Möller <nisse@lysator.liu.se> 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 * config.m4.in (SYMBOL_PREFIX): Define from from autoconf
ASM_SYMBOL_PREFIX. ASM_SYMBOL_PREFIX.
(C_NAMS): move definition to... (C_NAMS): move definition to...
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
threads. threads.
The fat_init function checks the cpuid flags, and sets function 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. implementation.
To get everything hooked in, we use a belt-and-suspenders approach. To get everything hooked in, we use a belt-and-suspenders approach.
...@@ -62,31 +62,92 @@ ...@@ -62,31 +62,92 @@
If ifunc support is available, function pointers are statically If ifunc support is available, function pointers are statically
initialized to NULL, and we register resolver functions, e.g., initialized to NULL, and we register resolver functions, e.g.,
_aes_encrypt_resolve, which call fat_init, and then return the _nettle_aes_encrypt_resolve, which call fat_init, and then return
function pointer, e.g., the value of _aes_encrypt_vec. 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 If ifunc is not available, we have to define a wrapper function to
jump via the function pointer. (FIXME: For internal calls, we could jump via the function pointer. (FIXME: For internal calls, we could
do this as a macro). We statically initialize each function pointer do this as a macro). We statically initialize each function pointer
to point to a special initialization function, e.g., to point to a special initialization function, e.g.,
_aes_encrypt_init, which calls fat_init, and then invokes the right _nettle_aes_encrypt_init, which calls fat_init, and then invokes
function. This way, all pointers are setup correctly at the first the right function. This way, all pointers are setup correctly at
call to any fat function. the first call to any fat function.
*/ */
#if HAVE_LINK_IFUNC #if HAVE_LINK_IFUNC
# define IFUNC(resolve) __attribute__ ((ifunc (resolve))) # define IFUNC(resolve) __attribute__ ((ifunc (resolve)))
# define vec_init(f) NULL
# define FAT_BOILERPLATE()
#else #else
# define IFUNC(resolve) # define IFUNC(resolve)
# define vec_init(f) f##_init
#endif #endif
#if HAVE_GCC_ATTRIBUTE #if HAVE_GCC_ATTRIBUTE
# define CONSTRUCTOR __attribute__ ((constructor)) # define CONSTRUCTOR __attribute__ ((constructor))
#elif defined (__sun) #else
# pragma init(fat_init)
# define CONSTRUCTOR # define CONSTRUCTOR
# if defined (__sun)
# pragma init(fat_init)
# endif
#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]); void _nettle_cpuid (uint32_t input, uint32_t regs[4]);
typedef void void_func (void); typedef void void_func (void);
...@@ -95,31 +156,19 @@ typedef void aes_crypt_internal_func (unsigned rounds, const uint32_t *keys, ...@@ -95,31 +156,19 @@ typedef void aes_crypt_internal_func (unsigned rounds, const uint32_t *keys,
const struct aes_table *T, const struct aes_table *T,
size_t length, uint8_t *dst, size_t length, uint8_t *dst,
const uint8_t *src); const uint8_t *src);
aes_crypt_internal_func _aes_encrypt IFUNC ("_aes_encrypt_resolve"); DECLARE_FAT_FUNC(_nettle_aes_encrypt, aes_crypt_internal_func)
aes_crypt_internal_func _nettle_aes_encrypt_x86_64; DECLARE_FAT_FUNC_VAR(aes_encrypt, aes_crypt_internal_func, x86_64)
aes_crypt_internal_func _nettle_aes_encrypt_aesni; DECLARE_FAT_FUNC_VAR(aes_encrypt, aes_crypt_internal_func, aesni)
aes_crypt_internal_func _aes_decrypt IFUNC ("_aes_decrypt_resolve"); DECLARE_FAT_FUNC(_nettle_aes_decrypt, aes_crypt_internal_func)
aes_crypt_internal_func _nettle_aes_decrypt_x86_64; DECLARE_FAT_FUNC_VAR(aes_decrypt, aes_crypt_internal_func, x86_64)
aes_crypt_internal_func _nettle_aes_decrypt_aesni; 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"); DECLARE_FAT_FUNC(nettle_memxor, memxor_func)
memxor_func _nettle_memxor_x86_64; DECLARE_FAT_FUNC_VAR(memxor, memxor_func, x86_64)
memxor_func _nettle_memxor_sse2; DECLARE_FAT_FUNC_VAR(memxor, memxor_func, 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;
/* This function should usually be called only once, at startup. But /* This function should usually be called only once, at startup. But
it is idempotent, and on x86, pointer updates are atomic, so it is idempotent, and on x86, pointer updates are atomic, so
...@@ -148,15 +197,15 @@ fat_init (void) ...@@ -148,15 +197,15 @@ fat_init (void)
{ {
if (verbose) if (verbose)
fprintf (stderr, "libnettle: aes instructions available.\n"); fprintf (stderr, "libnettle: aes instructions available.\n");
_aes_encrypt_vec = _nettle_aes_encrypt_aesni; _nettle_aes_encrypt_vec = _nettle_aes_encrypt_aesni;
_aes_decrypt_vec = _nettle_aes_decrypt_aesni; _nettle_aes_decrypt_vec = _nettle_aes_decrypt_aesni;
} }
else else
{ {
if (verbose) if (verbose)
fprintf (stderr, "libnettle: aes instructions not available.\n"); fprintf (stderr, "libnettle: aes instructions not available.\n");
_aes_encrypt_vec = _nettle_aes_encrypt_x86_64; _nettle_aes_encrypt_vec = _nettle_aes_encrypt_x86_64;
_aes_decrypt_vec = _nettle_aes_decrypt_x86_64; _nettle_aes_decrypt_vec = _nettle_aes_decrypt_x86_64;
} }
_nettle_cpuid (0, cpuid_data); _nettle_cpuid (0, cpuid_data);
...@@ -166,13 +215,13 @@ fat_init (void) ...@@ -166,13 +215,13 @@ fat_init (void)
{ {
if (verbose) if (verbose)
fprintf (stderr, "libnettle: intel SSE2 will be used for XOR.\n"); fprintf (stderr, "libnettle: intel SSE2 will be used for XOR.\n");
_memxor_vec = _nettle_memxor_sse2; nettle_memxor_vec = _nettle_memxor_sse2;
} }
else else
{ {
if (verbose) if (verbose)
fprintf (stderr, "libnettle: intel SSE2 will not be used for XOR.\n"); 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 /* The x86_64 architecture should always make stores visible in the
...@@ -181,87 +230,20 @@ fat_init (void) ...@@ -181,87 +230,20 @@ fat_init (void)
initialized = 1; initialized = 1;
} }
#if HAVE_LINK_IFUNC DEFINE_FAT_FUNC(_nettle_aes_encrypt, void,
(unsigned rounds, const uint32_t *keys,
static void_func * const struct aes_table *T,
_aes_encrypt_resolve (void) size_t length, uint8_t *dst,
{ const uint8_t *src),
if (getenv ("NETTLE_FAT_VERBOSE")) (rounds, keys, T, length, dst, src))
fprintf (stderr, "libnettle: _aes_encrypt_resolve\n");
fat_init (); DEFINE_FAT_FUNC(_nettle_aes_decrypt, void,
return (void_func *) _aes_encrypt_vec; (unsigned rounds, const uint32_t *keys,
} const struct aes_table *T,
size_t length, uint8_t *dst,
static void_func * const uint8_t *src),
_aes_decrypt_resolve (void) (rounds, keys, T, length, dst, src))
{
if (getenv ("NETTLE_FAT_VERBOSE")) DEFINE_FAT_FUNC(nettle_memxor, void *,
fprintf (stderr, "libnettle: _aes_decrypt_resolve\n"); (void *dst, const void *src, size_t n),
fat_init (); (dst, src, n))
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 */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment