summaryrefslogtreecommitdiffstats
path: root/libexec/rtld-elf
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2006-09-19 12:47:13 +0000
committerkib <kib@FreeBSD.org>2006-09-19 12:47:13 +0000
commit7c4f63574da6b0549767ea376bfe0960936b2401 (patch)
tree1055c85af1c4fde6eed302872903c8fdd0b1cead /libexec/rtld-elf
parent4524e2abf414d47f87e1e97aaa1690f6385a6943 (diff)
downloadFreeBSD-src-7c4f63574da6b0549767ea376bfe0960936b2401.zip
FreeBSD-src-7c4f63574da6b0549767ea376bfe0960936b2401.tar.gz
Fix the buggy rev. 1.117. dagmembers are only initialized for dlopen'ed
dso that are actually loading. If dso a.so depends on b.so, then dlsym with handle from dlopen("b.so") will fail unconditionally. Correct implementation shall use the Obj_Entry.needed list to walk dependencies DAG. Test provided by: jkim Tested (prev. version) by: jkim, Nicolas Blais <nb_root at videotron ca>, h.blanke at chello nl Pointy hat to: kib Approved by: kan (mentor)
Diffstat (limited to 'libexec/rtld-elf')
-rw-r--r--libexec/rtld-elf/rtld.c68
1 files changed, 63 insertions, 5 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 61fbbf6..3059eae 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -125,6 +125,9 @@ static const Elf_Sym *symlook_default(const char *, unsigned long,
const Obj_Entry *, const Obj_Entry **, const Ver_Entry *, int);
static const Elf_Sym *symlook_list(const char *, unsigned long, const Objlist *,
const Obj_Entry **, const Ver_Entry *, int flags, DoneList *);
+static const Elf_Sym *symlook_needed(const char *, unsigned long,
+ const Needed_Entry *, const Obj_Entry **, const Ver_Entry *,
+ int flags, DoneList *dlp);
static void trace_loaded_objects(Obj_Entry *obj);
static void unlink_object(Obj_Entry *);
static void unload_object(Obj_Entry *);
@@ -1852,17 +1855,21 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve,
}
DoneList donelist;
- const Objlist *srch_list;
donelist_init(&donelist);
if (obj->mainprog) {
/* Search main program and all libraries loaded by it. */
- srch_list = &list_main;
+ def = symlook_list(name, hash, &list_main, &defobj, ve, flags,
+ &donelist);
} else {
+ Needed_Entry fake;
+
/* Search the whole DAG rooted at the given object. */
- srch_list = &(obj->dagmembers);
+ fake.next = NULL;
+ fake.obj = (Obj_Entry *)obj;
+ fake.name = 0;
+ def = symlook_needed(name, hash, &fake, &defobj, ve, flags,
+ &donelist);
}
- def = symlook_list(name, hash, srch_list, &defobj, ve, flags,
- &donelist);
}
if (def != NULL) {
@@ -2362,6 +2369,57 @@ symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
}
/*
+ * Search the symbol table of a shared object and all objects needed
+ * by it for a symbol of the given name. Search order is
+ * breadth-first. Returns a pointer to the symbol, or NULL if no
+ * definition was found.
+ */
+static const Elf_Sym *
+symlook_needed(const char *name, unsigned long hash, const Needed_Entry *needed,
+ const Obj_Entry **defobj_out, const Ver_Entry *ventry, int flags,
+ DoneList *dlp)
+{
+ const Elf_Sym *def, *def_w;
+ const Needed_Entry *n;
+ const Obj_Entry *obj, *defobj, *defobj1;
+
+ def = def_w = NULL;
+ defobj = NULL;
+ for (n = needed; n != NULL; n = n->next) {
+ if ((obj = n->obj) == NULL ||
+ donelist_check(dlp, obj) ||
+ (def = symlook_obj(name, hash, obj, ventry, flags)) == NULL)
+ continue;
+ defobj = obj;
+ if (ELF_ST_BIND(def->st_info) != STB_WEAK) {
+ *defobj_out = defobj;
+ return (def);
+ }
+ }
+ /*
+ * There we come when either symbol definition is not found in
+ * directly needed objects, or found symbol is weak.
+ */
+ for (n = needed; n != NULL; n = n->next) {
+ if ((obj = n->obj) == NULL)
+ continue;
+ def_w = symlook_needed(name, hash, obj->needed, &defobj1,
+ ventry, flags, dlp);
+ if (def_w == NULL)
+ continue;
+ if (def == NULL || ELF_ST_BIND(def_w->st_info) != STB_WEAK) {
+ def = def_w;
+ defobj = defobj1;
+ }
+ if (ELF_ST_BIND(def_w->st_info) != STB_WEAK)
+ break;
+ }
+ if (def != NULL)
+ *defobj_out = defobj;
+ return def;
+}
+
+/*
* Search the symbol table of a single shared object for a symbol of
* the given name and version, if requested. Returns a pointer to the
* symbol, or NULL if no definition was found.
OpenPOWER on IntegriCloud