about summary refs log tree commit diff
path: root/sysdeps/x86/dl-get-cpu-features.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/x86/dl-get-cpu-features.c')
-rw-r--r--sysdeps/x86/dl-get-cpu-features.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/sysdeps/x86/dl-get-cpu-features.c b/sysdeps/x86/dl-get-cpu-features.c
index 5f9e46b0c6..349472d99f 100644
--- a/sysdeps/x86/dl-get-cpu-features.c
+++ b/sysdeps/x86/dl-get-cpu-features.c
@@ -1,4 +1,4 @@
-/* This file is part of the GNU C Library.
+/* Initialize CPU feature data via IFUNC relocation.
    Copyright (C) 2015-2020 Free Software Foundation, Inc.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -18,6 +18,31 @@
 
 #include <ldsodefs.h>
 
+#ifdef SHARED
+# include <cpu-features.c>
+
+/* NB: Normally, DL_PLATFORM_INIT calls init_cpu_features to initialize
+   CPU features in dynamic executable.  But when loading ld.so inside of
+   static executable, DL_PLATFORM_INIT isn't called and IFUNC relocation
+   is used to call init_cpu_features.  In static executable, it is called
+   once by IFUNC relocation.  In dynamic executable, it is called twice
+   by DL_PLATFORM_INIT and by IFUNC relocation.  */
+extern void __x86_cpu_features (void) attribute_hidden;
+const void (*__x86_cpu_features_p) (void) attribute_hidden
+  = __x86_cpu_features;
+
+void
+_dl_x86_init_cpu_features (void)
+{
+  struct cpu_features *cpu_features = __get_cpu_features ();
+  if (cpu_features->basic.kind == arch_kind_unknown)
+    init_cpu_features (cpu_features);
+}
+
+__ifunc (__x86_cpu_features, __x86_cpu_features, NULL, void,
+	 _dl_x86_init_cpu_features);
+#endif
+
 #undef __x86_get_cpu_features
 
 const struct cpu_features *