diff options
-rw-r--r-- | libexec/rtld-elf/rtld.c | 162 | ||||
-rw-r--r-- | libexec/rtld-elf/rtld.h | 4 |
2 files changed, 97 insertions, 69 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 4eba8e7..9cbfe42 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -63,7 +63,7 @@ typedef void (*func_ptr_type)(); * check which ones have already been processed in some way. */ typedef struct Struct_DoneList { - Obj_Entry **objs; /* Array of object pointers */ + const Obj_Entry **objs; /* Array of object pointers */ unsigned int num_alloc; /* Allocated size of the array */ unsigned int num_used; /* Number of array slots used */ } DoneList; @@ -76,7 +76,7 @@ static void die(void); static void digest_dynamic(Obj_Entry *); static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *); static Obj_Entry *dlcheck(void *); -static bool donelist_check(DoneList *, Obj_Entry *); +static bool donelist_check(DoneList *, const Obj_Entry *); static char *find_library(const char *, const Obj_Entry *); static const char *gethints(void); static void init_dag(Obj_Entry *); @@ -106,6 +106,8 @@ static int relocate_objects(Obj_Entry *, bool); static void rtld_exit(void); static char *search_library_path(const char *, const char *); 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_list(const char *, unsigned long, Objlist *, const Obj_Entry **, bool in_plt, DoneList *); static void trace_loaded_objects(Obj_Entry *obj); @@ -706,7 +708,7 @@ dlcheck(void *handle) * add the object to the list and return false. */ static bool -donelist_check(DoneList *dlp, Obj_Entry *obj) +donelist_check(DoneList *dlp, const Obj_Entry *obj) { unsigned int i; @@ -792,81 +794,21 @@ find_library(const char *name, const Obj_Entry *refobj) * defining object via the reference parameter DEFOBJ_OUT. */ const Elf_Sym * -find_symdef(unsigned long symnum, Obj_Entry *refobj, +find_symdef(unsigned long symnum, const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt) { - DoneList donelist; const Elf_Sym *ref; const Elf_Sym *def; - const Elf_Sym *symp; - const Obj_Entry *obj; const Obj_Entry *defobj; - const Objlist_Entry *elm; const char *name; unsigned long hash; ref = refobj->symtab + symnum; name = refobj->strtab + ref->st_name; hash = elf_hash(name); - def = NULL; defobj = NULL; - donelist_init(&donelist); - - /* Look first in the referencing object if linked symbolically. */ - if (refobj->symbolic && !donelist_check(&donelist, refobj)) { - symp = symlook_obj(name, hash, refobj, in_plt); - if (symp != NULL) { - def = symp; - defobj = refobj; - } - } - /* Search all objects loaded at program start up. */ - if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { - symp = symlook_list(name, hash, &list_main, &obj, in_plt, &donelist); - if (symp != NULL && - (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { - def = symp; - defobj = obj; - } - } - - /* Search all dlopened DAGs containing the referencing object. */ - STAILQ_FOREACH(elm, &refobj->dldags, link) { - if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK) - break; - symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt, - &donelist); - if (symp != NULL && - (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { - def = symp; - defobj = obj; - } - } - - /* Search all RTLD_GLOBAL objects. */ - if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { - symp = symlook_list(name, hash, &list_global, &obj, in_plt, &donelist); - if (symp != NULL && - (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { - def = symp; - defobj = obj; - } - } - - /* - * Search the dynamic linker itself, and possibly resolve the - * symbol from there. This is how the application links to - * dynamic linker services such as dlopen. Only the values listed - * in the "exports" array can be resolved from the dynamic linker. - */ - if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { - symp = symlook_obj(name, hash, &obj_rtld, in_plt); - if (symp != NULL && is_exported(symp)) { - def = symp; - defobj = &obj_rtld; - } - } + def = symlook_default(name, hash, refobj, &defobj, in_plt); /* * If we found no definition and the reference is weak, treat the @@ -1605,7 +1547,7 @@ dlsym(void *handle, const char *name) defobj = NULL; rlock_acquire(); - if (handle == NULL || handle == RTLD_NEXT) { + if (handle == NULL || handle == RTLD_NEXT || handle == RTLD_DEFAULT) { void *retaddr; retaddr = __builtin_return_address(0); /* __GNUC__ only */ @@ -1617,13 +1559,16 @@ dlsym(void *handle, const char *name) if (handle == NULL) { /* Just the caller's shared object. */ def = symlook_obj(name, hash, obj, true); defobj = obj; - } else { /* All the shared objects after the caller's */ + } else if (handle == RTLD_NEXT) { /* Objects after caller's */ while ((obj = obj->next) != NULL) { if ((def = symlook_obj(name, hash, obj, true)) != NULL) { defobj = obj; break; } } + } else { + assert(handle == RTLD_DEFAULT); + def = symlook_default(name, hash, obj, &defobj, true); } } else { if ((obj = dlcheck(handle)) == NULL) { @@ -1808,6 +1753,89 @@ set_program_var(const char *name, const void *value) } } +/* + * Given a symbol name in a referencing object, find the corresponding + * definition of the symbol. Returns a pointer to the symbol, or NULL if + * no definition was found. Returns a pointer to the Obj_Entry of the + * defining object via the reference parameter DEFOBJ_OUT. + */ +static const Elf_Sym * +symlook_default(const char *name, unsigned long hash, + const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt) +{ + DoneList donelist; + const Elf_Sym *def; + const Elf_Sym *symp; + const Obj_Entry *obj; + const Obj_Entry *defobj; + const Objlist_Entry *elm; + def = NULL; + defobj = NULL; + donelist_init(&donelist); + + /* Look first in the referencing object if linked symbolically. */ + if (refobj->symbolic && !donelist_check(&donelist, refobj)) { + symp = symlook_obj(name, hash, refobj, in_plt); + if (symp != NULL) { + def = symp; + defobj = refobj; + } + } + + /* Search all objects loaded at program start up. */ + if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { + symp = symlook_list(name, hash, &list_main, &obj, in_plt, &donelist); + if (symp != NULL && + (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { + def = symp; + defobj = obj; + } + } + + /* Search all dlopened DAGs containing the referencing object. */ + STAILQ_FOREACH(elm, &refobj->dldags, link) { + if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK) + break; + symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt, + &donelist); + if (symp != NULL && + (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { + def = symp; + defobj = obj; + } + } + + /* Search all RTLD_GLOBAL objects. */ + if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { + symp = symlook_list(name, hash, &list_global, &obj, in_plt, &donelist); + if (symp != NULL && + (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { + def = symp; + defobj = obj; + } + } + + /* + * Search the dynamic linker itself, and possibly resolve the + * symbol from there. This is how the application links to + * dynamic linker services such as dlopen. Only the values listed + * in the "exports" array can be resolved from the dynamic linker. + */ + if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { + symp = symlook_obj(name, hash, &obj_rtld, in_plt); + if (symp != NULL && is_exported(symp)) { + def = symp; + defobj = &obj_rtld; + } + } + + if (def != NULL) + *defobj_out = defobj; + else + _rtld_error("%s: Undefined symbol \"%s\"", refobj->path, name); + return def; +} + static const Elf_Sym * symlook_list(const char *name, unsigned long hash, Objlist *objlist, const Obj_Entry **defobj_out, bool in_plt, DoneList *dlp) diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index 86d8181..68b6c4e 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -177,8 +177,8 @@ extern Elf_Addr _GLOBAL_OFFSET_TABLE_[]; */ int do_copy_relocations(Obj_Entry *); unsigned long elf_hash(const char *); -const Elf_Sym *find_symdef(unsigned long, Obj_Entry *, const Obj_Entry **, - bool); +const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *, + const Obj_Entry **, bool); void init_pltgot(Obj_Entry *); void lockdflt_init(LockInfo *); void obj_free(Obj_Entry *); |