aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog27
-rw-r--r--csu/libc-start.c11
-rw-r--r--elf/rtld.c4
-rw-r--r--sysdeps/generic/libc-start.h30
-rw-r--r--sysdeps/powerpc/Makefile10
-rw-r--r--sysdeps/powerpc/powerpc64le/Makefile10
-rw-r--r--sysdeps/powerpc/tst-tlsifunc-static.c19
-rw-r--r--sysdeps/powerpc/tst-tlsifunc.c129
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/libc-start.h29
9 files changed, 265 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 1195de4..baf8543 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2017-07-17 Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
+
+ [BZ #21707]
+ * csu/libc-start.c (LIBC_START_MAIN): Perform IREL{,A}
+ relocations before or after initializing the TCB on statically
+ linked executables. That's a per-architecture definition.
+ * elf/rtld.c (dl_main): Add a comment about thread-local
+ variables initialization.
+ * sysdeps/generic/libc-start.h: New file. Define
+ ARCH_APPLY_IREL and ARCH_SETUP_IREL.
+ * sysdeps/powerpc/Makefile:
+ [$(subdir) = elf && $(multi-arch) != no] (tests-static-internal): Add
+ tst-tlsifunc-static.
+ [$(subdir) = elf && $(multi-arch) != no && $(build-shared) == yes]
+ (tests-internal): Add tst-tlsifunc.
+ * sysdeps/powerpc/tst-tlsifunc.c: New file.
+ * sysdeps/powerpc/tst-tlsifunc-static.c: Likewise.
+ * sysdeps/powerpc/powerpc64le/Makefile (f128-loader-link): New
+ variable.
+ [$(subdir) = math] (test-float128% test-ifloat128%): Force
+ linking to the loader after linking to libgcc.
+ [$(subdir) = wcsmbs || $(subdir) = stdlib] (bug-strtod bug-strtod2)
+ (bug-strtod2 tst-strtod-round tst-wcstod-round tst-strtod6 tst-strrom)
+ (tst-strfrom-locale strfrom-skeleton): Likewise.
+ * sysdeps/unix/sysv/linux/powerpc/libc-start.h: New file. Define
+ ARCH_APPLY_IREL and ARCH_SETUP_IREL.
+
2017-07-17 DJ Delorie <dj@redhat.com>
* nss/nss_test.h: New.
diff --git a/csu/libc-start.c b/csu/libc-start.c
index c2dd159..6720617 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -108,6 +108,8 @@ apply_irel (void)
# define ARCH_INIT_CPU_FEATURES()
#endif
+#include <libc-start.h>
+
STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
MAIN_AUXVEC_DECL),
int argc,
@@ -189,11 +191,16 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
ARCH_INIT_CPU_FEATURES ();
/* Perform IREL{,A} relocations. */
- apply_irel ();
+ ARCH_SETUP_IREL ();
/* The stack guard goes into the TCB, so initialize it early. */
__libc_setup_tls ();
+ /* In some architectures, IREL{,A} relocations happen after TLS setup in
+ order to let IFUNC resolvers benefit from TCB information, e.g. powerpc's
+ hwcap and platform fields available in the TCB. */
+ ARCH_APPLY_IREL ();
+
/* Set up the stack checker's canary. */
uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
# ifdef THREAD_SET_STACK_GUARD
@@ -224,7 +231,7 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
__pointer_chk_guard_local = pointer_chk_guard;
# endif
-#endif
+#endif /* !SHARED */
/* Register the destructor of the dynamic linker if there is any. */
if (__glibc_likely (rtld_fini != NULL))
diff --git a/elf/rtld.c b/elf/rtld.c
index 65647fb..1772f89 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2208,7 +2208,9 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
/* Now that we have completed relocation, the initializer data
for the TLS blocks has its final values and we can copy them
- into the main thread's TLS area, which we allocated above. */
+ into the main thread's TLS area, which we allocated above.
+ Note: thread-local variables must only be accessed after completing
+ the next step. */
_dl_allocate_tls_init (tcbp);
/* And finally install it for the main thread. */
diff --git a/sysdeps/generic/libc-start.h b/sysdeps/generic/libc-start.h
new file mode 100644
index 0000000..1bbd962
--- /dev/null
+++ b/sysdeps/generic/libc-start.h
@@ -0,0 +1,30 @@
+/* Generic definitions for libc main startup.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LIBC_START_H
+#define _LIBC_START_H
+
+#ifndef SHARED
+/* By default we perform STT_GNU_IFUNC resolution *before* TLS
+ initialization, and this means you cannot, without machine
+ knowledge, access TLS from an IFUNC resolver. */
+#define ARCH_SETUP_IREL() apply_irel ()
+#define ARCH_APPLY_IREL()
+#endif /* ! SHARED */
+
+#endif /* _LIBC_START_H */
diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
index e03a202..0d9206b 100644
--- a/sysdeps/powerpc/Makefile
+++ b/sysdeps/powerpc/Makefile
@@ -11,7 +11,15 @@ sysdep-rtld-routines += dl-machine hwcapinfo
# Don't optimize GD tls sequence to LE.
LDFLAGS-tst-tlsopt-powerpc += -Wl,--no-tls-optimize
tests += tst-tlsopt-powerpc
-endif
+
+ifneq (no,$(multi-arch))
+tests-static += tst-tlsifunc-static
+tests-internal += tst-tlsifunc-static
+ifeq (yes,$(build-shared))
+tests-internal += tst-tlsifunc
+endif # build-shared
+endif # multi-arch
+endif # subdir = elf
ifeq ($(subdir),setjmp)
ifeq (yes,$(build-shared))
diff --git a/sysdeps/powerpc/powerpc64le/Makefile b/sysdeps/powerpc/powerpc64le/Makefile
index 2c34f38..77617b6 100644
--- a/sysdeps/powerpc/powerpc64le/Makefile
+++ b/sysdeps/powerpc/powerpc64le/Makefile
@@ -1,6 +1,11 @@
# When building float128 we need to ensure -mfloat128 is
# passed to all such object files.
+# libgcc requires __tcb_parse_hwcap_and_convert_at_platform when built with
+# a binary128 type. That symbol is provided by the loader on dynamically
+# linked executables, forcing to link the loader after libgcc link.
+f128-loader-link = $(as-needed) $(elf-objpfx)ld.so $(no-as-needed)
+
ifeq ($(subdir),math)
# sqrtf128 requires emulation before POWER9.
CPPFLAGS += -I../soft-fp
@@ -11,6 +16,8 @@ $(foreach suf,$(all-object-suffixes),%f128_r$(suf)): CFLAGS += -mfloat128
$(foreach suf,$(all-object-suffixes),$(objpfx)test-float128%$(suf)): CFLAGS += -mfloat128
$(foreach suf,$(all-object-suffixes),$(objpfx)test-ifloat128%$(suf)): CFLAGS += -mfloat128
CFLAGS-libm-test-support-float128.c += -mfloat128
+$(objpfx)test-float128% $(objpfx)test-ifloat128%: \
+ gnulib-tests += $(f128-loader-link)
endif
# Append flags to string <-> _Float128 routines.
@@ -28,6 +35,9 @@ CFLAGS-tst-strtod6.c += -mfloat128
CFLAGS-tst-strfrom.c += -mfloat128
CFLAGS-tst-strfrom-locale.c += -mfloat128
CFLAGS-strfrom-skeleton.c += -mfloat128
+$(foreach test,bug-strtod bug-strtod2 bug-strtod2 tst-strtod-round \
+tst-wcstod-round tst-strtod6 tst-strrom tst-strfrom-locale \
+strfrom-skeleton,$(objpfx)$(test)): gnulib-tests += $(f128-loader-link)
# When building glibc with support for _Float128, the powers of ten tables in
# fpioconst.c and in the string conversion functions must be extended. Some
diff --git a/sysdeps/powerpc/tst-tlsifunc-static.c b/sysdeps/powerpc/tst-tlsifunc-static.c
new file mode 100644
index 0000000..e5313af
--- /dev/null
+++ b/sysdeps/powerpc/tst-tlsifunc-static.c
@@ -0,0 +1,19 @@
+/* Test if an executable can read from the TLS from an STT_GNU_IFUNC resolver.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "tst-tlsifunc.c"
diff --git a/sysdeps/powerpc/tst-tlsifunc.c b/sysdeps/powerpc/tst-tlsifunc.c
new file mode 100644
index 0000000..0a8bdbf
--- /dev/null
+++ b/sysdeps/powerpc/tst-tlsifunc.c
@@ -0,0 +1,129 @@
+/* Test if an executable can read from the TLS from an STT_GNU_IFUNC resolver.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <libc-symbols.h>
+#include <tls-macros.h>
+
+__thread int bar;
+static int *bar_ptr = NULL;
+
+static uint32_t resolver_platform = 0;
+
+int foo (void);
+
+int tcb_test (void);
+
+/* Offsets copied from tcb-offsets.h. */
+#ifdef __powerpc64__
+# define __TPREG "r13"
+# define __ATPLATOFF -28764
+#else
+# define __TPREG "r2"
+# define __ATPLATOFF -28724
+#endif
+
+uint32_t
+get_platform (void)
+{
+ register unsigned long tp __asm__ (__TPREG);
+ uint32_t tmp;
+
+ __asm__ ("lwz %0,%1(%2)\n"
+ : "=r" (tmp)
+ : "i" (__ATPLATOFF), "b" (tp));
+
+ return tmp;
+}
+
+void
+init_foo (void)
+{
+ bar_ptr = TLS_GD (bar);
+}
+
+int
+my_foo (void)
+{
+ printf ("&bar = %p and bar_ptr = %p.\n", &bar, bar_ptr);
+ return bar_ptr != NULL;
+}
+
+__ifunc (foo, foo, my_foo, void, init_foo);
+
+void
+init_tcb_test (void)
+{
+ resolver_platform = get_platform ();
+}
+
+int
+my_tcb_test (void)
+{
+ printf ("resolver_platform = 0x%"PRIx32
+ " and current platform = 0x%"PRIx32".\n",
+ resolver_platform, get_platform ());
+ return resolver_platform != 0;
+}
+
+__ifunc (tcb_test, tcb_test, my_tcb_test, void, init_tcb_test);
+
+static int
+do_test (void)
+{
+ int ret = 0;
+
+ if (foo ())
+ printf ("PASS: foo IFUNC resolver called once.\n");
+ else
+ {
+ printf ("FAIL: foo IFUNC resolver not called once.\n");
+ ret = 1;
+ }
+
+ if (&bar == bar_ptr)
+ printf ("PASS: bar address read from IFUNC resolver is correct.\n");
+ else
+ {
+ printf ("FAIL: bar address read from IFUNC resolver is incorrect.\n");
+ ret = 1;
+ }
+
+ if (tcb_test ())
+ printf ("PASS: tcb_test IFUNC resolver called once.\n");
+ else
+ {
+ printf ("FAIL: tcb_test IFUNC resolver not called once.\n");
+ ret = 1;
+ }
+
+ if (resolver_platform == get_platform ())
+ printf ("PASS: platform read from IFUNC resolver is correct.\n");
+ else
+ {
+ printf ("FAIL: platform read from IFUNC resolver is incorrect.\n");
+ ret = 1;
+ }
+
+ return ret;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/powerpc/libc-start.h b/sysdeps/unix/sysv/linux/powerpc/libc-start.h
new file mode 100644
index 0000000..c0635be
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/powerpc/libc-start.h
@@ -0,0 +1,29 @@
+/* PowerPC definitions for libc main startup.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _LIBC_START_H
+#define _LIBC_START_H
+
+#ifndef SHARED
+/* IREL{,A} must happen after TCB initialization in order to allow IFUNC
+ resolvers to read TCB fields, e.g. hwcap and at_platform. */
+#define ARCH_SETUP_IREL()
+#define ARCH_APPLY_IREL() apply_irel ()
+#endif /* ! SHARED */
+
+#endif /* _LIBC_START_H */