summaryrefslogtreecommitdiff
path: root/libatomic
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2018-05-23 13:13:05 +0200
committerFlorian Weimer <fw@gcc.gnu.org>2018-05-23 13:13:05 +0200
commitcb3c90cc4253cc236a4d5669a893562b202570e5 (patch)
treef949dbb7958ca1eeed9204b05d8ea39418b7ac22 /libatomic
parent159440699bf6f97dccc94377d9d69e540a1904dc (diff)
x86: libatomic: Do not assume ELF constructors run before IFUNC resolvers
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
Diffstat (limited to 'libatomic')
-rw-r--r--libatomic/ChangeLog15
-rw-r--r--libatomic/config/x86/host-config.h34
-rw-r--r--libatomic/config/x86/init.c14
3 files changed, 54 insertions, 9 deletions
diff --git a/libatomic/ChangeLog b/libatomic/ChangeLog
index 82a2e040c6b..dcb1bae089a 100644
--- a/libatomic/ChangeLog
+++ b/libatomic/ChangeLog
@@ -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
diff --git a/libatomic/config/x86/host-config.h b/libatomic/config/x86/host-config.h
index 4a9ab4a6d94..0b6c33862ec 100644
--- a/libatomic/config/x86/host-config.h
+++ b/libatomic/config/x86/host-config.h
@@ -25,13 +25,39 @@
#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__
diff --git a/libatomic/config/x86/init.c b/libatomic/config/x86/init.c
index 8b9ccd3b3de..5a4cf8b0456 100644
--- a/libatomic/config/x86/init.c
+++ b/libatomic/config/x86/init.c
@@ -26,13 +26,17 @@
#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 */