summaryrefslogtreecommitdiffstats
path: root/libexec
diff options
context:
space:
mode:
Diffstat (limited to 'libexec')
-rw-r--r--libexec/rtld-elf/alpha/lockdflt.c21
-rw-r--r--libexec/rtld-elf/amd64/lockdflt.c21
-rw-r--r--libexec/rtld-elf/i386/lockdflt.c21
-rw-r--r--libexec/rtld-elf/lockdflt.c21
-rw-r--r--libexec/rtld-elf/rtld.c224
-rw-r--r--libexec/rtld-elf/rtld.h18
6 files changed, 187 insertions, 139 deletions
diff --git a/libexec/rtld-elf/alpha/lockdflt.c b/libexec/rtld-elf/alpha/lockdflt.c
index c926950..f9dbc5d 100644
--- a/libexec/rtld-elf/alpha/lockdflt.c
+++ b/libexec/rtld-elf/alpha/lockdflt.c
@@ -1,5 +1,5 @@
/*-
- * Copyright 1999 John D. Polstra.
+ * Copyright 1999, 2000 John D. Polstra.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,11 +51,8 @@ void
lockdflt_acquire(void *lock)
{
LockDflt *l = (LockDflt *)lock;
- sigset_t old_mask;
-
- sigprocmask(SIG_BLOCK, &l->lock_mask, &old_mask);
- if (l->depth == 0)
- l->old_mask = old_mask;
+ sigprocmask(SIG_BLOCK, &l->lock_mask, &l->old_mask);
+ assert(l->depth == 0);
l->depth++;
}
@@ -84,15 +81,7 @@ void
lockdflt_release(void *lock)
{
LockDflt *l = (LockDflt *)lock;
+ assert(l->depth == 1);
l->depth--;
- assert(l->depth >= 0);
- if (l->depth == 0)
- sigprocmask(SIG_SETMASK, &l->old_mask, NULL);
-}
-
-void
-lockdflt_init(void)
-{
- dllockinit(NULL, lockdflt_create, lockdflt_acquire, lockdflt_acquire,
- lockdflt_release, lockdflt_destroy, NULL);
+ sigprocmask(SIG_SETMASK, &l->old_mask, NULL);
}
diff --git a/libexec/rtld-elf/amd64/lockdflt.c b/libexec/rtld-elf/amd64/lockdflt.c
index c926950..f9dbc5d 100644
--- a/libexec/rtld-elf/amd64/lockdflt.c
+++ b/libexec/rtld-elf/amd64/lockdflt.c
@@ -1,5 +1,5 @@
/*-
- * Copyright 1999 John D. Polstra.
+ * Copyright 1999, 2000 John D. Polstra.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,11 +51,8 @@ void
lockdflt_acquire(void *lock)
{
LockDflt *l = (LockDflt *)lock;
- sigset_t old_mask;
-
- sigprocmask(SIG_BLOCK, &l->lock_mask, &old_mask);
- if (l->depth == 0)
- l->old_mask = old_mask;
+ sigprocmask(SIG_BLOCK, &l->lock_mask, &l->old_mask);
+ assert(l->depth == 0);
l->depth++;
}
@@ -84,15 +81,7 @@ void
lockdflt_release(void *lock)
{
LockDflt *l = (LockDflt *)lock;
+ assert(l->depth == 1);
l->depth--;
- assert(l->depth >= 0);
- if (l->depth == 0)
- sigprocmask(SIG_SETMASK, &l->old_mask, NULL);
-}
-
-void
-lockdflt_init(void)
-{
- dllockinit(NULL, lockdflt_create, lockdflt_acquire, lockdflt_acquire,
- lockdflt_release, lockdflt_destroy, NULL);
+ sigprocmask(SIG_SETMASK, &l->old_mask, NULL);
}
diff --git a/libexec/rtld-elf/i386/lockdflt.c b/libexec/rtld-elf/i386/lockdflt.c
index c926950..f9dbc5d 100644
--- a/libexec/rtld-elf/i386/lockdflt.c
+++ b/libexec/rtld-elf/i386/lockdflt.c
@@ -1,5 +1,5 @@
/*-
- * Copyright 1999 John D. Polstra.
+ * Copyright 1999, 2000 John D. Polstra.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,11 +51,8 @@ void
lockdflt_acquire(void *lock)
{
LockDflt *l = (LockDflt *)lock;
- sigset_t old_mask;
-
- sigprocmask(SIG_BLOCK, &l->lock_mask, &old_mask);
- if (l->depth == 0)
- l->old_mask = old_mask;
+ sigprocmask(SIG_BLOCK, &l->lock_mask, &l->old_mask);
+ assert(l->depth == 0);
l->depth++;
}
@@ -84,15 +81,7 @@ void
lockdflt_release(void *lock)
{
LockDflt *l = (LockDflt *)lock;
+ assert(l->depth == 1);
l->depth--;
- assert(l->depth >= 0);
- if (l->depth == 0)
- sigprocmask(SIG_SETMASK, &l->old_mask, NULL);
-}
-
-void
-lockdflt_init(void)
-{
- dllockinit(NULL, lockdflt_create, lockdflt_acquire, lockdflt_acquire,
- lockdflt_release, lockdflt_destroy, NULL);
+ sigprocmask(SIG_SETMASK, &l->old_mask, NULL);
}
diff --git a/libexec/rtld-elf/lockdflt.c b/libexec/rtld-elf/lockdflt.c
index c926950..f9dbc5d 100644
--- a/libexec/rtld-elf/lockdflt.c
+++ b/libexec/rtld-elf/lockdflt.c
@@ -1,5 +1,5 @@
/*-
- * Copyright 1999 John D. Polstra.
+ * Copyright 1999, 2000 John D. Polstra.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,11 +51,8 @@ void
lockdflt_acquire(void *lock)
{
LockDflt *l = (LockDflt *)lock;
- sigset_t old_mask;
-
- sigprocmask(SIG_BLOCK, &l->lock_mask, &old_mask);
- if (l->depth == 0)
- l->old_mask = old_mask;
+ sigprocmask(SIG_BLOCK, &l->lock_mask, &l->old_mask);
+ assert(l->depth == 0);
l->depth++;
}
@@ -84,15 +81,7 @@ void
lockdflt_release(void *lock)
{
LockDflt *l = (LockDflt *)lock;
+ assert(l->depth == 1);
l->depth--;
- assert(l->depth >= 0);
- if (l->depth == 0)
- sigprocmask(SIG_SETMASK, &l->old_mask, NULL);
-}
-
-void
-lockdflt_init(void)
-{
- dllockinit(NULL, lockdflt_create, lockdflt_acquire, lockdflt_acquire,
- lockdflt_release, lockdflt_destroy, NULL);
+ sigprocmask(SIG_SETMASK, &l->old_mask, NULL);
}
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 5bcd390..b5bba08 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -1,5 +1,5 @@
/*-
- * Copyright 1996, 1997, 1998, 1999 John D. Polstra.
+ * Copyright 1996, 1997, 1998, 1999, 2000 John D. Polstra.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -73,13 +73,16 @@ typedef struct Struct_LockInfo {
* Function declarations.
*/
static const char *basename(const char *);
-static void call_fini_functions(Obj_Entry *);
-static void call_init_functions(Obj_Entry *);
static void die(void);
static void digest_dynamic(Obj_Entry *);
static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
static Obj_Entry *dlcheck(void *);
static char *find_library(const char *, const Obj_Entry *);
+static void funclist_call(Funclist *);
+static void funclist_clear(Funclist *);
+static void funclist_init(Funclist *);
+static void funclist_push_head(Funclist *, InitFunc);
+static void funclist_push_tail(Funclist *, InitFunc);
static const char *gethints(void);
static void init_dag(Obj_Entry *);
static void init_dag1(Obj_Entry *root, Obj_Entry *obj);
@@ -102,7 +105,7 @@ static void set_program_var(const char *, const void *);
static const Elf_Sym *symlook_list(const char *, unsigned long,
Objlist *, const Obj_Entry **, bool in_plt);
static void trace_loaded_objects(Obj_Entry *obj);
-static void unload_object(Obj_Entry *, bool do_fini_funcs);
+static void unload_object(Obj_Entry *);
static void unref_dag(Obj_Entry *);
void r_debug_state(void);
@@ -158,7 +161,7 @@ static func_ptr_type exports[] = {
/*
* Global declarations normally provided by crt1. The dynamic linker is
- * not build with crt1, so we have to provide them ourselves.
+ * not built with crt1, so we have to provide them ourselves.
*/
char *__progname;
char **environ;
@@ -209,6 +212,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
Elf_Auxinfo *auxp;
const char *argv0;
Obj_Entry *obj;
+ Funclist initlist;
/*
* On entry, the dynamic linker itself has not been relocated yet.
@@ -325,15 +329,22 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
if (load_needed_objects(obj_main) == -1)
die();
- for (obj = obj_list; obj != NULL; obj = obj->next)
+ /*
+ * Make a list of all objects loaded at startup. Also construct
+ * the list of init functions to call, in reverse order.
+ */
+ funclist_init(&initlist);
+ for (obj = obj_list; obj != NULL; obj = obj->next) {
objlist_add(&list_main, obj);
+ if (obj->init != NULL && !obj->mainprog)
+ funclist_push_head(&initlist, obj->init);
+ }
if (ld_tracing) { /* We're done */
trace_loaded_objects(obj_main);
exit(0);
}
- dbg("relocating objects");
if (relocate_objects(obj_main,
ld_bind_now != NULL && *ld_bind_now != '\0') == -1)
die();
@@ -351,8 +362,10 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
r_debug_state(); /* say hello to gdb! */
- dbg("calling _init functions");
- call_init_functions(obj_main->next);
+ funclist_call(&initlist);
+ wlock_acquire();
+ funclist_clear(&initlist);
+ lock_release();
dbg("transferring control to program entry point = %p", obj_main->entry);
@@ -418,26 +431,6 @@ basename(const char *name)
}
static void
-call_fini_functions(Obj_Entry *first)
-{
- Obj_Entry *obj;
-
- for (obj = first; obj != NULL; obj = obj->next)
- if (obj->fini != NULL)
- (*obj->fini)();
-}
-
-static void
-call_init_functions(Obj_Entry *first)
-{
- if (first != NULL) {
- call_init_functions(first->next);
- if (first->init != NULL)
- (*first->init)();
- }
-}
-
-static void
die(void)
{
const char *msg = dlerror();
@@ -565,11 +558,11 @@ digest_dynamic(Obj_Entry *obj)
break;
case DT_INIT:
- obj->init = (void (*)(void)) (obj->relocbase + dynp->d_un.d_ptr);
+ obj->init = (InitFunc) (obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_FINI:
- obj->fini = (void (*)(void)) (obj->relocbase + dynp->d_un.d_ptr);
+ obj->fini = (InitFunc) (obj->relocbase + dynp->d_un.d_ptr);
break;
case DT_DEBUG:
@@ -834,6 +827,55 @@ find_symdef(unsigned long symnum, Obj_Entry *refobj,
return def;
}
+static void
+funclist_call(Funclist *list)
+{
+ Funclist_Entry *elm;
+
+ STAILQ_FOREACH(elm, list, link) {
+ dbg("calling init/fini function at %p", elm->func);
+ (*elm->func)();
+ }
+}
+
+static void
+funclist_clear(Funclist *list)
+{
+ Funclist_Entry *elm;
+
+ while (!STAILQ_EMPTY(list)) {
+ elm = STAILQ_FIRST(list);
+ STAILQ_REMOVE_HEAD(list, link);
+ free(elm);
+ }
+}
+
+static void
+funclist_init(Funclist *list)
+{
+ STAILQ_INIT(list);
+}
+
+static void
+funclist_push_head(Funclist *list, InitFunc func)
+{
+ Funclist_Entry *elm;
+
+ elm = NEW(Funclist_Entry);
+ elm->func = func;
+ STAILQ_INSERT_HEAD(list, elm, link);
+}
+
+static void
+funclist_push_tail(Funclist *list, InitFunc func)
+{
+ Funclist_Entry *elm;
+
+ elm = NEW(Funclist_Entry);
+ elm->func = func;
+ STAILQ_INSERT_TAIL(list, elm, link);
+}
+
/*
* Return the search path from the ldconfig hints file, reading it if
* necessary. Returns NULL if there are problems with the hints file,
@@ -1214,8 +1256,12 @@ relocate_objects(Obj_Entry *first, bool bind_now)
static void
rtld_exit(void)
{
+ Obj_Entry *obj;
+
dbg("rtld_exit()");
- call_fini_functions(obj_list->next);
+ for (obj = obj_list->next; obj != NULL; obj = obj->next)
+ if (obj->fini != NULL)
+ (*obj->fini)();
}
static char *
@@ -1258,6 +1304,8 @@ int
dlclose(void *handle)
{
Obj_Entry *root;
+ Obj_Entry *obj;
+ Funclist finilist;
wlock_acquire();
root = dlcheck(handle);
@@ -1266,11 +1314,31 @@ dlclose(void *handle)
return -1;
}
- GDB_STATE(RT_DELETE);
- unload_object(root, true);
+ /* Unreference the object and its dependencies. */
root->dl_refcount--;
- GDB_STATE(RT_CONSISTENT);
+ unref_dag(root);
+ if (root->refcount == 0) {
+ /*
+ * The object is no longer referenced, so we must unload it.
+ * First, make a list of the fini functions and then call them
+ * with no locks held.
+ */
+ funclist_init(&finilist);
+ for (obj = obj_list->next; obj != NULL; obj = obj->next)
+ if (obj->refcount == 0 && obj->fini != NULL)
+ funclist_push_tail(&finilist, obj->fini);
+
+ lock_release();
+ funclist_call(&finilist);
+ wlock_acquire();
+ funclist_clear(&finilist);
+
+ /* Finish cleaning up the newly-unreferenced objects. */
+ GDB_STATE(RT_DELETE);
+ unload_object(root);
+ GDB_STATE(RT_CONSISTENT);
+ }
lock_release();
return 0;
}
@@ -1338,6 +1406,10 @@ dlopen(const char *name, int mode)
{
Obj_Entry **old_obj_tail;
Obj_Entry *obj;
+ Obj_Entry *initobj;
+ Funclist initlist;
+
+ funclist_init(&initlist);
wlock_acquire();
GDB_STATE(RT_ADD);
@@ -1363,15 +1435,27 @@ dlopen(const char *name, int mode)
if (load_needed_objects(obj) == -1 ||
(init_dag(obj), relocate_objects(obj, mode == RTLD_NOW)) == -1) {
- unload_object(obj, false);
obj->dl_refcount--;
+ unref_dag(obj);
+ if (obj->refcount == 0)
+ unload_object(obj);
obj = NULL;
- } else
- call_init_functions(obj);
+ } else {
+ /* Make list of init functions to call, in reverse order */
+ for (initobj = obj; initobj != NULL; initobj = initobj->next)
+ if (initobj->init != NULL)
+ funclist_push_head(&initlist, initobj->init);
+ }
}
}
GDB_STATE(RT_CONSISTENT);
+
+ /* Call the init functions with no locks held. */
+ lock_release();
+ funclist_call(&initlist);
+ wlock_acquire();
+ funclist_clear(&initlist);
lock_release();
return obj;
}
@@ -1734,44 +1818,40 @@ trace_loaded_objects(Obj_Entry *obj)
}
/*
- * Note, this is called only for objects loaded by dlopen().
+ * Unload a dlopened object and its dependencies from memory and from
+ * our data structures. It is assumed that the DAG rooted in the
+ * object has already been unreferenced, and that the object has a
+ * reference count of 0.
*/
static void
-unload_object(Obj_Entry *root, bool do_fini_funcs)
+unload_object(Obj_Entry *root)
{
- unref_dag(root);
- if (root->refcount == 0) { /* We are finished with some objects. */
- Obj_Entry *obj;
- Obj_Entry **linkp;
- Objlist_Entry *elm;
-
- /* Finalize objects that are about to be unmapped. */
- if (do_fini_funcs)
- for (obj = obj_list->next; obj != NULL; obj = obj->next)
- if (obj->refcount == 0 && obj->fini != NULL)
- (*obj->fini)();
-
- /* Remove the DAG from all objects' DAG lists. */
- STAILQ_FOREACH(elm, &root->dagmembers , link)
- objlist_remove(&elm->obj->dldags, root);
-
- /* Remove the DAG from the RTLD_GLOBAL list. */
- objlist_remove(&list_global, root);
-
- /* Unmap all objects that are no longer referenced. */
- linkp = &obj_list->next;
- while ((obj = *linkp) != NULL) {
- if (obj->refcount == 0) {
- dbg("unloading \"%s\"", obj->path);
- munmap(obj->mapbase, obj->mapsize);
- linkmap_delete(obj);
- *linkp = obj->next;
- obj_free(obj);
- } else
- linkp = &obj->next;
- }
- obj_tail = linkp;
+ Obj_Entry *obj;
+ Obj_Entry **linkp;
+ Objlist_Entry *elm;
+
+ assert(root->refcount == 0);
+
+ /* Remove the DAG from all objects' DAG lists. */
+ STAILQ_FOREACH(elm, &root->dagmembers , link)
+ objlist_remove(&elm->obj->dldags, root);
+
+ /* Remove the DAG from the RTLD_GLOBAL list. */
+ objlist_remove(&list_global, root);
+
+ /* Unmap all objects that are no longer referenced. */
+ linkp = &obj_list->next;
+ while ((obj = *linkp) != NULL) {
+ if (obj->refcount == 0) {
+ dbg("unloading \"%s\"", obj->path);
+ munmap(obj->mapbase, obj->mapsize);
+ linkmap_delete(obj);
+ *linkp = obj->next;
+ obj_free(obj);
+ } else
+ linkp = &obj->next;
}
+ obj_tail = linkp;
}
static void
diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h
index b8fcf2c..3a88547 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -1,5 +1,5 @@
/*-
- * Copyright 1996-1998 John D. Polstra.
+ * Copyright 1996, 1997, 1998, 1999, 2000 John D. Polstra.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -52,6 +52,7 @@ typedef unsigned char bool;
struct stat;
struct Struct_Obj_Entry;
+/* Lists of shared objects */
typedef struct Struct_Objlist_Entry {
STAILQ_ENTRY(Struct_Objlist_Entry) link;
struct Struct_Obj_Entry *obj;
@@ -59,6 +60,17 @@ typedef struct Struct_Objlist_Entry {
typedef STAILQ_HEAD(Struct_Objlist, Struct_Objlist_Entry) Objlist;
+/* Lists of init or fini functions */
+typedef void (*InitFunc)(void);
+
+typedef struct Struct_Funclist_Entry {
+ STAILQ_ENTRY(Struct_Funclist_Entry) link;
+ InitFunc func;
+} Funclist_Entry;
+
+typedef STAILQ_HEAD(Struct_Funclist, Struct_Funclist_Entry) Funclist;
+
+/* Lists of shared object dependencies */
typedef struct Struct_Needed_Entry {
struct Struct_Needed_Entry *next;
struct Struct_Obj_Entry *obj;
@@ -122,8 +134,8 @@ typedef struct Struct_Obj_Entry {
const char *rpath; /* Search path specified in object */
Needed_Entry *needed; /* Shared objects needed by this one (%) */
- void (*init)(void); /* Initialization function to call */
- void (*fini)(void); /* Termination function to call */
+ InitFunc init; /* Initialization function to call */
+ InitFunc fini; /* Termination function to call */
bool mainprog; /* True if this is the main program */
bool rtld; /* True if this is the dynamic linker */
OpenPOWER on IntegriCloud