summaryrefslogtreecommitdiffstats
path: root/libexec/rtld-elf/rtld.c
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/rtld-elf/rtld.c')
-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