x86: libatomic: Do not assume ELF constructors run before IFUNC resolvers
authorFlorian Weimer <fweimer@redhat.com>
Wed, 23 May 2018 11:13:05 +0000 (13:13 +0200)
committerFlorian Weimer <fw@gcc.gnu.org>
Wed, 23 May 2018 11:13:05 +0000 (13:13 +0200)
PR libgcc/60790
x86: Do not assume ELF constructors run before IFUNC resolvers.
* config/x86/host-config.h (libat_feat1_ecx, libat_feat1_edx):
Remove declarations.
(__libat_feat1, __libat_feat1_init): Declare.
(FEAT1_REGISTER): Define.
(load_feat1): New function.
(IFUNC_COND_1): Adjust.
* config/x86/init.c (libat_feat1_ecx, libat_feat1_edx)
(init_cpuid): Remove definitions.
(__libat_feat1): New variable.
(__libat_feat1_init): New function.

From-SVN: r260603

libatomic/ChangeLog
libatomic/config/x86/host-config.h
libatomic/config/x86/init.c

index 82a2e040c6b04c07ef322854d707b136f004f9d6..dcb1bae089a6818d1ac35c73ef244cc6dc5e52a7 100644 (file)
@@ -1,3 +1,18 @@
+2018-05-23  Florian Weimer  <fweimer@redhat.com>
+
+       PR libgcc/60790
+       x86: Do not assume ELF constructors run before IFUNC resolvers.
+       * config/x86/host-config.h (libat_feat1_ecx, libat_feat1_edx):
+       Remove declarations.
+       (__libat_feat1, __libat_feat1_init): Declare.
+       (FEAT1_REGISTER): Define.
+       (load_feat1): New function.
+       (IFUNC_COND_1): Adjust.
+       * config/x86/init.c (libat_feat1_ecx, libat_feat1_edx)
+       (init_cpuid): Remove definitions.
+       (__libat_feat1): New variable.
+       (__libat_feat1_init): New function.
+
 2018-05-02  Tom de Vries  <tom@codesourcery.com>
 
        PR testsuite/85106
index 4a9ab4a6d94878a12fda8af27419e413dc6c4c0c..0b6c33862ec12c7947be041a49b8137f15631c78 100644 (file)
 #if HAVE_IFUNC
 #include <cpuid.h>
 
-extern unsigned int libat_feat1_ecx HIDDEN;
-extern unsigned int libat_feat1_edx HIDDEN;
+#ifdef __x86_64__
+# define FEAT1_REGISTER ecx
+#else
+# define FEAT1_REGISTER edx
+#endif
+
+/* Value of the CPUID feature register FEAT1_REGISTER for the cmpxchg
+   bit for IFUNC_COND1 below.  */
+extern unsigned int __libat_feat1 HIDDEN;
+
+/* Initialize libat_feat1 and return its value.  */
+unsigned int __libat_feat1_init (void) HIDDEN;
+
+/* Return the value of the relevant feature register for the relevant
+   cmpxchg bit, or 0 if there is no CPUID support.  */
+static inline unsigned int
+__attribute__ ((const))
+load_feat1 (void)
+{
+  /* See the store in __libat_feat1_init.  */
+  unsigned int feat1 = __atomic_load_n (&__libat_feat1, __ATOMIC_RELAXED);
+  if (feat1 == 0)
+    /* Assume that initialization has not happened yet.  This may get
+       called repeatedly if the CPU does not have any feature bits at
+       all.  */
+    feat1 = __libat_feat1_init ();
+  return feat1;
+}
 
 #ifdef __x86_64__
-# define IFUNC_COND_1  (libat_feat1_ecx & bit_CMPXCHG16B)
+# define IFUNC_COND_1  (load_feat1 () & bit_CMPXCHG16B)
 #else
-# define IFUNC_COND_1  (libat_feat1_edx & bit_CMPXCHG8B)
+# define IFUNC_COND_1  (load_feat1 () & bit_CMPXCHG8B)
 #endif
 
 #ifdef __x86_64__
index 8b9ccd3b3de38dcd4d4bdc889f256b41df70e7d3..5a4cf8b04567bf533a7e8c22b780c3f6f13901ad 100644 (file)
 
 #if HAVE_IFUNC
 
-unsigned int libat_feat1_ecx, libat_feat1_edx;
+unsigned int __libat_feat1;
 
-static void __attribute__((constructor))
-init_cpuid (void)
+unsigned int
+__libat_feat1_init (void)
 {
-  unsigned int eax, ebx;
-  __get_cpuid (1, &eax, &ebx, &libat_feat1_ecx, &libat_feat1_edx);
+  unsigned int eax, ebx, ecx, edx;
+  FEAT1_REGISTER = 0;
+  __get_cpuid (1, &eax, &ebx, &ecx, &edx);
+  /* See the load in load_feat1.  */
+  __atomic_store_n (&__libat_feat1, FEAT1_REGISTER, __ATOMIC_RELAXED);
+  return FEAT1_REGISTER;
 }
 
 #endif /* HAVE_IFUNC */