diff options
author | kib <kib@FreeBSD.org> | 2006-09-19 12:47:13 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2006-09-19 12:47:13 +0000 |
commit | 7c4f63574da6b0549767ea376bfe0960936b2401 (patch) | |
tree | 1055c85af1c4fde6eed302872903c8fdd0b1cead /libexec | |
parent | 4524e2abf414d47f87e1e97aaa1690f6385a6943 (diff) | |
download | FreeBSD-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')
-rw-r--r-- | libexec/rtld-elf/rtld.c | 68 |
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. |