aboutsummaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2016-11-30 15:59:57 +0100
committerFlorian Weimer <fweimer@redhat.com>2016-11-30 15:59:57 +0100
commit9e78f6f6e7134a5f299cc8de77370218f8019237 (patch)
tree04aa339daf9901b8fc1851353c697528659e7afe /elf
parent705a79f82560ff6472cebed86aa5db04cdea3bce (diff)
downloadglibc-9e78f6f6e7134a5f299cc8de77370218f8019237.tar
glibc-9e78f6f6e7134a5f299cc8de77370218f8019237.tar.gz
glibc-9e78f6f6e7134a5f299cc8de77370218f8019237.tar.bz2
glibc-9e78f6f6e7134a5f299cc8de77370218f8019237.zip
Implement _dl_catch_error, _dl_signal_error in libc.so [BZ #16628]
This change moves the main implementation of _dl_catch_error, _dl_signal_error to libc.so, where TLS variables can be used directly. This removes a writable function pointer from the rtld_global variable. For use during initial relocation, minimal implementations of these functions are provided in ld.so. These are eventually interposed by the libc.so implementations. This is implemented by compiling elf/dl-error-skeleton.c twice, via elf/dl-error.c and elf/dl-error-minimal.c. As a side effect of this change, the static version of dl-error.c no longer includes support for the _dl_signal_cerror/_dl_receive_error mechanism because it is only used in ld.so.
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile21
-rw-r--r--elf/Versions6
-rw-r--r--elf/dl-close.c2
-rw-r--r--elf/dl-error-minimal.c23
-rw-r--r--elf/dl-error-skeleton.c230
-rw-r--r--elf/dl-error.c210
-rw-r--r--elf/dl-libc.c4
-rw-r--r--elf/dl-sym.c8
-rw-r--r--elf/dl-tsd.c53
-rw-r--r--elf/rtld.c19
-rw-r--r--elf/tst-latepthread.c105
-rw-r--r--elf/tst-latepthreadmod.c33
12 files changed, 428 insertions, 286 deletions
diff --git a/elf/Makefile b/elf/Makefile
index 82c7e0559d..33b003b170 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -24,12 +24,12 @@ include ../Makeconfig
headers = elf.h bits/elfclass.h link.h bits/link.h
routines = $(all-dl-routines) dl-support dl-iteratephdr \
dl-addr dl-addr-obj enbl-secure dl-profstub \
- dl-origin dl-libc dl-sym dl-tsd dl-sysdep
+ dl-origin dl-libc dl-sym dl-sysdep dl-error
# The core dynamic linking functions are in libc for the static and
# profiled libraries.
dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \
- runtime error init fini debug misc \
+ runtime init fini debug misc \
version profile conflict tls origin scope \
execstack caller open close trampoline)
ifeq (yes,$(use-ldconfig))
@@ -43,7 +43,8 @@ shared-only-routines += dl-caller
# ld.so uses those routines, plus some special stuff for being the program
# interpreter and operating independent of libc.
-rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal
+rtld-routines = rtld $(all-dl-routines) dl-sysdep dl-environ dl-minimal \
+ dl-error-minimal
all-rtld-routines = $(rtld-routines) $(sysdep-rtld-routines)
CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
@@ -150,7 +151,8 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
tst-nodelete) \
tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
tst-ptrguard1 tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \
- tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload
+ tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error tst-noload \
+ tst-latepthread
# reldep9
ifeq ($(build-hardcoded-path-in-tests),yes)
tests += tst-dlopen-aout
@@ -224,7 +226,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
tst-array5dep tst-null-argv-lib \
tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \
tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \
- tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12
+ tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \
+ tst-latepthreadmod
ifeq (yes,$(have-mtls-dialect-gnu2))
tests += tst-gnu2-tls1
modules-names += tst-gnu2-tls1mod
@@ -1264,6 +1267,14 @@ tst-audit12-ENV = LD_AUDIT=$(objpfx)tst-auditmod12.so
$(objpfx)tst-audit12mod1.so: $(objpfx)tst-audit12mod2.so
LDFLAGS-tst-audit12mod2.so = -Wl,--version-script=tst-audit12mod2.map
+# Override -z defs, so that we can reference an undefined symbol.
+# Force lazy binding for the same reason.
+LDFLAGS-tst-latepthreadmod.so = \
+ -Wl,-z,lazy -Wl,--unresolved-symbols=ignore-all
+$(objpfx)tst-latepthreadmod.so: $(shared-thread-library)
+$(objpfx)tst-latepthread: $(libdl)
+$(objpfx)tst-latepthread.out: $(objpfx)tst-latepthreadmod.so
+
tst-prelink-ENV = LD_TRACE_PRELINKING=1
$(objpfx)tst-prelink-conflict.out: $(objpfx)tst-prelink.out
diff --git a/elf/Versions b/elf/Versions
index 23deda984f..05e5449f4d 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -26,6 +26,9 @@ libc {
_dl_open_hook;
_dl_sym; _dl_vsym;
__libc_dlclose; __libc_dlopen_mode; __libc_dlsym;
+
+ # Internal error handling support. Interposes the functions in ld.so.
+ _dl_signal_error; _dl_catch_error;
}
}
@@ -64,5 +67,8 @@ ld {
# Pointer protection.
__pointer_chk_guard;
+
+ # Internal error handling support. Interposed by libc.so.
+ _dl_signal_error; _dl_catch_error;
}
}
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 687d7de874..648970332e 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -814,7 +814,7 @@ _dl_close (void *_map)
}
if (__builtin_expect (map->l_direct_opencount, 1) == 0)
- GLRO(dl_signal_error) (0, map->l_name, NULL, N_("shared object not open"));
+ _dl_signal_error (0, map->l_name, NULL, N_("shared object not open"));
/* Acquire the lock. */
__rtld_lock_lock_recursive (GL(dl_load_lock));
diff --git a/elf/dl-error-minimal.c b/elf/dl-error-minimal.c
new file mode 100644
index 0000000000..d535d65877
--- /dev/null
+++ b/elf/dl-error-minimal.c
@@ -0,0 +1,23 @@
+/* Error handling for runtime dynamic linker, minimal version.
+ Copyright (C) 1995-2016 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/>. */
+
+/* This version does lives in ld.so, does not use thread-local data
+ and supports _dl_signal_cerror and _dl_receive_error. */
+
+#define DL_ERROR_BOOTSTRAP 1
+#include "dl-error-skeleton.c"
diff --git a/elf/dl-error-skeleton.c b/elf/dl-error-skeleton.c
new file mode 100644
index 0000000000..beb31ae393
--- /dev/null
+++ b/elf/dl-error-skeleton.c
@@ -0,0 +1,230 @@
+/* Template for error handling for runtime dynamic linker.
+ Copyright (C) 1995-2016 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/>. */
+
+/* The following macro needs to be defined before including this
+ skeleton file:
+
+ DL_ERROR_BOOTSTRAP
+
+ If 1, do not use TLS and implement _dl_signal_cerror and
+ _dl_receive_error. If 0, TLS is used, and the variants with
+ error callbacks are not provided. */
+
+
+#include <libintl.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <stdio.h>
+
+/* This structure communicates state between _dl_catch_error and
+ _dl_signal_error. */
+struct catch
+ {
+ const char **objname; /* Object/File name. */
+ const char **errstring; /* Error detail filled in here. */
+ bool *malloced; /* Nonzero if the string is malloced
+ by the libc malloc. */
+ volatile int *errcode; /* Return value of _dl_signal_error. */
+ jmp_buf env; /* longjmp here on error. */
+ };
+
+/* Multiple threads at once can use the `_dl_catch_error' function. The
+ calls can come from `_dl_map_object_deps', `_dlerror_run', or from
+ any of the libc functionality which loads dynamic objects (NSS, iconv).
+ Therefore we have to be prepared to save the state in thread-local
+ memory. */
+#if !DL_ERROR_BOOTSTRAP
+static __thread struct catch *catch_hook attribute_tls_model_ie;
+#else
+/* The version of this code in ld.so cannot use thread-local variables
+ and is used during bootstrap only. */
+static struct catch *catch_hook;
+#endif
+
+/* This message we return as a last resort. We define the string in a
+ variable since we have to avoid freeing it and so have to enable
+ a pointer comparison. See below and in dlfcn/dlerror.c. */
+static const char _dl_out_of_memory[] = "out of memory";
+
+#if DL_ERROR_BOOTSTRAP
+/* This points to a function which is called when an continuable error is
+ received. Unlike the handling of `catch' this function may return.
+ The arguments will be the `errstring' and `objname'.
+
+ Since this functionality is not used in normal programs (only in ld.so)
+ we do not care about multi-threaded programs here. We keep this as a
+ global variable. */
+static receiver_fct receiver;
+#endif /* DL_ERROR_BOOTSTRAP */
+
+void
+internal_function
+_dl_signal_error (int errcode, const char *objname, const char *occation,
+ const char *errstring)
+{
+ struct catch *lcatch = catch_hook;
+
+ if (! errstring)
+ errstring = N_("DYNAMIC LINKER BUG!!!");
+
+ if (objname == NULL)
+ objname = "";
+ if (lcatch != NULL)
+ {
+ /* We are inside _dl_catch_error. Return to it. We have to
+ duplicate the error string since it might be allocated on the
+ stack. The object name is always a string constant. */
+ size_t len_objname = strlen (objname) + 1;
+ size_t len_errstring = strlen (errstring) + 1;
+
+ char *errstring_copy = malloc (len_objname + len_errstring);
+ if (errstring_copy != NULL)
+ {
+ /* Make a copy of the object file name and the error string. */
+ *lcatch->objname = memcpy (__mempcpy (errstring_copy,
+ errstring, len_errstring),
+ objname, len_objname);
+ *lcatch->errstring = errstring_copy;
+
+ /* If the main executable is relocated it means the libc's malloc
+ is used. */
+ bool malloced = true;
+#ifdef SHARED
+ malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
+ && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0));
+#endif
+ *lcatch->malloced = malloced;
+ }
+ else
+ {
+ /* This is better than nothing. */
+ *lcatch->objname = "";
+ *lcatch->errstring = _dl_out_of_memory;
+ *lcatch->malloced = false;
+ }
+
+ *lcatch->errcode = errcode;
+
+ /* We do not restore the signal mask because none was saved. */
+ __longjmp (lcatch->env[0].__jmpbuf, 1);
+ }
+ else
+ {
+ /* Lossage while resolving the program's own symbols is always fatal. */
+ char buffer[1024];
+ _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n",
+ RTLD_PROGNAME,
+ occation ?: N_("error while loading shared libraries"),
+ objname, *objname ? ": " : "",
+ errstring, errcode ? ": " : "",
+ (errcode
+ ? __strerror_r (errcode, buffer, sizeof buffer)
+ : ""));
+ }
+}
+libc_hidden_def (_dl_signal_error)
+
+
+#if DL_ERROR_BOOTSTRAP
+void
+internal_function
+_dl_signal_cerror (int errcode, const char *objname, const char *occation,
+ const char *errstring)
+{
+ if (__builtin_expect (GLRO(dl_debug_mask)
+ & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
+ _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation,
+ errstring, receiver ? "continued" : "fatal");
+
+ if (receiver)
+ {
+ /* We are inside _dl_receive_error. Call the user supplied
+ handler and resume the work. The receiver will still be
+ installed. */
+ (*receiver) (errcode, objname, errstring);
+ }
+ else
+ _dl_signal_error (errcode, objname, occation, errstring);
+}
+#endif /* DL_ERROR_BOOTSTRAP */
+
+
+int
+internal_function
+_dl_catch_error (const char **objname, const char **errstring,
+ bool *mallocedp, void (*operate) (void *), void *args)
+{
+ /* We need not handle `receiver' since setting a `catch' is handled
+ before it. */
+
+ /* Only this needs to be marked volatile, because it is the only local
+ variable that gets changed between the setjmp invocation and the
+ longjmp call. All others are just set here (before setjmp) and read
+ in _dl_signal_error (before longjmp). */
+ volatile int errcode;
+
+ struct catch c;
+ /* Don't use an initializer since we don't need to clear C.env. */
+ c.objname = objname;
+ c.errstring = errstring;
+ c.malloced = mallocedp;
+ c.errcode = &errcode;
+
+ struct catch *const old = catch_hook;
+ catch_hook = &c;
+
+ /* Do not save the signal mask. */
+ if (__builtin_expect (__sigsetjmp (c.env, 0), 0) == 0)
+ {
+ (*operate) (args);
+ catch_hook = old;
+ *objname = NULL;
+ *errstring = NULL;
+ *mallocedp = false;
+ return 0;
+ }
+
+ /* We get here only if we longjmp'd out of OPERATE. _dl_signal_error has
+ already stored values into *OBJNAME, *ERRSTRING, and *MALLOCEDP. */
+ catch_hook = old;
+ return errcode;
+}
+libc_hidden_def (_dl_catch_error)
+
+#if DL_ERROR_BOOTSTRAP
+void
+internal_function
+_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args)
+{
+ struct catch *old_catch = catch_hook;
+ receiver_fct old_receiver = receiver;
+
+ /* Set the new values. */
+ catch_hook = NULL;
+ receiver = fct;
+
+ (*operate) (args);
+
+ catch_hook = old_catch;
+ receiver = old_receiver;
+}
+#endif /* DL_ERROR_BOOTSTRAP */
diff --git a/elf/dl-error.c b/elf/dl-error.c
index bd22ec6cf0..7fe36b4631 100644
--- a/elf/dl-error.c
+++ b/elf/dl-error.c
@@ -1,4 +1,4 @@
-/* Error handling for runtime dynamic linker.
+/* Error handling for runtime dynamic linker, full version.
Copyright (C) 1995-2016 Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -16,206 +16,12 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-#include <libintl.h>
-#include <setjmp.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <ldsodefs.h>
+/* This implementation lives in libc.so because it uses thread-local
+ data, which is not available in ld.so. It interposes the version
+ in dl-error-minimal.c after ld.so bootstrap.
-/* This structure communicates state between _dl_catch_error and
- _dl_signal_error. */
-struct catch
- {
- const char **objname; /* Object/File name. */
- const char **errstring; /* Error detail filled in here. */
- bool *malloced; /* Nonzero if the string is malloced
- by the libc malloc. */
- volatile int *errcode; /* Return value of _dl_signal_error. */
- jmp_buf env; /* longjmp here on error. */
- };
+ The signal/catch mechanism is used by the audit framework, which
+ means that even in ld.so, not all errors are fatal. */
-/* Multiple threads at once can use the `_dl_catch_error' function. The
- calls can come from `_dl_map_object_deps', `_dlerror_run', or from
- any of the libc functionality which loads dynamic objects (NSS, iconv).
- Therefore we have to be prepared to save the state in thread-local
- memory. The _dl_error_catch_tsd function pointer is reset by the thread
- library so that it returns the address of a thread-local variable. */
-
-
-/* This message we return as a last resort. We define the string in a
- variable since we have to avoid freeing it and so have to enable
- a pointer comparison. See below and in dlfcn/dlerror.c. */
-static const char _dl_out_of_memory[] = "out of memory";
-
-
-/* This points to a function which is called when an continuable error is
- received. Unlike the handling of `catch' this function may return.
- The arguments will be the `errstring' and `objname'.
-
- Since this functionality is not used in normal programs (only in ld.so)
- we do not care about multi-threaded programs here. We keep this as a
- global variable. */
-static receiver_fct receiver;
-
-#ifdef _LIBC_REENTRANT
-# define CATCH_HOOK (*(struct catch **) (*GL(dl_error_catch_tsd)) ())
-#else
-static struct catch *catch_hook;
-# define CATCH_HOOK catch_hook
-#endif
-
-void
-internal_function
-_dl_signal_error (int errcode, const char *objname, const char *occation,
- const char *errstring)
-{
- struct catch *lcatch;
-
- if (! errstring)
- errstring = N_("DYNAMIC LINKER BUG!!!");
-
- lcatch = CATCH_HOOK;
- if (objname == NULL)
- objname = "";
- if (lcatch != NULL)
- {
- /* We are inside _dl_catch_error. Return to it. We have to
- duplicate the error string since it might be allocated on the
- stack. The object name is always a string constant. */
- size_t len_objname = strlen (objname) + 1;
- size_t len_errstring = strlen (errstring) + 1;
-
- char *errstring_copy = malloc (len_objname + len_errstring);
- if (errstring_copy != NULL)
- {
- /* Make a copy of the object file name and the error string. */
- *lcatch->objname = memcpy (__mempcpy (errstring_copy,
- errstring, len_errstring),
- objname, len_objname);
- *lcatch->errstring = errstring_copy;
-
- /* If the main executable is relocated it means the libc's malloc
- is used. */
- bool malloced = true;
-#ifdef SHARED
- malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
- && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0));
-#endif
- *lcatch->malloced = malloced;
- }
- else
- {
- /* This is better than nothing. */
- *lcatch->objname = "";
- *lcatch->errstring = _dl_out_of_memory;
- *lcatch->malloced = false;
- }
-
- *lcatch->errcode = errcode;
-
- /* We do not restore the signal mask because none was saved. */
- __longjmp (lcatch->env[0].__jmpbuf, 1);
- }
- else
- {
- /* Lossage while resolving the program's own symbols is always fatal. */
- char buffer[1024];
- _dl_fatal_printf ("%s: %s: %s%s%s%s%s\n",
- RTLD_PROGNAME,
- occation ?: N_("error while loading shared libraries"),
- objname, *objname ? ": " : "",
- errstring, errcode ? ": " : "",
- (errcode
- ? __strerror_r (errcode, buffer, sizeof buffer)
- : ""));
- }
-}
-
-
-void
-internal_function
-_dl_signal_cerror (int errcode, const char *objname, const char *occation,
- const char *errstring)
-{
- if (__builtin_expect (GLRO(dl_debug_mask)
- & ~(DL_DEBUG_STATISTICS|DL_DEBUG_PRELINK), 0))
- _dl_debug_printf ("%s: error: %s: %s (%s)\n", objname, occation,
- errstring, receiver ? "continued" : "fatal");
-
- if (receiver)
- {
- /* We are inside _dl_receive_error. Call the user supplied
- handler and resume the work. The receiver will still be
- installed. */
- (*receiver) (errcode, objname, errstring);
- }
- else
- _dl_signal_error (errcode, objname, occation, errstring);
-}
-
-
-int
-internal_function
-_dl_catch_error (const char **objname, const char **errstring,
- bool *mallocedp, void (*operate) (void *), void *args)
-{
- /* We need not handle `receiver' since setting a `catch' is handled
- before it. */
-
- /* Only this needs to be marked volatile, because it is the only local
- variable that gets changed between the setjmp invocation and the
- longjmp call. All others are just set here (before setjmp) and read
- in _dl_signal_error (before longjmp). */
- volatile int errcode;
-
- struct catch c;
- /* Don't use an initializer since we don't need to clear C.env. */
- c.objname = objname;
- c.errstring = errstring;
- c.malloced = mallocedp;
- c.errcode = &errcode;
-
- struct catch **const catchp = &CATCH_HOOK;
- struct catch *const old = *catchp;
- *catchp = &c;
-
- /* Do not save the signal mask. */
- if (__builtin_expect (__sigsetjmp (c.env, 0), 0) == 0)
- {
- (*operate) (args);
- *catchp = old;
- *objname = NULL;
- *errstring = NULL;
- *mallocedp = false;
- return 0;
- }
-
- /* We get here only if we longjmp'd out of OPERATE. _dl_signal_error has
- already stored values into *OBJNAME, *ERRSTRING, and *MALLOCEDP. */
- *catchp = old;
- return errcode;
-}
-
-
-void
-internal_function
-_dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args)
-{
- struct catch **const catchp = &CATCH_HOOK;
- struct catch *old_catch;
- receiver_fct old_receiver;
-
- old_catch = *catchp;
- old_receiver = receiver;
-
- /* Set the new values. */
- *catchp = NULL;
- receiver = fct;
-
- (*operate) (args);
-
- *catchp = old_catch;
- receiver = old_receiver;
-}
+#define DL_ERROR_BOOTSTRAP 0
+#include "dl-error-skeleton.c"
diff --git a/elf/dl-libc.c b/elf/dl-libc.c
index d56de1a57a..dde44c8799 100644
--- a/elf/dl-libc.c
+++ b/elf/dl-libc.c
@@ -43,8 +43,8 @@ dlerror_run (void (*operate) (void *), void *args)
const char *last_errstring = NULL;
bool malloced;
- int result = (GLRO(dl_catch_error) (&objname, &last_errstring, &malloced,
- operate, args)
+ int result = (_dl_catch_error (&objname, &last_errstring, &malloced,
+ operate, args)
?: last_errstring != NULL);
if (result && malloced)
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index 6431c22614..e00b286991 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -123,8 +123,8 @@ do_sym (void *handle, const char *name, void *who,
const char *objname;
const char *errstring = NULL;
bool malloced;
- int err = GLRO(dl_catch_error) (&objname, &errstring, &malloced,
- call_dl_lookup, &args);
+ int err = _dl_catch_error (&objname, &errstring, &malloced,
+ call_dl_lookup, &args);
THREAD_GSCOPE_RESET_FLAG ();
@@ -136,7 +136,7 @@ do_sym (void *handle, const char *name, void *who,
if (malloced)
free ((char *) errstring);
- GLRO(dl_signal_error) (err, objname_dup, NULL, errstring_dup);
+ _dl_signal_error (err, objname_dup, NULL, errstring_dup);
/* NOTREACHED */
}
@@ -150,7 +150,7 @@ do_sym (void *handle, const char *name, void *who,
if (match == NULL
|| caller < match->l_map_start
|| caller >= match->l_map_end)
- GLRO(dl_signal_error) (0, NULL, NULL, N_("\
+ _dl_signal_error (0, NULL, NULL, N_("\
RTLD_NEXT used in code not dynamically loaded"));
}
diff --git a/elf/dl-tsd.c b/elf/dl-tsd.c
deleted file mode 100644
index 7181e1c9e0..0000000000
--- a/elf/dl-tsd.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Thread-local data used by error handling for runtime dynamic linker.
- Copyright (C) 2002-2016 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/>. */
-
-#ifdef _LIBC_REENTRANT
-
-# include <ldsodefs.h>
-# include <tls.h>
-
-# ifndef SHARED
-
-/* _dl_error_catch_tsd points to this for the single-threaded case.
- It's reset by the thread library for multithreaded programs
- if we're not using __thread. */
-void ** __attribute__ ((const))
-_dl_initial_error_catch_tsd (void)
-{
- static __thread void *data;
- return &data;
-}
-void **(*_dl_error_catch_tsd) (void) __attribute__ ((const))
- = &_dl_initial_error_catch_tsd;
-
-# else
-
-/* libpthread sets _dl_error_catch_tsd to point to this function.
- We define it here instead of in libpthread so that it doesn't
- need to have a TLS segment of its own just for this one pointer. */
-
-void ** __attribute__ ((const))
-__libc_dl_error_tsd (void)
-{
- static __thread void *data attribute_tls_model_ie;
- return &data;
-}
-
-# endif /* SHARED */
-
-#endif /* _LIBC_REENTRANT */
diff --git a/elf/rtld.c b/elf/rtld.c
index 647661ca45..4ec25d7c30 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -167,8 +167,6 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
/* Function pointers. */
._dl_debug_printf = _dl_debug_printf,
- ._dl_catch_error = _dl_catch_error,
- ._dl_signal_error = _dl_signal_error,
._dl_mcount = _dl_mcount,
._dl_lookup_symbol_x = _dl_lookup_symbol_x,
._dl_check_caller = _dl_check_caller,
@@ -637,18 +635,6 @@ cannot allocate TLS data structures for initial thread");
return tcbp;
}
-#ifdef _LIBC_REENTRANT
-/* _dl_error_catch_tsd points to this for the single-threaded case.
- It's reset by the thread library for multithreaded programs. */
-void ** __attribute__ ((const))
-_dl_initial_error_catch_tsd (void)
-{
- static void *data;
- return &data;
-}
-#endif
-
-
static unsigned int
do_preload (const char *fname, struct link_map *main_map, const char *where)
{
@@ -752,11 +738,6 @@ dl_main (const ElfW(Phdr) *phdr,
#endif
void *tcbp = NULL;
-#ifdef _LIBC_REENTRANT
- /* Explicit initialization since the reloc would just be more work. */
- GL(dl_error_catch_tsd) = &_dl_initial_error_catch_tsd;
-#endif
-
GL(dl_init_static_tls) = &_dl_nothread_init_static_tls;
#if defined SHARED && defined _LIBC_REENTRANT \
diff --git a/elf/tst-latepthread.c b/elf/tst-latepthread.c
new file mode 100644
index 0000000000..9449ef6c2d
--- /dev/null
+++ b/elf/tst-latepthread.c
@@ -0,0 +1,105 @@
+/* Test that loading libpthread does not break ld.so exceptions (bug 16628).
+ Copyright (C) 2016 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 <dlfcn.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ void *handle = dlopen ("tst-latepthreadmod.so", RTLD_LOCAL | RTLD_LAZY);
+ if (handle == NULL)
+ {
+ printf ("error: dlopen failed: %s\n", dlerror ());
+ return 1;
+ }
+ void *ptr = dlsym (handle, "trigger_dynlink_failure");
+ if (ptr == NULL)
+ {
+ printf ("error: dlsym failed: %s\n", dlerror ());
+ return 1;
+ }
+ int (*func) (void) = ptr;
+
+ /* Run the actual test in a subprocess, to capture the error. */
+ int fds[2];
+ if (pipe (fds) < 0)
+ {
+ printf ("error: pipe: %m\n");
+ return 1;
+ }
+ pid_t pid = fork ();
+ if (pid < 0)
+ {
+ printf ("error: fork: %m\n");
+ return 1;
+ }
+ else if (pid == 0)
+ {
+ if (dup2 (fds[1], STDERR_FILENO) < 0)
+ _exit (2);
+ /* Trigger an abort. */
+ func ();
+ _exit (3);
+ }
+ /* NB: This assumes that the abort message is so short that the pipe
+ does not block. */
+ int status;
+ if (waitpid (pid, &status, 0) < 0)
+ {
+ printf ("error: waitpid: %m\n");
+ return 1;
+ }
+
+ /* Check the printed error message. */
+ if (close (fds[1]) < 0)
+ {
+ printf ("error: close: %m\n");
+ return 1;
+ }
+ char buf[512];
+ /* Leave room for the NUL terminator. */
+ ssize_t ret = read (fds[0], buf, sizeof (buf) - 1);
+ if (ret < 0)
+ {
+ printf ("error: read: %m\n");
+ return 1;
+ }
+ if (ret > 0 && buf[ret - 1] == '\n')
+ --ret;
+ buf[ret] = '\0';
+ printf ("info: exit status: %d, message: %s\n", status, buf);
+ if (strstr (buf, "undefined symbol: this_function_is_not_defined") == NULL)
+ {
+ printf ("error: message does not contain expected string\n");
+ return 1;
+ }
+ if (!WIFEXITED (status) || WEXITSTATUS (status) != 127)
+ {
+ printf ("error: unexpected process exit status\n");
+ return 1;
+ }
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/elf/tst-latepthreadmod.c b/elf/tst-latepthreadmod.c
new file mode 100644
index 0000000000..ce81206f2a
--- /dev/null
+++ b/elf/tst-latepthreadmod.c
@@ -0,0 +1,33 @@
+/* DSO which links against libpthread and triggers a lazy binding.
+ Copyright (C) 2016 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/>. */
+
+/* This file is compiled into a DSO which loads libpthread, but fails
+ the dynamic linker afterwards. */
+
+#include <pthread.h>
+
+/* Link in libpthread. */
+void *pthread_create_ptr = &pthread_create;
+
+int this_function_is_not_defined (void);
+
+int
+trigger_dynlink_failure (void)
+{
+ return this_function_is_not_defined ();
+}