diff options
| author | Konstantin Belousov <kib@FreeBSD.org> | 2007-01-16 07:51:04 +0000 |
|---|---|---|
| committer | Konstantin Belousov <kib@FreeBSD.org> | 2007-01-16 07:51:04 +0000 |
| commit | a74283464deb37bfce2ce1604b40ae767b5a79bc (patch) | |
| tree | e076b9a7a42d85a80575ff23f52a7925c22f4a92 /libexec | |
| parent | 32ddb9ef6f126079039c34963216d50e6ff70b39 (diff) | |
Notes
Diffstat (limited to 'libexec')
| -rw-r--r-- | libexec/rtld-elf/rtld.c | 97 |
1 files changed, 74 insertions, 23 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index a8ca864f4272..342ed281eac2 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -92,11 +92,10 @@ static void *fill_search_info(const char *, size_t, void *); static char *find_library(const char *, const Obj_Entry *); static const char *gethints(void); static void init_dag(Obj_Entry *); -static void init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *); +static void init_dag1(Obj_Entry *, Obj_Entry *, DoneList *); static void init_rtld(caddr_t); -static void initlist_add_neededs(Needed_Entry *needed, Objlist *list); -static void initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, - Objlist *list); +static void initlist_add_neededs(Needed_Entry *, Objlist *); +static void initlist_add_objects(Obj_Entry *, Obj_Entry **, Objlist *); static bool is_exported(const Elf_Sym *); static void linkmap_add(Obj_Entry *); static void linkmap_delete(Obj_Entry *); @@ -120,17 +119,19 @@ static void rtld_exit(void); static char *search_library_path(const char *, const char *); static const void **get_program_var_addr(const char *name); static void set_program_var(const char *, const void *); -static const Elf_Sym *symlook_default(const char *, unsigned long hash, - const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt); +static const Elf_Sym *symlook_default(const char *, unsigned long, + const Obj_Entry *, const Obj_Entry **, bool); static const Elf_Sym *symlook_list(const char *, unsigned long, - Objlist *, const Obj_Entry **, bool in_plt, DoneList *); -static void trace_loaded_objects(Obj_Entry *obj); + const Objlist *, const Obj_Entry **, bool, DoneList *); +static const Elf_Sym *symlook_needed(const char *, unsigned long, + const Needed_Entry *, const Obj_Entry **, bool, DoneList *); +static void trace_loaded_objects(Obj_Entry *); static void unlink_object(Obj_Entry *); static void unload_object(Obj_Entry *); static void unref_dag(Obj_Entry *); static void ref_dag(Obj_Entry *); -void r_debug_state(struct r_debug*, struct link_map*); +void r_debug_state(struct r_debug *, struct link_map *); /* * Data declarations. @@ -1766,10 +1767,10 @@ trace: void * dlsym(void *handle, const char *name) { - const Obj_Entry *obj; - unsigned long hash; + DoneList donelist; + const Obj_Entry *obj, *defobj; const Elf_Sym *def; - const Obj_Entry *defobj; + unsigned long hash; int lockstate; hash = elf_hash(name); @@ -1810,20 +1811,20 @@ dlsym(void *handle, const char *name) return NULL; } + donelist_init(&donelist); if (obj->mainprog) { - DoneList donelist; - /* Search main program and all libraries loaded by it. */ - donelist_init(&donelist); def = symlook_list(name, hash, &list_main, &defobj, true, - &donelist); + &donelist); } else { - /* - * XXX - This isn't correct. The search should include the whole - * DAG rooted at the given object. - */ - def = symlook_obj(name, hash, obj, true); - defobj = obj; + Needed_Entry fake; + + /* Search the whole DAG rooted at the given object. */ + fake.next = NULL; + fake.obj = (Obj_Entry *)obj; + fake.name = 0; + def = symlook_needed(name, hash, &fake, &defobj, true, + &donelist); } } @@ -2274,7 +2275,7 @@ symlook_default(const char *name, unsigned long hash, } static const Elf_Sym * -symlook_list(const char *name, unsigned long hash, Objlist *objlist, +symlook_list(const char *name, unsigned long hash, const Objlist *objlist, const Obj_Entry **defobj_out, bool in_plt, DoneList *dlp) { const Elf_Sym *symp; @@ -2302,6 +2303,56 @@ symlook_list(const char *name, unsigned long hash, 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, bool in_plt, 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, in_plt)) == 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, + in_plt, 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. Returns a pointer to the symbol, or NULL if no * definition was found. |
