diff options
Diffstat (limited to 'lib/libc/stdlib/atexit.c')
-rw-r--r-- | lib/libc/stdlib/atexit.c | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/lib/libc/stdlib/atexit.c b/lib/libc/stdlib/atexit.c index a7a9a32..97cf234 100644 --- a/lib/libc/stdlib/atexit.c +++ b/lib/libc/stdlib/atexit.c @@ -37,6 +37,7 @@ static char sccsid[] = "@(#)atexit.c 8.2 (Berkeley) 7/3/94"; __FBSDID("$FreeBSD$"); #include "namespace.h" +#include <link.h> #include <stddef.h> #include <stdlib.h> #include <unistd.h> @@ -147,6 +148,9 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso) return (error); } +#pragma weak __pthread_cxa_finalize +void __pthread_cxa_finalize(const struct dl_phdr_info *); + /* * Call all handlers registered with __cxa_atexit for the shared * object owning 'dso'. Note: if 'dso' is NULL, then all remaining @@ -155,18 +159,28 @@ __cxa_atexit(void (*func)(void *), void *arg, void *dso) void __cxa_finalize(void *dso) { + struct dl_phdr_info phdr_info; struct atexit *p; struct atexit_fn fn; - int n; + int n, has_phdr; + + if (dso != NULL) + has_phdr = _rtld_addr_phdr(dso, &phdr_info); + else + has_phdr = 0; _MUTEX_LOCK(&atexit_mutex); for (p = __atexit; p; p = p->next) { for (n = p->ind; --n >= 0;) { if (p->fns[n].fn_type == ATEXIT_FN_EMPTY) continue; /* already been called */ - if (dso != NULL && dso != p->fns[n].fn_dso) - continue; /* wrong DSO */ fn = p->fns[n]; + if (dso != NULL && dso != fn.fn_dso) { + /* wrong DSO ? */ + if (!has_phdr || !__elf_phdr_match_addr( + &phdr_info, fn.fn_ptr.cxa_func)) + continue; + } /* Mark entry to indicate that this particular handler has already been called. @@ -185,4 +199,7 @@ __cxa_finalize(void *dso) _MUTEX_UNLOCK(&atexit_mutex); if (dso == NULL) _MUTEX_DESTROY(&atexit_mutex); + + if (&__pthread_cxa_finalize != NULL) + __pthread_cxa_finalize(&phdr_info); } |