about summary refs log tree commit diff
path: root/sysdeps/x86/dl-get-cpu-features.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2020-07-04 06:35:49 -0700
committerH.J. Lu <hjl.tools@gmail.com>2020-10-16 16:17:53 -0700
commit0f09154c64005e78b61484ae87b5ea2028051ea0 (patch)
tree81d0f0364965dad247f36131b6a9a40f56a6e9ab /sysdeps/x86/dl-get-cpu-features.c
parentd6fa3170997b4af0a702eebdae7e4d3c57d74b65 (diff)
downloadglibc-0f09154c64005e78b61484ae87b5ea2028051ea0.tar.gz
glibc-0f09154c64005e78b61484ae87b5ea2028051ea0.tar.xz
glibc-0f09154c64005e78b61484ae87b5ea2028051ea0.zip
x86: Initialize CPU info via IFUNC relocation [BZ 26203]
X86 CPU features in ld.so are initialized by init_cpu_features, which is
invoked by DL_PLATFORM_INIT from _dl_sysdep_start.  But when ld.so is
loaded by static executable, DL_PLATFORM_INIT is never called.  Also
x86 cache info in libc.o and libc.a is initialized by a constructor
which may be called too late.  Since some fields in _rtld_global_ro
in ld.so are initialized by dynamic relocation, we can also initialize
x86 CPU features in _rtld_global_ro in ld.so and cache info in libc.so
by initializing dummy function pointers in ld.so and libc.so via IFUNC
relocation.

Key points:

1. IFUNC is always supported, independent of --enable-multi-arch or
--disable-multi-arch.  Linker generates IFUNC relocations from input
IFUNC objects and ld.so performs IFUNC relocations.
2. There are no IFUNC dependencies in ld.so before dynamic relocation
have been performed,
3. The x86 CPU features in ld.so is initialized by DL_PLATFORM_INIT
in dynamic executable and by IFUNC relocation in dlopen in static
executable.
4. The x86 cache info in libc.o is initialized by IFUNC relocation.
5. In libc.a, both x86 CPU features and cache info are initialized from
ARCH_INIT_CPU_FEATURES, not by IFUNC relocation, before __libc_early_init
is called.

Note: _dl_x86_init_cpu_features can be called more than once from
DL_PLATFORM_INIT and during relocation in ld.so.
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 *