Commit dff9f68c authored by Niels Möller's avatar Niels Möller

Made fat initialization more robust.

parent b686476f
2015-01-23 Niels Möller <nisse@lysator.liu.se>
* fat-setup.h (DEFINE_FAT_FUNC): Check value of function pointer,
before calling fat_init. Should be correct even without memory
barrier.
* fat-x86_64.c (fat_init): Deleted static variable initialized.
The checks of the relevant pointer in DEFINE_FAT_FUNC is more
robust.
* fat-arm.c (fat_init): Likewise.
2015-01-21 Niels Möller <nisse@lysator.liu.se> 2015-01-21 Niels Möller <nisse@lysator.liu.se>
* fat-arm.c (fat_init): Setup for use of neon assembly functions. * fat-arm.c (fat_init): Setup for use of neon assembly functions.
......
...@@ -164,13 +164,9 @@ DECLARE_FAT_FUNC_VAR(umac_nh_n, umac_nh_n_func, neon); ...@@ -164,13 +164,9 @@ DECLARE_FAT_FUNC_VAR(umac_nh_n, umac_nh_n_func, neon);
static void CONSTRUCTOR static void CONSTRUCTOR
fat_init (void) fat_init (void)
{ {
static volatile int initialized = 0;
struct arm_features features; struct arm_features features;
int verbose; int verbose;
if (initialized)
return;
get_arm_features (&features); get_arm_features (&features);
verbose = getenv (ENV_VERBOSE) != NULL; verbose = getenv (ENV_VERBOSE) != NULL;
...@@ -213,8 +209,6 @@ fat_init (void) ...@@ -213,8 +209,6 @@ fat_init (void)
_nettle_umac_nh_vec = _nettle_umac_nh_c; _nettle_umac_nh_vec = _nettle_umac_nh_c;
_nettle_umac_nh_n_vec = _nettle_umac_nh_n_c; _nettle_umac_nh_n_vec = _nettle_umac_nh_n_c;
} }
/* FIXME: Needs memory barrier, to enforce store ordering. */
initialized = 1;
} }
DEFINE_FAT_FUNC(_nettle_aes_encrypt, void, DEFINE_FAT_FUNC(_nettle_aes_encrypt, void,
......
...@@ -30,10 +30,11 @@ ...@@ -30,10 +30,11 @@
*/ */
/* Fat library initialization works as follows. The main function is /* Fat library initialization works as follows. The main function is
fat_init. It tries to do initialization only once, but since it is fat_init. We try to do initialization only once, but since it is
idempotent and pointer updates are atomic on x86_64, there's no idempotent, there's no harm if it is in some cases called multiple
harm if it is in some cases called multiple times from several times from several threads. For correctness, we rely on atomic
threads. writes, but not on memory barriers or any other synchronization
mechanism.
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, _nettle_aes_encrypt_vec, to point to the appropriate pointers, e.g, _nettle_aes_encrypt_vec, to point to the appropriate
...@@ -47,18 +48,24 @@ ...@@ -47,18 +48,24 @@
For the actual indirection, there are two cases. For the actual indirection, there are two cases.
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.,
_nettle_aes_encrypt_resolve, which call fat_init, and then return _nettle_aes_encrypt_resolve, which call fat_init, and then return
the function pointer, e.g., the value of _nettle_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
jump via the function pointer. (FIXME: For internal calls, we could to jump via the function pointer. (FIXME: For internal calls, we
do this as a macro). We statically initialize each function pointer could do this as a macro).
to point to a special initialization function, e.g.,
_nettle_aes_encrypt_init, which calls fat_init, and then invokes We statically initialize each function pointer to point to a
the right function. This way, all pointers are setup correctly at special initialization function, e.g., _nettle_aes_encrypt_init,
the first call to any fat function. 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.
And atomic writes are required for correctness in the case that
several threads do "first call to any fat function" at the same
time.
*/ */
#if HAVE_GCC_ATTRIBUTE #if HAVE_GCC_ATTRIBUTE
...@@ -107,7 +114,8 @@ ...@@ -107,7 +114,8 @@
{ \ { \
if (getenv (ENV_VERBOSE)) \ if (getenv (ENV_VERBOSE)) \
fprintf (stderr, "libnettle: "#name"_resolve\n"); \ fprintf (stderr, "libnettle: "#name"_resolve\n"); \
fat_init(); \ if (!name##_vec) \
fat_init(); \
return (void_func *) name##_vec; \ return (void_func *) name##_vec; \
} }
...@@ -125,7 +133,8 @@ ...@@ -125,7 +133,8 @@
static rtype name##_init prototype { \ static rtype name##_init prototype { \
if (getenv (ENV_VERBOSE)) \ if (getenv (ENV_VERBOSE)) \
fprintf (stderr, "libnettle: "#name"_init\n"); \ fprintf (stderr, "libnettle: "#name"_init\n"); \
fat_init(); \ if (name##_vec == name##_init) \
fat_init(); \
assert (name##_vec != name##_init); \ assert (name##_vec != name##_init); \
return name##_vec args; \ return name##_vec args; \
} }
......
...@@ -122,11 +122,8 @@ DECLARE_FAT_FUNC_VAR(memxor, memxor_func, sse2) ...@@ -122,11 +122,8 @@ DECLARE_FAT_FUNC_VAR(memxor, memxor_func, sse2)
static void CONSTRUCTOR static void CONSTRUCTOR
fat_init (void) fat_init (void)
{ {
static volatile int initialized = 0;
struct x86_features features; struct x86_features features;
int verbose; int verbose;
if (initialized)
return;
/* FIXME: Replace all getenv calls by getenv_secure? */ /* FIXME: Replace all getenv calls by getenv_secure? */
verbose = getenv (ENV_VERBOSE) != NULL; verbose = getenv (ENV_VERBOSE) != NULL;
...@@ -169,11 +166,6 @@ fat_init (void) ...@@ -169,11 +166,6 @@ fat_init (void)
fprintf (stderr, "libnettle: intel SSE2 will not be used for memxor.\n"); fprintf (stderr, "libnettle: intel SSE2 will not be used for memxor.\n");
nettle_memxor_vec = _nettle_memxor_x86_64; nettle_memxor_vec = _nettle_memxor_x86_64;
} }
/* The x86_64 architecture should always make stores visible in the
right order to other processors (except for non-temporal stores
and the like). So we don't need any memory barrier. */
initialized = 1;
} }
DEFINE_FAT_FUNC(_nettle_aes_encrypt, void, DEFINE_FAT_FUNC(_nettle_aes_encrypt, void,
......
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