diff options
Diffstat (limited to 'libexec/rtld-elf/rtld.c')
-rw-r--r-- | libexec/rtld-elf/rtld.c | 713 |
1 files changed, 464 insertions, 249 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index a53a25a..802773b 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -71,16 +71,6 @@ typedef void (*func_ptr_type)(); typedef void * (*path_enum_proc) (const char *path, size_t len, void *arg); /* - * This structure provides a reentrant way to keep a list of objects and - * check which ones have already been processed in some way. - */ -typedef struct Struct_DoneList { - 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; - -/* * Function declarations. */ static const char *basename(const char *); @@ -91,6 +81,8 @@ static void digest_dynamic2(Obj_Entry *, const Elf_Dyn *, const Elf_Dyn *); static void digest_dynamic(Obj_Entry *, int); static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *); static Obj_Entry *dlcheck(void *); +static Obj_Entry *dlopen_object(const char *name, Obj_Entry *refobj, + int lo_flags, int mode); static Obj_Entry *do_load_object(int, const char *, char *, struct stat *, int); static int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *); static bool donelist_check(DoneList *, const Obj_Entry *); @@ -106,12 +98,14 @@ static void initlist_add_neededs(Needed_Entry *, Objlist *); static void initlist_add_objects(Obj_Entry *, Obj_Entry **, Objlist *); static void linkmap_add(Obj_Entry *); static void linkmap_delete(Obj_Entry *); +static void load_filtees(Obj_Entry *, int flags, RtldLockState *); +static void unload_filtees(Obj_Entry *); static int load_needed_objects(Obj_Entry *, int); static int load_preload_objects(void); static Obj_Entry *load_object(const char *, const Obj_Entry *, int); static Obj_Entry *obj_from_addr(const void *); -static void objlist_call_fini(Objlist *, Obj_Entry *, int *); -static void objlist_call_init(Objlist *, int *); +static void objlist_call_fini(Objlist *, Obj_Entry *, RtldLockState *); +static void objlist_call_init(Objlist *, RtldLockState *); static void objlist_clear(Objlist *); static Objlist_Entry *objlist_find(Objlist *, const Obj_Entry *); static void objlist_init(Objlist *); @@ -119,20 +113,18 @@ static void objlist_push_head(Objlist *, Obj_Entry *); static void objlist_push_tail(Objlist *, Obj_Entry *); static void objlist_remove(Objlist *, Obj_Entry *); static void *path_enumerate(const char *, path_enum_proc, void *); -static int relocate_objects(Obj_Entry *, bool, Obj_Entry *); +static int relocate_objects(Obj_Entry *, bool, Obj_Entry *, RtldLockState *); static int rtld_dirname(const char *, char *); static int rtld_dirname_abs(const char *, char *); static void rtld_exit(void); static char *search_library_path(const char *, const char *); static const void **get_program_var_addr(const char *); static void set_program_var(const char *, const void *); -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, DoneList *); -static const Elf_Sym *symlook_needed(const char *, unsigned long, - const Needed_Entry *, const Obj_Entry **, const Ver_Entry *, - int, DoneList *); +static int symlook_default(SymLook *, const Obj_Entry *refobj); +static void symlook_init_from_req(SymLook *, const SymLook *); +static int symlook_list(SymLook *, const Objlist *, DoneList *); +static int symlook_needed(SymLook *, const Needed_Entry *, DoneList *); +static int symlook_obj1(SymLook *, const Obj_Entry *); static void trace_loaded_objects(Obj_Entry *); static void unlink_object(Obj_Entry *); static void unload_object(Obj_Entry *); @@ -157,6 +149,7 @@ void r_debug_state(struct r_debug *, struct link_map *); static char *error_message; /* Message for dlerror(), or NULL */ struct r_debug r_debug; /* for GDB; */ static bool libmap_disable; /* Disable libmap */ +static bool ld_loadfltr; /* Immediate filters processing */ static char *libmap_override; /* Maps to use in addition to libmap.conf */ static bool trust; /* False for setuid and setgid programs */ static bool dangerous_ld_env; /* True if environment variables have been @@ -300,7 +293,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) Obj_Entry *obj; Obj_Entry **preload_tail; Objlist initlist; - int lockstate; + RtldLockState lockstate; /* * On entry, the dynamic linker itself has not been relocated yet. @@ -346,7 +339,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) if (!trust) { if (unsetenv(LD_ "PRELOAD") || unsetenv(LD_ "LIBMAP") || unsetenv(LD_ "LIBRARY_PATH") || unsetenv(LD_ "LIBMAP_DISABLE") || - unsetenv(LD_ "DEBUG") || unsetenv(LD_ "ELF_HINTS_PATH")) { + unsetenv(LD_ "DEBUG") || unsetenv(LD_ "ELF_HINTS_PATH") || + unsetenv(LD_ "LOADFLTR")) { _rtld_error("environment corrupt; aborting"); die(); } @@ -357,9 +351,10 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) ld_library_path = getenv(LD_ "LIBRARY_PATH"); ld_preload = getenv(LD_ "PRELOAD"); ld_elf_hints_path = getenv(LD_ "ELF_HINTS_PATH"); + ld_loadfltr = getenv(LD_ "LOADFLTR") != NULL; dangerous_ld_env = libmap_disable || (libmap_override != NULL) || (ld_library_path != NULL) || (ld_preload != NULL) || - (ld_elf_hints_path != NULL); + (ld_elf_hints_path != NULL) || ld_loadfltr; ld_tracing = getenv(LD_ "TRACE_LOADED_OBJECTS"); ld_utrace = getenv(LD_ "UTRACE"); @@ -373,6 +368,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) dbg("RTLD dynamic = %p", obj_rtld.dynamic); dbg("RTLD pltgot = %p", obj_rtld.pltgot); + dbg("initializing thread locks"); + lockdflt_init(); + /* * Load the main program, or process its program header if it is * already loaded. @@ -498,7 +496,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) allocate_initial_tls(obj_list); if (relocate_objects(obj_main, - ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld) == -1) + ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld, NULL) == -1) die(); dbg("doing copy relocations"); @@ -515,19 +513,21 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) set_program_var("environ", env); set_program_var("__elf_aux_vector", aux); - dbg("initializing thread locks"); - lockdflt_init(); - /* Make a list of init functions to call. */ objlist_init(&initlist); initlist_add_objects(obj_list, preload_tail, &initlist); r_debug_state(NULL, &obj_main->linkmap); /* say hello to gdb! */ - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); objlist_call_init(&initlist, &lockstate); objlist_clear(&initlist); - wlock_release(rtld_bind_lock, lockstate); + dbg("loading filtees"); + for (obj = obj_list->next; obj != NULL; obj = obj->next) { + if (ld_loadfltr || obj->z_loadfltr) + load_filtees(obj, 0, &lockstate); + } + lock_release(rtld_bind_lock, &lockstate); dbg("transferring control to program entry point = %p", obj_main->entry); @@ -545,16 +545,19 @@ _rtld_bind(Obj_Entry *obj, Elf_Size reloff) const Obj_Entry *defobj; Elf_Addr *where; Elf_Addr target; - int lockstate; + RtldLockState lockstate; - lockstate = rlock_acquire(rtld_bind_lock); + rlock_acquire(rtld_bind_lock, &lockstate); + if (setjmp(lockstate.env) != 0) + lock_upgrade(rtld_bind_lock, &lockstate); if (obj->pltrel) rel = (const Elf_Rel *) ((caddr_t) obj->pltrel + reloff); else rel = (const Elf_Rel *) ((caddr_t) obj->pltrela + reloff); where = (Elf_Addr *) (obj->relocbase + rel->r_offset); - def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL); + def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL, + &lockstate); if (def == NULL) die(); @@ -572,7 +575,7 @@ _rtld_bind(Obj_Entry *obj, Elf_Size reloff) * that the trampoline needs. */ target = reloc_jmpslot(where, target, defobj, obj, rel); - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return target; } @@ -721,6 +724,8 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath, { const Elf_Dyn *dynp; Needed_Entry **needed_tail = &obj->needed; + Needed_Entry **needed_filtees_tail = &obj->needed_filtees; + Needed_Entry **needed_aux_filtees_tail = &obj->needed_aux_filtees; int plttype = DT_REL; *dyn_rpath = NULL; @@ -831,6 +836,30 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath, } break; + case DT_FILTER: + if (!obj->rtld) { + Needed_Entry *nep = NEW(Needed_Entry); + nep->name = dynp->d_un.d_val; + nep->obj = NULL; + nep->next = NULL; + + *needed_filtees_tail = nep; + needed_filtees_tail = &nep->next; + } + break; + + case DT_AUXILIARY: + if (!obj->rtld) { + Needed_Entry *nep = NEW(Needed_Entry); + nep->name = dynp->d_un.d_val; + nep->obj = NULL; + nep->next = NULL; + + *needed_aux_filtees_tail = nep; + needed_aux_filtees_tail = &nep->next; + } + break; + case DT_PLTGOT: obj->pltgot = (Elf_Addr *) (obj->relocbase + dynp->d_un.d_ptr); break; @@ -923,6 +952,8 @@ digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath, obj->bind_now = true; if (dynp->d_un.d_val & DF_1_NODELETE) obj->z_nodelete = true; + if (dynp->d_un.d_val & DF_1_LOADFLTR) + obj->z_loadfltr = true; break; default: @@ -1163,14 +1194,15 @@ find_library(const char *xname, const Obj_Entry *refobj) */ const Elf_Sym * find_symdef(unsigned long symnum, const Obj_Entry *refobj, - const Obj_Entry **defobj_out, int flags, SymCache *cache) + const Obj_Entry **defobj_out, int flags, SymCache *cache, + RtldLockState *lockstate) { const Elf_Sym *ref; const Elf_Sym *def; const Obj_Entry *defobj; - const Ver_Entry *ventry; + SymLook req; const char *name; - unsigned long hash; + int res; /* * If we have already found this symbol, get the information from @@ -1185,6 +1217,7 @@ find_symdef(unsigned long symnum, const Obj_Entry *refobj, ref = refobj->symtab + symnum; name = refobj->strtab + ref->st_name; + def = NULL; defobj = NULL; /* @@ -1200,9 +1233,15 @@ find_symdef(unsigned long symnum, const Obj_Entry *refobj, _rtld_error("%s: Bogus symbol table entry %lu", refobj->path, symnum); } - ventry = fetch_ventry(refobj, symnum); - hash = elf_hash(name); - def = symlook_default(name, hash, refobj, &defobj, ventry, flags); + symlook_init(&req, name); + req.flags = flags; + req.ventry = fetch_ventry(refobj, symnum); + req.lockstate = lockstate; + res = symlook_default(&req, refobj); + if (res == 0) { + def = req.sym_out; + defobj = req.defobj_out; + } } else { def = ref; defobj = refobj; @@ -1336,7 +1375,7 @@ init_rtld(caddr_t mapbase, Elf_Auxinfo **aux_info) * that symbols can be found. */ - relocate_objects(&objtmp, true, &objtmp); + relocate_objects(&objtmp, true, &objtmp, NULL); } /* Initialize the object list. */ @@ -1416,6 +1455,77 @@ initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, Objlist *list) #define FPTR_TARGET(f) ((Elf_Addr) (f)) #endif +static void +free_needed_filtees(Needed_Entry *n) +{ + Needed_Entry *needed, *needed1; + + for (needed = n; needed != NULL; needed = needed->next) { + if (needed->obj != NULL) { + dlclose(needed->obj); + needed->obj = NULL; + } + } + for (needed = n; needed != NULL; needed = needed1) { + needed1 = needed->next; + free(needed); + } +} + +static void +unload_filtees(Obj_Entry *obj) +{ + + free_needed_filtees(obj->needed_filtees); + obj->needed_filtees = NULL; + free_needed_filtees(obj->needed_aux_filtees); + obj->needed_aux_filtees = NULL; + obj->filtees_loaded = false; +} + +static void +load_filtee1(Obj_Entry *obj, Needed_Entry *needed, int flags) +{ + + for (; needed != NULL; needed = needed->next) { + needed->obj = dlopen_object(obj->strtab + needed->name, obj, + flags, ((ld_loadfltr || obj->z_loadfltr) ? RTLD_NOW : RTLD_LAZY) | + RTLD_LOCAL); + } +} + +static void +load_filtees(Obj_Entry *obj, int flags, RtldLockState *lockstate) +{ + + lock_restart_for_upgrade(lockstate); + if (!obj->filtees_loaded) { + load_filtee1(obj, obj->needed_filtees, flags); + load_filtee1(obj, obj->needed_aux_filtees, flags); + obj->filtees_loaded = true; + } +} + +static int +process_needed(Obj_Entry *obj, Needed_Entry *needed, int flags) +{ + Obj_Entry *obj1; + + for (; needed != NULL; needed = needed->next) { + obj1 = needed->obj = load_object(obj->strtab + needed->name, obj, + flags & ~RTLD_LO_NOLOAD); + if (obj1 == NULL && !ld_tracing && (flags & RTLD_LO_FILTEES) == 0) + return (-1); + if (obj1 != NULL && obj1->z_nodelete && !obj1->ref_nodel) { + dbg("obj %s nodelete", obj1->path); + init_dag(obj1); + ref_dag(obj1); + obj1->ref_nodel = true; + } + } + return (0); +} + /* * Given a shared object, traverse its list of needed objects, and load * each of them. Returns 0 on success. Generates an error message and @@ -1424,26 +1534,13 @@ initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, Objlist *list) static int load_needed_objects(Obj_Entry *first, int flags) { - Obj_Entry *obj, *obj1; + Obj_Entry *obj; for (obj = first; obj != NULL; obj = obj->next) { - Needed_Entry *needed; - - for (needed = obj->needed; needed != NULL; needed = needed->next) { - obj1 = needed->obj = load_object(obj->strtab + needed->name, obj, - flags & ~RTLD_LO_NOLOAD); - if (obj1 == NULL && !ld_tracing) - return -1; - if (obj1 != NULL && obj1->z_nodelete && !obj1->ref_nodel) { - dbg("obj %s nodelete", obj1->path); - init_dag(obj1); - ref_dag(obj1); - obj1->ref_nodel = true; - } - } + if (process_needed(obj, obj->needed, flags) == -1) + return (-1); } - - return 0; + return (0); } static int @@ -1615,7 +1712,7 @@ obj_from_addr(const void *addr) * the objects are expected to have non-NULL fini functions. */ static void -objlist_call_fini(Objlist *list, Obj_Entry *root, int *lockstate) +objlist_call_fini(Objlist *list, Obj_Entry *root, RtldLockState *lockstate) { Objlist_Entry *elm; char *saved_msg; @@ -1645,9 +1742,9 @@ objlist_call_fini(Objlist *list, Obj_Entry *root, int *lockstate) * won't be unloaded although its fini function has been * called. */ - wlock_release(rtld_bind_lock, *lockstate); + lock_release(rtld_bind_lock, lockstate); call_initfini_pointer(elm->obj, elm->obj->fini); - *lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, lockstate); /* No need to free anything if process is going down. */ if (root != NULL) free(elm); @@ -1668,7 +1765,7 @@ objlist_call_fini(Objlist *list, Obj_Entry *root, int *lockstate) * functions. */ static void -objlist_call_init(Objlist *list, int *lockstate) +objlist_call_init(Objlist *list, RtldLockState *lockstate) { Objlist_Entry *elm; Obj_Entry *obj; @@ -1700,9 +1797,9 @@ objlist_call_init(Objlist *list, int *lockstate) * without better locking. */ elm->obj->init_done = true; - wlock_release(rtld_bind_lock, *lockstate); + lock_release(rtld_bind_lock, lockstate); call_initfini_pointer(elm->obj, elm->obj->init); - *lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, lockstate); } errmsg_restore(saved_msg); } @@ -1774,7 +1871,8 @@ objlist_remove(Objlist *list, Obj_Entry *obj) * or -1 on failure. */ static int -relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj) +relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj, + RtldLockState *lockstate) { Obj_Entry *obj; @@ -1799,7 +1897,7 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj) } /* Process the non-PLT relocations. */ - if (reloc_non_plt(obj, rtldobj)) + if (reloc_non_plt(obj, rtldobj, lockstate)) return -1; if (obj->textrel) { /* Re-protected the text segment. */ @@ -1816,7 +1914,7 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj) return -1; /* Relocate the jump slots if we are doing immediate binding. */ if (obj->bind_now || bind_now) - if (reloc_jmpslots(obj) == -1) + if (reloc_jmpslots(obj, lockstate) == -1) return -1; @@ -1842,15 +1940,15 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj) static void rtld_exit(void) { - int lockstate; + RtldLockState lockstate; - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); dbg("rtld_exit()"); objlist_call_fini(&list_fini, NULL, &lockstate); /* No need to remove the items from the list, since we are exiting. */ if (!libmap_disable) lm_fini(); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); } static void * @@ -1945,12 +2043,12 @@ int dlclose(void *handle) { Obj_Entry *root; - int lockstate; + RtldLockState lockstate; - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); root = dlcheck(handle); if (root == NULL) { - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return -1; } LD_UTRACE(UTRACE_DLCLOSE_START, handle, NULL, 0, root->dl_refcount, @@ -1976,7 +2074,7 @@ dlclose(void *handle) unref_dag(root); LD_UTRACE(UTRACE_DLCLOSE_STOP, handle, NULL, 0, 0, NULL); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return 0; } @@ -2013,25 +2111,36 @@ dllockinit(void *context, void * dlopen(const char *name, int mode) { - Obj_Entry **old_obj_tail; - Obj_Entry *obj; - Objlist initlist; - int result, lockstate, nodelete, lo_flags; + int lo_flags; LD_UTRACE(UTRACE_DLOPEN_START, NULL, NULL, 0, mode, name); ld_tracing = (mode & RTLD_TRACE) == 0 ? NULL : "1"; if (ld_tracing != NULL) environ = (char **)*get_program_var_addr("environ"); - nodelete = mode & RTLD_NODELETE; lo_flags = RTLD_LO_DLOPEN; + if (mode & RTLD_NODELETE) + lo_flags |= RTLD_LO_NODELETE; if (mode & RTLD_NOLOAD) lo_flags |= RTLD_LO_NOLOAD; if (ld_tracing != NULL) lo_flags |= RTLD_LO_TRACE; + return (dlopen_object(name, obj_main, lo_flags, + mode & (RTLD_MODEMASK | RTLD_GLOBAL))); +} + +static Obj_Entry * +dlopen_object(const char *name, Obj_Entry *refobj, int lo_flags, int mode) +{ + Obj_Entry **old_obj_tail; + Obj_Entry *obj; + Objlist initlist; + RtldLockState lockstate; + int result; + objlist_init(&initlist); - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); GDB_STATE(RT_ADD,NULL); old_obj_tail = obj_tail; @@ -2040,25 +2149,24 @@ dlopen(const char *name, int mode) obj = obj_main; obj->refcount++; } else { - obj = load_object(name, obj_main, lo_flags); + obj = load_object(name, refobj, lo_flags); } if (obj) { obj->dl_refcount++; if (mode & RTLD_GLOBAL && objlist_find(&list_global, obj) == NULL) objlist_push_tail(&list_global, obj); - mode &= RTLD_MODEMASK; if (*old_obj_tail != NULL) { /* We loaded something new. */ assert(*old_obj_tail == obj); - result = load_needed_objects(obj, RTLD_LO_DLOPEN); + result = load_needed_objects(obj, lo_flags & RTLD_LO_DLOPEN); init_dag(obj); ref_dag(obj); if (result != -1) result = rtld_verify_versions(&obj->dagmembers); if (result != -1 && ld_tracing) goto trace; - if (result == -1 || - (relocate_objects(obj, mode == RTLD_NOW, &obj_rtld)) == -1) { + if (result == -1 || (relocate_objects(obj, (mode & RTLD_MODEMASK) + == RTLD_NOW, &obj_rtld, &lockstate)) == -1) { obj->dl_refcount--; unref_dag(obj); if (obj->refcount == 0) @@ -2079,10 +2187,11 @@ dlopen(const char *name, int mode) init_dag(obj); ref_dag(obj); - if (ld_tracing) + if ((lo_flags & RTLD_LO_TRACE) != 0) goto trace; } - if (obj != NULL && (nodelete || obj->z_nodelete) && !obj->ref_nodel) { + if (obj != NULL && ((lo_flags & RTLD_LO_NODELETE) != 0 || + obj->z_nodelete) && !obj->ref_nodel) { dbg("obj %s nodelete", obj->path); ref_dag(obj); obj->z_nodelete = obj->ref_nodel = true; @@ -2096,11 +2205,11 @@ dlopen(const char *name, int mode) /* Call the init functions. */ objlist_call_init(&initlist, &lockstate); objlist_clear(&initlist); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return obj; trace: trace_loaded_objects(obj); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); exit(0); } @@ -2110,36 +2219,46 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, { DoneList donelist; const Obj_Entry *obj, *defobj; - const Elf_Sym *def, *symp; - unsigned long hash; - int lockstate; + const Elf_Sym *def; + SymLook req; + RtldLockState lockstate; + int res; - hash = elf_hash(name); def = NULL; defobj = NULL; - flags |= SYMLOOK_IN_PLT; - - lockstate = rlock_acquire(rtld_bind_lock); + symlook_init(&req, name); + req.ventry = ve; + req.flags = flags | SYMLOOK_IN_PLT; + req.lockstate = &lockstate; + + rlock_acquire(rtld_bind_lock, &lockstate); + if (setjmp(lockstate.env) != 0) + lock_upgrade(rtld_bind_lock, &lockstate); if (handle == NULL || handle == RTLD_NEXT || handle == RTLD_DEFAULT || handle == RTLD_SELF) { if ((obj = obj_from_addr(retaddr)) == NULL) { _rtld_error("Cannot determine caller's shared object"); - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return NULL; } if (handle == NULL) { /* Just the caller's shared object. */ - def = symlook_obj(name, hash, obj, ve, flags); - defobj = obj; + res = symlook_obj(&req, obj); + if (res == 0) { + def = req.sym_out; + defobj = req.defobj_out; + } } else if (handle == RTLD_NEXT || /* Objects after caller's */ handle == RTLD_SELF) { /* ... caller included */ if (handle == RTLD_NEXT) obj = obj->next; for (; obj != NULL; obj = obj->next) { - if ((symp = symlook_obj(name, hash, obj, ve, flags)) != NULL) { - if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) { - def = symp; - defobj = obj; + res = symlook_obj(&req, obj); + if (res == 0) { + if (def == NULL || + ELF_ST_BIND(req.sym_out->st_info) != STB_WEAK) { + def = req.sym_out; + defobj = req.defobj_out; if (ELF_ST_BIND(def->st_info) != STB_WEAK) break; } @@ -2151,37 +2270,46 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, * dynamic linker services such as dlopen. */ if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { - symp = symlook_obj(name, hash, &obj_rtld, ve, flags); - if (symp != NULL) { - def = symp; - defobj = &obj_rtld; + res = symlook_obj(&req, &obj_rtld); + if (res == 0) { + def = req.sym_out; + defobj = req.defobj_out; } } } else { assert(handle == RTLD_DEFAULT); - def = symlook_default(name, hash, obj, &defobj, ve, flags); + res = symlook_obj(&req, obj); + if (res == 0) { + defobj = req.defobj_out; + def = req.sym_out; + } } } else { if ((obj = dlcheck(handle)) == NULL) { - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return NULL; } donelist_init(&donelist); if (obj->mainprog) { /* Search main program and all libraries loaded by it. */ - def = symlook_list(name, hash, &list_main, &defobj, ve, flags, - &donelist); - - /* - * We do not distinguish between 'main' object and global scope. - * If symbol is not defined by objects loaded at startup, continue - * search among dynamically loaded objects with RTLD_GLOBAL - * scope. - */ - if (def == NULL) - def = symlook_list(name, hash, &list_global, &defobj, ve, - flags, &donelist); + res = symlook_list(&req, &list_main, &donelist); + if (res == 0) { + def = req.sym_out; + defobj = req.defobj_out; + } else { + /* + * We do not distinguish between 'main' object and + * global scope. If symbol is not defined by objects + * loaded at startup, continue search among + * dynamically loaded objects with RTLD_GLOBAL scope. + */ + res = symlook_list(&req, &list_global, &donelist); + if (res == 0) { + def = req.sym_out; + defobj = req.defobj_out; + } + } } else { Needed_Entry fake; @@ -2189,13 +2317,16 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, fake.next = NULL; fake.obj = (Obj_Entry *)obj; fake.name = 0; - def = symlook_needed(name, hash, &fake, &defobj, ve, flags, - &donelist); + res = symlook_needed(&req, &fake, &donelist); + if (res == 0) { + def = req.sym_out; + defobj = req.defobj_out; + } } } if (def != NULL) { - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); /* * The value required by the caller is derived from the value @@ -2212,7 +2343,7 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, } _rtld_error("Undefined symbol \"%s\"", name); - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return NULL; } @@ -2253,17 +2384,17 @@ int _rtld_addr_phdr(const void *addr, struct dl_phdr_info *phdr_info) { const Obj_Entry *obj; - int lockstate; + RtldLockState lockstate; - lockstate = rlock_acquire(rtld_bind_lock); + rlock_acquire(rtld_bind_lock, &lockstate); obj = obj_from_addr(addr); if (obj == NULL) { _rtld_error("No shared object contains address"); - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return (0); } rtld_fill_dl_phdr_info(obj, phdr_info); - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return (1); } @@ -2274,13 +2405,13 @@ dladdr(const void *addr, Dl_info *info) const Elf_Sym *def; void *symbol_addr; unsigned long symoffset; - int lockstate; + RtldLockState lockstate; - lockstate = rlock_acquire(rtld_bind_lock); + rlock_acquire(rtld_bind_lock, &lockstate); obj = obj_from_addr(addr); if (obj == NULL) { _rtld_error("No shared object contains address"); - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return 0; } info->dli_fname = obj->path; @@ -2319,7 +2450,7 @@ dladdr(const void *addr, Dl_info *info) if (info->dli_saddr == addr) break; } - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return 1; } @@ -2327,9 +2458,10 @@ int dlinfo(void *handle, int request, void *p) { const Obj_Entry *obj; - int error, lockstate; + RtldLockState lockstate; + int error; - lockstate = rlock_acquire(rtld_bind_lock); + rlock_acquire(rtld_bind_lock, &lockstate); if (handle == NULL || handle == RTLD_SELF) { void *retaddr; @@ -2341,7 +2473,7 @@ dlinfo(void *handle, int request, void *p) obj = dlcheck(handle); if (obj == NULL) { - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return (-1); } @@ -2364,7 +2496,7 @@ dlinfo(void *handle, int request, void *p) error = -1; } - rlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return (error); } @@ -2389,10 +2521,11 @@ dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param) { struct dl_phdr_info phdr_info; const Obj_Entry *obj; - int error, bind_lockstate, phdr_lockstate; + RtldLockState bind_lockstate, phdr_lockstate; + int error; - phdr_lockstate = wlock_acquire(rtld_phdr_lock); - bind_lockstate = rlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_phdr_lock, &phdr_lockstate); + rlock_acquire(rtld_bind_lock, &bind_lockstate); error = 0; @@ -2402,8 +2535,8 @@ dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param) break; } - rlock_release(rtld_bind_lock, bind_lockstate); - wlock_release(rtld_phdr_lock, phdr_lockstate); + lock_release(rtld_bind_lock, &bind_lockstate); + lock_release(rtld_phdr_lock, &phdr_lockstate); return (error); } @@ -2631,20 +2764,16 @@ static const void ** get_program_var_addr(const char *name) { const Obj_Entry *obj; - unsigned long hash; + SymLook req; - hash = elf_hash(name); + symlook_init(&req, name); for (obj = obj_main; obj != NULL; obj = obj->next) { - const Elf_Sym *def; - - if ((def = symlook_obj(name, hash, obj, NULL, 0)) != NULL) { - const void **addr; - - addr = (const void **)(obj->relocbase + def->st_value); - return addr; + if (symlook_obj(&req, obj) == 0) { + return ((const void **)(req.defobj_out->relocbase + + req.sym_out->st_value)); } } - return NULL; + return (NULL); } /* @@ -2669,37 +2798,38 @@ set_program_var(const char *name, const void *value) * 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, const Ver_Entry *ventry, int flags) +static int +symlook_default(SymLook *req, const Obj_Entry *refobj) { DoneList donelist; const Elf_Sym *def; - const Elf_Sym *symp; - const Obj_Entry *obj; const Obj_Entry *defobj; const Objlist_Entry *elm; + SymLook req1; + int res; def = NULL; defobj = NULL; donelist_init(&donelist); + symlook_init_from_req(&req1, req); /* Look first in the referencing object if linked symbolically. */ if (refobj->symbolic && !donelist_check(&donelist, refobj)) { - symp = symlook_obj(name, hash, refobj, ventry, flags); - if (symp != NULL) { - def = symp; - defobj = refobj; + res = symlook_obj(&req1, refobj); + if (res == 0) { + def = req1.sym_out; + defobj = req1.defobj_out; + assert(defobj != NULL); } } /* 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, ventry, flags, - &donelist); - if (symp != NULL && - (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { - def = symp; - defobj = obj; + res = symlook_list(&req1, &list_main, &donelist); + if (res == 0 && + (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) { + def = req1.sym_out; + defobj = req1.defobj_out; + assert(defobj != NULL); } } @@ -2707,12 +2837,12 @@ symlook_default(const char *name, unsigned long hash, const Obj_Entry *refobj, STAILQ_FOREACH(elm, &list_global, link) { if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK) break; - symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, ventry, - flags, &donelist); - if (symp != NULL && - (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { - def = symp; - defobj = obj; + res = symlook_list(&req1, &elm->obj->dagmembers, &donelist); + if (res == 0 && + (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) { + def = req1.sym_out; + defobj = req1.defobj_out; + assert(defobj != NULL); } } @@ -2720,12 +2850,12 @@ symlook_default(const char *name, unsigned long hash, const Obj_Entry *refobj, 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, ventry, - flags, &donelist); - if (symp != NULL && - (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { - def = symp; - defobj = obj; + res = symlook_list(&req1, &elm->obj->dagmembers, &donelist); + if (res == 0 && + (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) { + def = req1.sym_out; + defobj = req1.defobj_out; + assert(defobj != NULL); } } @@ -2735,45 +2865,53 @@ symlook_default(const char *name, unsigned long hash, const Obj_Entry *refobj, * dynamic linker services such as dlopen. */ if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { - symp = symlook_obj(name, hash, &obj_rtld, ventry, flags); - if (symp != NULL) { - def = symp; - defobj = &obj_rtld; + res = symlook_obj(&req1, &obj_rtld); + if (res == 0) { + def = req1.sym_out; + defobj = req1.defobj_out; + assert(defobj != NULL); } } - if (def != NULL) - *defobj_out = defobj; - return def; + if (def != NULL) { + assert(defobj != NULL); + req->defobj_out = defobj; + req->sym_out = def; + return (0); + } + return (ESRCH); } -static const Elf_Sym * -symlook_list(const char *name, unsigned long hash, const Objlist *objlist, - const Obj_Entry **defobj_out, const Ver_Entry *ventry, int flags, - DoneList *dlp) +static int +symlook_list(SymLook *req, const Objlist *objlist, DoneList *dlp) { - const Elf_Sym *symp; const Elf_Sym *def; const Obj_Entry *defobj; const Objlist_Entry *elm; + SymLook req1; + int res; def = NULL; defobj = NULL; STAILQ_FOREACH(elm, objlist, link) { if (donelist_check(dlp, elm->obj)) continue; - if ((symp = symlook_obj(name, hash, elm->obj, ventry, flags)) != NULL) { - if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) { - def = symp; - defobj = elm->obj; + symlook_init_from_req(&req1, req); + if ((res = symlook_obj(&req1, elm->obj)) == 0) { + if (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK) { + def = req1.sym_out; + defobj = req1.defobj_out; if (ELF_ST_BIND(def->st_info) != STB_WEAK) break; } } } - if (def != NULL) - *defobj_out = defobj; - return def; + if (def != NULL) { + req->sym_out = def; + req->defobj_out = defobj; + return (0); + } + return (ESRCH); } /* @@ -2782,26 +2920,28 @@ symlook_list(const char *name, unsigned long hash, const Objlist *objlist, * 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) +static int +symlook_needed(SymLook *req, const Needed_Entry *needed, DoneList *dlp) { const Elf_Sym *def, *def_w; const Needed_Entry *n; - const Obj_Entry *obj, *defobj, *defobj1; + const Obj_Entry *defobj, *defobj1; + SymLook req1; + int res; def = def_w = NULL; defobj = NULL; + symlook_init_from_req(&req1, req); 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) + if (n->obj == NULL || donelist_check(dlp, n->obj) || + (res = symlook_obj(&req1, n->obj)) != 0) continue; - defobj = obj; + def = req1.sym_out; + defobj = req1.defobj_out; if (ELF_ST_BIND(def->st_info) != STB_WEAK) { - *defobj_out = defobj; - return (def); + req->defobj_out = defobj; + req->sym_out = def; + return (0); } } /* @@ -2809,12 +2949,13 @@ symlook_needed(const char *name, unsigned long hash, const Needed_Entry *needed, * directly needed objects, or found symbol is weak. */ for (n = needed; n != NULL; n = n->next) { - if ((obj = n->obj) == NULL) + if (n->obj == NULL) continue; - def_w = symlook_needed(name, hash, obj->needed, &defobj1, - ventry, flags, dlp); - if (def_w == NULL) + res = symlook_needed(&req1, n->obj->needed, dlp); + if (res != 0) continue; + def_w = req1.sym_out; + defobj1 = req1.defobj_out; if (def == NULL || ELF_ST_BIND(def_w->st_info) != STB_WEAK) { def = def_w; defobj = defobj1; @@ -2822,22 +2963,60 @@ symlook_needed(const char *name, unsigned long hash, const Needed_Entry *needed, if (ELF_ST_BIND(def_w->st_info) != STB_WEAK) break; } - if (def != NULL) - *defobj_out = defobj; - return (def); + if (def != NULL) { + req->sym_out = def; + req->defobj_out = defobj; + return (0); + } + return (ESRCH); } /* * 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. + * symbol, or NULL if no definition was found. If the object is + * filter, return filtered symbol from filtee. * * The symbol's hash value is passed in for efficiency reasons; that * eliminates many recomputations of the hash value. */ -const Elf_Sym * -symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, - const Ver_Entry *ventry, int flags) +int +symlook_obj(SymLook *req, const Obj_Entry *obj) +{ + DoneList donelist; + SymLook req1; + int res, mres; + + mres = symlook_obj1(req, obj); + if (mres == 0) { + if (obj->needed_filtees != NULL) { + load_filtees(__DECONST(Obj_Entry *, obj), 0, req->lockstate); + donelist_init(&donelist); + symlook_init_from_req(&req1, req); + res = symlook_needed(&req1, obj->needed_filtees, &donelist); + if (res == 0) { + req->sym_out = req1.sym_out; + req->defobj_out = req1.defobj_out; + } + return (res); + } + if (obj->needed_aux_filtees != NULL) { + load_filtees(__DECONST(Obj_Entry *, obj), 0, req->lockstate); + donelist_init(&donelist); + symlook_init_from_req(&req1, req); + res = symlook_needed(&req1, obj->needed_aux_filtees, &donelist); + if (res == 0) { + req->sym_out = req1.sym_out; + req->defobj_out = req1.defobj_out; + return (res); + } + } + } + return (mres); +} + +static int +symlook_obj1(SymLook *req, const Obj_Entry *obj) { unsigned long symnum; const Elf_Sym *vsymp; @@ -2845,18 +3024,18 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, int vcount; if (obj->buckets == NULL) - return NULL; + return (ESRCH); vsymp = NULL; vcount = 0; - symnum = obj->buckets[hash % obj->nbuckets]; + symnum = obj->buckets[req->hash % obj->nbuckets]; for (; symnum != STN_UNDEF; symnum = obj->chains[symnum]) { const Elf_Sym *symp; const char *strp; if (symnum >= obj->nchains) - return NULL; /* Bad object */ + return (ESRCH); /* Bad object */ symp = obj->symtab + symnum; strp = obj->strtab + symp->st_name; @@ -2872,7 +3051,7 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, if (symp->st_shndx != SHN_UNDEF) break; #ifndef __mips__ - else if (((flags & SYMLOOK_IN_PLT) == 0) && + else if (((req->flags & SYMLOOK_IN_PLT) == 0) && (ELF_ST_TYPE(symp->st_info) == STT_FUNC)) break; /* fallthrough */ @@ -2880,10 +3059,10 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, default: continue; } - if (name[0] != strp[0] || strcmp(name, strp) != 0) + if (req->name[0] != strp[0] || strcmp(req->name, strp) != 0) continue; - if (ventry == NULL) { + if (req->ventry == NULL) { if (obj->versyms != NULL) { verndx = VER_NDX(obj->versyms[symnum]); if (verndx > obj->vernum) { @@ -2893,7 +3072,7 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, } /* * If we are not called from dlsym (i.e. this is a normal - * relocation from unversioned binary, accept the symbol + * relocation from unversioned binary), accept the symbol * immediately if it happens to have first version after * this shared object became versioned. Otherwise, if * symbol is versioned and not hidden, remember it. If it @@ -2902,9 +3081,13 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, * end of the function. If symbol is global (verndx < 2) * accept it unconditionally. */ - if ((flags & SYMLOOK_DLSYM) == 0 && verndx == VER_NDX_GIVEN) - return symp; - else if (verndx >= VER_NDX_GIVEN) { + if ((req->flags & SYMLOOK_DLSYM) == 0 && + verndx == VER_NDX_GIVEN) { + req->sym_out = symp; + req->defobj_out = obj; + return (0); + } + else if (verndx >= VER_NDX_GIVEN) { if ((obj->versyms[symnum] & VER_NDX_HIDDEN) == 0) { if (vsymp == NULL) vsymp = symp; @@ -2913,13 +3096,15 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, continue; } } - return symp; + req->sym_out = symp; + req->defobj_out = obj; + return (0); } else { if (obj->versyms == NULL) { - if (object_match_name(obj, ventry->name)) { + if (object_match_name(obj, req->ventry->name)) { _rtld_error("%s: object %s should provide version %s for " - "symbol %s", obj_rtld.path, obj->path, ventry->name, - obj->strtab + symnum); + "symbol %s", obj_rtld.path, obj->path, + req->ventry->name, obj->strtab + symnum); continue; } } else { @@ -2929,8 +3114,8 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, obj->path, obj->strtab + symnum, verndx); continue; } - if (obj->vertab[verndx].hash != ventry->hash || - strcmp(obj->vertab[verndx].name, ventry->name)) { + if (obj->vertab[verndx].hash != req->ventry->hash || + strcmp(obj->vertab[verndx].name, req->ventry->name)) { /* * Version does not match. Look if this is a global symbol * and if it is not hidden. If global symbol (verndx < 2) @@ -2938,16 +3123,23 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, * called by dlvsym, because dlvsym looks for a specific * version and default one is not what dlvsym wants. */ - if ((flags & SYMLOOK_DLSYM) || + if ((req->flags & SYMLOOK_DLSYM) || (obj->versyms[symnum] & VER_NDX_HIDDEN) || (verndx >= VER_NDX_GIVEN)) continue; } } - return symp; + req->sym_out = symp; + req->defobj_out = obj; + return (0); } } - return (vcount == 1) ? vsymp : NULL; + if (vcount == 1) { + req->sym_out = vsymp; + req->defobj_out = obj; + return (0); + } + return (ESRCH); } static void @@ -3071,6 +3263,7 @@ unload_object(Obj_Entry *root) LD_UTRACE(UTRACE_UNLOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0, obj->path); dbg("unloading \"%s\"", obj->path); + unload_filtees(root); munmap(obj->mapbase, obj->mapsize); linkmap_delete(obj); *linkp = obj->next; @@ -3127,14 +3320,14 @@ void * tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset) { Elf_Addr* dtv = *dtvp; - int lockstate; + RtldLockState lockstate; /* Check dtv generation in case new modules have arrived */ if (dtv[0] != tls_dtv_generation) { Elf_Addr* newdtv; int to_copy; - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); newdtv = calloc(1, (tls_max_index + 2) * sizeof(Elf_Addr)); to_copy = dtv[1]; if (to_copy > tls_max_index) @@ -3143,17 +3336,17 @@ tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset) newdtv[0] = tls_dtv_generation; newdtv[1] = tls_max_index; free(dtv); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); *dtvp = newdtv; } /* Dynamically allocate module TLS if necessary */ if (!dtv[index + 1]) { /* Signal safe, wlock will block out signals. */ - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); if (!dtv[index + 1]) dtv[index + 1] = (Elf_Addr)allocate_module_tls(index); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); } return (void*) (dtv[index + 1] + offset); } @@ -3429,22 +3622,22 @@ void * _rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) { void *ret; - int lockstate; + RtldLockState lockstate; - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); ret = allocate_tls(obj_list, oldtls, tcbsize, tcbalign); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); return (ret); } void _rtld_free_tls(void *tcb, size_t tcbsize, size_t tcbalign) { - int lockstate; + RtldLockState lockstate; - lockstate = wlock_acquire(rtld_bind_lock); + wlock_acquire(rtld_bind_lock, &lockstate); free_tls(tcb, tcbsize, tcbalign); - wlock_release(rtld_bind_lock, lockstate); + lock_release(rtld_bind_lock, &lockstate); } static void @@ -3679,6 +3872,28 @@ fetch_ventry(const Obj_Entry *obj, unsigned long symnum) return NULL; } +void +symlook_init(SymLook *dst, const char *name) +{ + + bzero(dst, sizeof(*dst)); + dst->name = name; + dst->hash = elf_hash(name); +} + +static void +symlook_init_from_req(SymLook *dst, const SymLook *src) +{ + + dst->name = src->name; + dst->hash = src->hash; + dst->ventry = src->ventry; + dst->flags = src->flags; + dst->defobj_out = NULL; + dst->sym_out = NULL; + dst->lockstate = src->lockstate; +} + /* * Overrides for libc_pic-provided functions. */ |