diff options
author | Ulrich Drepper <drepper@redhat.com> | 1998-09-06 09:16:53 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 1998-09-06 09:16:53 +0000 |
commit | be93561004695198611aa8707f10250f780988b2 (patch) | |
tree | 7b9a502d849b761d966114b855a1fa9de4022e90 /elf/dl-error.c | |
parent | 9eb71e60ef889158238c3066c75b65336d846684 (diff) | |
download | glibc-be93561004695198611aa8707f10250f780988b2.tar glibc-be93561004695198611aa8707f10250f780988b2.tar.gz glibc-be93561004695198611aa8707f10250f780988b2.tar.bz2 glibc-be93561004695198611aa8707f10250f780988b2.zip |
Update.
1998-09-06 09:00 Ulrich Drepper <drepper@cygnus.com>
* version.h (VERSION): Bump to 2.0.96.
Rewrite runtime linker to be truly thread-safe. There is now no
global variable specifying the scope. We create all needed
scopes at the time the link maps are created.
* elf/Versions [GLIBC_2.1]: Add _dl_loaded and _dl_main_searchlist.
* elf/link.h: Add struct r_scope_elem and use this for l_searchlist,
l_symbolic_searchlist, l_scope, and l_local_scope elements in
struct link_map.
* elf/dl-close.c: Rewritten accordingly.
* elf/dl-deps.c: Likewise.
* elf/dl-error.c: Likewise.
* elf/dl-init.c: Likewise.
* elf/dl-load.c: Likewise.
* elf/dl-lookup.c: Likewise.
* elf/dl-object.c: Likewise.
* elf/dl-open.c: Likewise.
* elf/dl-reloc.c: Likewise.
* elf/dl-runtime.c: Likewise.
* elf/dl-support.c: Likewise.
* elf/dl-symbol.c: Likewise.
* elf/dl-version.c: Likewise.
* elf/dlfcn.h: Likewise.
* elf/dlsym.c: Likewise.
* elf/dlvsym.c: Likewise.
* elf/ldsodefs.h: Likewise.
* elf/rtld.c: Likewise.
* iconv/gconv_dl.c: Likewise.
* nss/nsswitch.c: Likewise.
* sysdeps/i386/dl-machine.h: Likewise.
* sysdeps/unix/sysv/linux/i386/dl-librecon.h: Likewise.
Diffstat (limited to 'elf/dl-error.c')
-rw-r--r-- | elf/dl-error.c | 83 |
1 files changed, 65 insertions, 18 deletions
diff --git a/elf/dl-error.c b/elf/dl-error.c index 03292abaf4..cfb6b9ead5 100644 --- a/elf/dl-error.c +++ b/elf/dl-error.c @@ -22,6 +22,7 @@ #include <string.h> #include <unistd.h> #include <elf/ldsodefs.h> +#include <bits/libc-lock.h> /* This structure communicates state between _dl_catch_error and _dl_signal_error. */ @@ -31,14 +32,57 @@ struct catch jmp_buf env; /* longjmp here on error. */ }; -/* This points to such a structure during a call to _dl_catch_error. - During implicit startup and run-time work for needed shared libraries, - this is null. */ +/* Multiple threads at once can use the `_dl_catch_error' function. The + calls can come from the `_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 safe the state in thread-local + memory. `catch' will only be used for the non-threaded case. + + Please note the horrible kludge we have to use to check for the + thread functions to be defined. The problem is that while running + ld.so standalone (i.e., before the relocation with the libc symbols + available) we do not have a real handling of undefined weak symbols. + All symbols are relocated, regardless of the availability. They are + relocated relative to the load address of the dynamic linker. Adding + this start address to zero (the value in the GOT for undefined symbols) + leads to an address which is the load address of ld.so. Once we have + relocated with the libc values the value is NULL if the function is + not available. Our "solution" is to regard NULL and the ld.so load + address as indicators for unavailable weak symbols. */ static struct catch *catch; +#ifdef PIC +# define tsd_setspecific(data) \ + if (__libc_internal_tsd_set != (void *) _dl_rtld_map.l_addr \ + && __libc_internal_tsd_set != NULL) \ + __libc_internal_tsd_set (_LIBC_TSD_KEY_DL_ERROR, data); \ + else \ + catch = (data) +# define tsd_getspecific() \ + (__libc_internal_tsd_set != (void *) _dl_rtld_map.l_addr \ + && __libc_internal_tsd_set != NULL \ + ? (struct catch *) __libc_internal_tsd_get (_LIBC_TSD_KEY_DL_ERROR) \ + : catch) +#else +# define tsd_setspecific(data) \ + if (__libc_internal_tsd_set != NULL) \ + __libc_internal_tsd_set (_LIBC_TSD_KEY_DL_ERROR, data); \ + else \ + catch = (data) +# define tsd_getspecific() \ + (__libc_internal_tsd_set != NULL \ + ? (struct catch *) __libc_internal_tsd_get (_LIBC_TSD_KEY_DL_ERROR) \ + : catch) +#endif + + /* This points to a function which is called when an error is received. Unlike the handling of `catch' this function may return. - The arguments will be the `errstring' and `objname'. */ + 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; @@ -48,27 +92,30 @@ _dl_signal_error (int errcode, const char *objname, const char *errstring) { + struct catch *lcatch; + if (! errstring) errstring = "DYNAMIC LINKER BUG!!!"; - if (catch) + lcatch = tsd_getspecific (); + 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. */ size_t objname_len = objname ? strlen (objname) + 2 : 0; size_t errstring_len = strlen (errstring) + 1; - catch->errstring = malloc (objname_len + errstring_len); - if (catch->errstring != NULL) + lcatch->errstring = malloc (objname_len + errstring_len); + if (lcatch->errstring != NULL) { if (objname_len > 0) { - memcpy (catch->errstring, objname, objname_len - 2); - memcpy (catch->errstring + objname_len - 2, ": ", 2); + memcpy (lcatch->errstring, objname, objname_len - 2); + memcpy (lcatch->errstring + objname_len - 2, ": ", 2); } - memcpy (catch->errstring + objname_len, errstring, errstring_len); + memcpy (lcatch->errstring + objname_len, errstring, errstring_len); } - longjmp (catch->env, errcode ?: -1); + longjmp (lcatch->env, errcode ?: -1); } else if (receiver) { @@ -106,19 +153,19 @@ _dl_catch_error (char **errstring, inefficient. So we initialize `c' by hand. */ c.errstring = NULL; - old = catch; + old = tsd_getspecific (); errcode = setjmp (c.env); if (errcode == 0) { - catch = &c; + tsd_setspecific (&c); (*operate) (args); - catch = old; + tsd_setspecific (old); *errstring = NULL; return 0; } /* We get here only if we longjmp'd out of OPERATE. */ - catch = old; + tsd_setspecific (old); *errstring = c.errstring; return errcode == -1 ? 0 : errcode; } @@ -130,15 +177,15 @@ _dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args) struct catch *old_catch; receiver_fct old_receiver; - old_catch = catch; + old_catch = tsd_getspecific (); old_receiver = receiver; /* Set the new values. */ - catch = NULL; + tsd_setspecific (NULL); receiver = fct; (*operate) (args); - catch = old_catch; + tsd_setspecific (old_catch); receiver = old_receiver; } |