diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 61fbbf6633d1..3059eaeefe70 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) { @@ -2361,6 +2368,57 @@ symlook_list(const char *name, unsigned long hash, const Objlist *objlist, return def; } +/* + * 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