1 /* vi: set sw=4 ts=4: */
3 * Program to load an ELF binary on a linux system, and run it
4 * after resolving ELF shared library symbols
6 * Copyright (C) 2000-2006 by Erik Andersen <andersen@uclibc.org>
7 * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
8 * David Engel, Hongjiu Lu and Mitch D'Souza
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. The name of the above contributors may not be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <bits/uClibc_mutex.h>
39 #ifdef __UCLIBC_HAS_TLS__
43 #if defined(USE_TLS) && USE_TLS
46 extern void _dl_add_to_slotinfo(struct link_map *l);
49 /* TODO: get rid of global lock and use more finegrained locking, or
50 * perhaps RCU for the global structures */
51 __UCLIBC_MUTEX_STATIC(_dl_mutex, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
54 # if defined(USE_TLS) && USE_TLS
55 extern struct link_map *_dl_update_slotinfo(unsigned long int req_modid);
58 /* When libdl is loaded as a shared library, we need to load in
59 * and use a pile of symbols from ldso... */
62 extern struct elf_resolve * _dl_load_shared_library(unsigned, struct dyn_elf **,
63 struct elf_resolve *, char *, int);
64 extern int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int lazy);
65 extern void _dl_protect_relro(struct elf_resolve * tpnt);
68 extern struct dyn_elf *_dl_symbol_tables;
69 extern struct dyn_elf *_dl_handles;
70 extern struct elf_resolve *_dl_loaded_modules;
71 extern void _dl_free (void *__ptr);
72 extern struct r_debug *_dl_debug_addr;
73 extern unsigned long _dl_error_number;
74 extern void *(*_dl_malloc_function)(size_t);
75 extern void (*_dl_free_function) (void *p);
76 extern void _dl_run_init_array(struct elf_resolve *);
77 extern void _dl_run_fini_array(struct elf_resolve *);
78 #ifdef __LDSO_CACHE_SUPPORT__
79 int _dl_map_cache(void);
80 int _dl_unmap_cache(void);
83 extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy);
85 #ifdef __SUPPORT_LD_DEBUG__
86 extern char *_dl_debug;
91 #define _dl_malloc malloc
94 /* When libdl is linked as a static library, we need to replace all
95 * the symbols that otherwise would have been loaded in from ldso... */
97 #ifdef __SUPPORT_LD_DEBUG__
98 char *_dl_debug = NULL;
99 char *_dl_debug_symbols = NULL;
100 char *_dl_debug_move = NULL;
101 char *_dl_debug_reloc = NULL;
102 char *_dl_debug_detail = NULL;
103 char *_dl_debug_nofixups = NULL;
104 char *_dl_debug_bindings = NULL;
105 int _dl_debug_file = 2;
107 const char *_dl_progname = ""; /* Program name */
108 void *(*_dl_malloc_function)(size_t);
109 void (*_dl_free_function) (void *p);
110 #ifdef __LDSO_LD_LIBRARY_PATH__
111 char *_dl_library_path = NULL; /* Where we look for libraries */
113 int _dl_errno = 0; /* We can't use the real errno in ldso */
114 size_t _dl_pagesize = PAGE_SIZE; /* Store the page size for use later */
115 /* This global variable is also to communicate with debuggers such as gdb. */
116 struct r_debug *_dl_debug_addr = NULL;
118 #include "../ldso/dl-array.c"
119 #include "../ldso/dl-debug.c"
122 # if defined(USE_TLS) && USE_TLS
124 * Giving this initialized value preallocates some surplus bytes in the
125 * static TLS area, see __libc_setup_tls (libc-tls.c).
127 size_t _dl_tls_static_size = 2048;
129 #include LDSO_ELFINTERP
130 #include "../ldso/dl-hash.c"
131 #define _dl_trace_loaded_objects 0
132 #include "../ldso/dl-elf.c"
135 #ifdef __SUPPORT_LD_DEBUG__
136 # define _dl_if_debug_print(fmt, args...) \
139 fprintf(stderr, "%s():%i: " fmt, __func__, __LINE__, ## args); \
142 # define _dl_if_debug_print(fmt, args...)
145 static int do_dlclose(void *, int need_fini);
148 static const char *const dl_error_names[] = {
151 "Unable to open /dev/zero",
153 #if defined (__i386__)
155 #elif defined (__sparc__)
157 #elif defined (__mc68000__)
160 "Unrecognized binary type",
162 "Not an ELF shared library",
163 "Unable to mmap file",
164 "No dynamic section",
165 "Library contains unsupported TLS",
166 #ifdef ELF_USES_RELOCA
167 "Unable to process REL relocs",
169 "Unable to process RELA relocs",
172 "Unable to resolve symbol"
176 #if defined(USE_TLS) && USE_TLS
179 * Systems which do not have tls_index also probably have to define
180 * DONT_USE_TLS_INDEX.
183 # ifndef __TLS_GET_ADDR
184 # define __TLS_GET_ADDR __tls_get_addr
188 * Return the symbol address given the map of the module it is in and
189 * the symbol record. This is used in dl-sym.c.
193 _dl_tls_symaddr(struct link_map *map, const Elf32_Addr st_value)
195 # ifndef DONT_USE_TLS_INDEX
198 .ti_module = map->l_tls_modid,
199 .ti_offset = st_value
202 return __TLS_GET_ADDR (&tmp);
204 return __TLS_GET_ADDR (map->l_tls_modid, st_value);
209 /* Returns true when a non-empty entry was found. */
211 remove_slotinfo(size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
212 bool should_be_there)
214 if (idx - disp >= listp->len) {
215 if (listp->next == NULL) {
217 * The index is not actually valid in the slotinfo list,
218 * because this object was closed before it was fully set
219 * up due to some error.
221 _dl_assert(!should_be_there);
223 if (remove_slotinfo(idx, listp->next, disp + listp->len,
228 * No non-empty entry. Search from the end of this element's
231 idx = disp + listp->len;
234 struct link_map *old_map = listp->slotinfo[idx - disp].map;
237 * The entry might still be in its unused state if we are
238 * closing an object that wasn't fully set up.
240 if (__builtin_expect(old_map != NULL, 1)) {
241 _dl_assert(old_map->l_tls_modid == idx);
243 /* Mark the entry as unused. */
244 listp->slotinfo[idx - disp].gen = _dl_tls_generation + 1;
245 listp->slotinfo[idx - disp].map = NULL;
249 * If this is not the last currently used entry no need to
252 if (idx != _dl_tls_max_dtv_idx)
256 while (idx - disp > (disp == 0 ? 1 + _dl_tls_static_nelem : 0)) {
259 if (listp->slotinfo[idx - disp].map != NULL) {
260 /* Found a new last used index. */
261 _dl_tls_max_dtv_idx = idx;
266 /* No non-entry in this list element. */
271 #ifndef __LDSO_NO_CLEANUP__
272 void dl_cleanup(void) attribute_hidden __attribute__ ((destructor));
273 void dl_cleanup(void)
275 struct dyn_elf *h, *n;
277 for (h = _dl_handles; h; h = n) {
284 static ptrdiff_t _dl_build_local_scope (struct elf_resolve **list,
285 struct elf_resolve *map)
287 struct elf_resolve **p = list;
288 struct init_fini_list *q;
291 map->init_flag |= DL_RESERVED;
293 for (q = map->init_fini; q; q = q->next)
294 if (! (q->tpnt->init_flag & DL_RESERVED))
295 p += _dl_build_local_scope (p, q->tpnt);
299 static void *do_dlopen(const char *libname, int flag, ElfW(Addr) from)
301 struct elf_resolve *tpnt, *tfrom;
302 struct dyn_elf *dyn_chain, *rpnt = NULL, *dyn_ptr, *relro_ptr, *handle;
303 struct elf_resolve *tpnt1;
304 void (*dl_brk) (void);
306 struct init_fini_list *tmp, *runp, *runp2, *dep_list;
307 unsigned int nlist, i;
308 struct elf_resolve **init_fini_list;
309 static bool _dl_init;
310 struct elf_resolve **local_scope;
311 struct r_scope_elem *ls;
312 #if defined(USE_TLS) && USE_TLS
313 bool any_tls = false;
316 /* A bit of sanity checking... */
317 if (!(flag & (RTLD_LAZY|RTLD_NOW|RTLD_NOLOAD))) {
318 _dl_error_number = LD_BAD_HANDLE;
324 _dl_malloc_function = malloc;
325 _dl_free_function = free;
327 /* Cover the trivial case first */
329 return _dl_symbol_tables;
332 # ifdef __SUPPORT_LD_DEBUG__
333 _dl_debug = getenv("LD_DEBUG");
335 if (strstr(_dl_debug, "all")) {
336 _dl_debug_detail = _dl_debug_move = _dl_debug_symbols
337 = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = (void*)1;
339 _dl_debug_detail = strstr(_dl_debug, "detail");
340 _dl_debug_move = strstr(_dl_debug, "move");
341 _dl_debug_symbols = strstr(_dl_debug, "sym");
342 _dl_debug_reloc = strstr(_dl_debug, "reloc");
343 _dl_debug_nofixups = strstr(_dl_debug, "nofix");
344 _dl_debug_bindings = strstr(_dl_debug, "bind");
353 * Try and locate the module we were called from - we
354 * need this so that we get the correct RPATH/RUNPATH. Note that
355 * this is the current behavior under Solaris, but the
356 * ABI+ specifies that we should only use the RPATH from
357 * the application. Thus this may go away at some time
361 struct dyn_elf *dpnt;
363 for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
365 if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom))
369 for (rpnt = _dl_symbol_tables; rpnt && rpnt->next; rpnt = rpnt->next)
373 now_flag = (flag & RTLD_NOW) ? RTLD_NOW : 0;
374 if (getenv("LD_BIND_NOW"))
377 #if !defined SHARED && defined __LDSO_LD_LIBRARY_PATH__
378 /* When statically linked, the _dl_library_path is not yet initialized */
379 _dl_library_path = getenv("LD_LIBRARY_PATH");
382 /* Try to load the specified library */
383 _dl_if_debug_print("Trying to dlopen '%s', RTLD_GLOBAL:%d RTLD_NOW:%d\n",
384 (char*)libname, (flag & RTLD_GLOBAL ? 1:0), (now_flag & RTLD_NOW ? 1:0));
386 tpnt = _dl_load_shared_library((flag & RTLD_NOLOAD) ? DL_RESOLVE_NOLOAD : 0,
387 &rpnt, tfrom, (char*)libname, 0);
392 dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
393 memset(dyn_chain, 0, sizeof(struct dyn_elf));
394 dyn_chain->dyn = tpnt;
395 tpnt->rtld_flags |= (flag & RTLD_GLOBAL);
397 dyn_chain->next_handle = _dl_handles;
398 _dl_handles = dyn_ptr = dyn_chain;
400 if (tpnt->usage_count > 1) {
401 _dl_if_debug_print("Lib: %s already opened\n", libname);
402 /* see if there is a handle from a earlier dlopen */
403 for (handle = _dl_handles->next_handle; handle; handle = handle->next_handle) {
404 if (handle->dyn == tpnt) {
405 dyn_chain->init_fini.init_fini = handle->init_fini.init_fini;
406 dyn_chain->init_fini.nlist = handle->init_fini.nlist;
407 for (i = 0; i < dyn_chain->init_fini.nlist; i++)
408 dyn_chain->init_fini.init_fini[i]->rtld_flags |= (flag & RTLD_GLOBAL);
409 dyn_chain->next = handle->next;
416 tpnt->init_flag |= DL_OPENED;
418 _dl_if_debug_print("Looking for needed libraries\n");
420 runp = alloca(sizeof(*runp));
423 dep_list = runp2 = runp;
424 for (; runp; runp = runp->next) {
429 runp->tpnt->init_fini = NULL; /* clear any previous dependcies */
430 for (dpnt = (ElfW(Dyn) *) runp->tpnt->dynamic_addr; dpnt->d_tag; dpnt++) {
431 if (dpnt->d_tag == DT_NEEDED) {
432 lpntstr = (char*) (runp->tpnt->dynamic_info[DT_STRTAB] +
434 _dl_if_debug_print("Trying to load '%s', needed by '%s'\n",
435 lpntstr, runp->tpnt->libname);
436 tpnt1 = _dl_load_shared_library(0, &rpnt, runp->tpnt, lpntstr, 0);
440 tpnt1->rtld_flags |= (flag & RTLD_GLOBAL);
442 /* This list is for dlsym() and relocation */
443 dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
444 memset (dyn_ptr->next, 0, sizeof (struct dyn_elf));
445 dyn_ptr = dyn_ptr->next;
446 dyn_ptr->dyn = tpnt1;
447 /* Used to record RTLD_LOCAL scope */
448 tmp = alloca(sizeof(struct init_fini_list));
450 tmp->next = runp->tpnt->init_fini;
451 runp->tpnt->init_fini = tmp;
453 for (tmp=dep_list; tmp; tmp = tmp->next) {
454 if (tpnt1 == tmp->tpnt) { /* if match => cirular dependency, drop it */
455 _dl_if_debug_print("Circular dependency, skipping '%s',\n",
457 tpnt1->usage_count--;
461 if (!tmp) { /* Don't add if circular dependency detected */
462 runp2->next = alloca(sizeof(*runp));
470 init_fini_list = malloc(nlist * sizeof(struct elf_resolve *));
471 dyn_chain->init_fini.init_fini = init_fini_list;
472 dyn_chain->init_fini.nlist = nlist;
474 for (runp2 = dep_list; runp2; runp2 = runp2->next) {
475 init_fini_list[i++] = runp2->tpnt;
476 for (runp = runp2->tpnt->init_fini; runp; runp = runp->next) {
477 if (!(runp->tpnt->rtld_flags & RTLD_GLOBAL)) {
478 tmp = malloc(sizeof(struct init_fini_list));
479 tmp->tpnt = runp->tpnt;
480 tmp->next = runp2->tpnt->rtld_local;
481 runp2->tpnt->rtld_local = tmp;
486 /* Build the local scope for the dynamically loaded modules. */
487 local_scope = _dl_malloc(nlist * sizeof(struct elf_resolve *)); /* Could it allocated on stack? */
488 for (i = 0; i < nlist; i++)
489 if (init_fini_list[i]->symbol_scope.r_nlist == 0) {
491 cnt = _dl_build_local_scope(local_scope, init_fini_list[i]);
492 init_fini_list[i]->symbol_scope.r_list = _dl_malloc(cnt * sizeof(struct elf_resolve *));
493 init_fini_list[i]->symbol_scope.r_nlist = cnt;
494 _dl_memcpy (init_fini_list[i]->symbol_scope.r_list, local_scope,
495 cnt * sizeof (struct elf_resolve *));
496 /* Restoring the init_flag.*/
497 for (k = 0; k < nlist; k++)
498 init_fini_list[k]->init_flag &= ~DL_RESERVED;
501 _dl_free(local_scope);
503 /* Sort the INIT/FINI list in dependency order. */
504 for (runp2 = dep_list; runp2; runp2 = runp2->next) {
506 for (j = 0; init_fini_list[j] != runp2->tpnt; ++j)
508 for (k = j + 1; k < nlist; ++k) {
509 struct init_fini_list *ele = init_fini_list[k]->init_fini;
511 for (; ele; ele = ele->next) {
512 if (ele->tpnt == runp2->tpnt) {
513 struct elf_resolve *here = init_fini_list[k];
514 _dl_if_debug_print("Move %s from pos %d to %d in INIT/FINI list.\n", here->libname, k, j);
515 for (i = (k - j); i; --i)
516 init_fini_list[i+j] = init_fini_list[i+j-1];
517 init_fini_list[j] = here;
524 #ifdef __SUPPORT_LD_DEBUG__
526 fprintf(stderr, "\nINIT/FINI order and dependencies:\n");
527 for (i = 0; i < nlist; i++) {
528 fprintf(stderr, "lib: %s has deps:\n", init_fini_list[i]->libname);
529 runp = init_fini_list[i]->init_fini;
530 for (; runp; runp = runp->next)
531 fprintf(stderr, " %s ", runp->tpnt->libname);
532 fprintf(stderr, "\n");
537 _dl_if_debug_print("Beginning dlopen relocation fixups\n");
539 * OK, now all of the kids are tucked into bed in their proper addresses.
540 * Now we go through and look for REL and RELA records that indicate fixups
541 * to the GOT tables. We need to do this in reverse order so that COPY
542 * directives work correctly */
546 * Get the tail of the list.
547 * In the static case doesn't need to extend the global scope, it is
548 * ready to be used as it is, because _dl_loaded_modules already points
549 * to the dlopened library.
551 for (ls = &_dl_loaded_modules->symbol_scope; ls && ls->next; ls = ls->next);
553 /* Extend the global scope by adding the local scope of the dlopened DSO. */
554 ls->next = &dyn_chain->dyn->symbol_scope;
558 * Relocation of the GOT entries for MIPS have to be done
559 * after all the libraries have been loaded.
561 _dl_perform_mips_global_got_relocations(tpnt, !now_flag);
564 if (_dl_fixup(dyn_chain, &_dl_loaded_modules->symbol_scope, now_flag))
568 for (rpnt = relro_ptr->next; rpnt; rpnt = rpnt->next) {
569 if (rpnt->dyn->relro_size)
570 _dl_protect_relro(rpnt->dyn);
573 /* TODO: Should we set the protections of all pages back to R/O now ? */
576 #if defined(USE_TLS) && USE_TLS
578 for (i=0; i < nlist; i++) {
579 struct elf_resolve *tmp_tpnt = init_fini_list[i];
580 /* Only add TLS memory if this object is loaded now and
581 therefore is not yet initialized. */
583 if (!(tmp_tpnt->init_flag & INIT_FUNCS_CALLED)
584 /* Only if the module defines thread local data. */
585 && __builtin_expect (tmp_tpnt->l_tls_blocksize > 0, 0)) {
587 /* Now that we know the object is loaded successfully add
588 modules containing TLS data to the slot info table. We
589 might have to increase its size. */
590 _dl_add_to_slotinfo ((struct link_map*)tmp_tpnt);
592 /* It is the case in which we couldn't perform TLS static
593 initialization at relocation time, and we delayed it until
594 the relocation has been completed. */
596 if (tmp_tpnt->l_need_tls_init) {
597 tmp_tpnt->l_need_tls_init = 0;
599 /* Update the slot information data for at least the
600 generation of the DSO we are allocating data for. */
601 _dl_update_slotinfo (tmp_tpnt->l_tls_modid);
604 _dl_init_static_tls((struct link_map*)tmp_tpnt);
605 _dl_assert (tmp_tpnt->l_need_tls_init == 0);
608 /* We have to bump the generation counter. */
613 /* Bump the generation number if necessary. */
614 if (any_tls && __builtin_expect (++_dl_tls_generation == 0, 0)) {
615 _dl_debug_early("TLS generation counter wrapped! Please report this.");
621 /* Notify the debugger we have added some objects. */
622 if (_dl_debug_addr) {
623 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
624 if (dl_brk != NULL) {
625 _dl_debug_addr->r_state = RT_ADD;
628 _dl_debug_addr->r_state = RT_CONSISTENT;
633 /* Run the ctors and setup the dtors */
634 for (i = nlist; i; --i) {
635 tpnt = init_fini_list[i-1];
636 if (tpnt->init_flag & INIT_FUNCS_CALLED)
638 tpnt->init_flag |= INIT_FUNCS_CALLED;
640 if (tpnt->dynamic_info[DT_INIT]) {
641 void (*dl_elf_func) (void);
642 dl_elf_func = (void (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_INIT]);
644 _dl_if_debug_print("running ctors for library %s at '%p'\n",
645 tpnt->libname, dl_elf_func);
646 DL_CALL_FUNC_AT_ADDR (dl_elf_func, tpnt->loadaddr, (void(*)(void)));
650 _dl_run_init_array(tpnt);
654 return (void *) dyn_chain;
657 /* Something went wrong. Clean up and return NULL. */
659 do_dlclose(dyn_chain, 0);
663 void *dlopen(const char *libname, int flag)
667 __UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
668 ret = do_dlopen(libname, flag,
669 (ElfW(Addr)) __builtin_return_address(0));
670 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
675 static void *do_dlsym(void *vhandle, const char *name, void *caller_address)
677 struct elf_resolve *tpnt, *tfrom;
678 struct dyn_elf *handle;
680 struct dyn_elf *rpnt;
682 struct symbol_ref sym_ref = { NULL, NULL };
683 /* Nastiness to support underscore prefixes. */
684 #ifdef __UCLIBC_UNDERSCORES__
686 char *name2 = tmp_buf;
687 size_t nlen = strlen (name) + 1;
688 if (nlen + 1 > sizeof (tmp_buf))
689 name2 = malloc (nlen + 1);
691 _dl_error_number = LD_ERROR_MMAP_FAILED;
695 memcpy (name2 + 1, name, nlen);
697 const char *name2 = name;
699 handle = (struct dyn_elf *) vhandle;
701 /* First of all verify that we have a real handle
702 of some kind. Return NULL if not a valid handle. */
705 handle = _dl_symbol_tables;
706 else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
707 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
711 _dl_error_number = LD_BAD_HANDLE;
715 } else if (handle == RTLD_NEXT) {
717 * Try and locate the module we were called from - we
718 * need this so that we know where to start searching
719 * from. We never pass RTLD_NEXT down into the actual
720 * dynamic loader itself, as it doesn't know
721 * how to properly treat it.
723 from = (ElfW(Addr)) caller_address;
726 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
728 if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom)) {
735 if (handle == _dl_symbol_tables)
736 tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
739 ret = _dl_find_hash(name2, &handle->dyn->symbol_scope, tpnt, ELF_RTYPE_CLASS_DLSYM, &sym_ref);
742 handle = handle->next;
743 } while (from && handle);
745 #if defined(USE_TLS) && USE_TLS && defined SHARED
746 if (sym_ref.sym && (ELF_ST_TYPE(sym_ref.sym->st_info) == STT_TLS) && (sym_ref.tpnt)) {
747 /* The found symbol is a thread-local storage variable.
748 Return its address for the current thread. */
749 ret = _dl_tls_symaddr ((struct link_map *)sym_ref.tpnt, (Elf32_Addr)ret);
757 _dl_error_number = LD_NO_SYMBOL;
759 #ifdef __UCLIBC_UNDERSCORES__
760 if (name2 != tmp_buf)
766 void *dlsym(void *vhandle, const char *name)
770 __UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
771 ret = do_dlsym(vhandle, name, __builtin_return_address(0));
772 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
778 void *dlvsym(void *vhandle, const char *name, const char *version)
780 return dlsym(vhandle, name);
784 static int do_dlclose(void *vhandle, int need_fini)
786 struct dyn_elf *rpnt, *rpnt1, *rpnt1_tmp;
787 struct init_fini_list *runp, *tmp;
789 struct elf_resolve *tpnt, *run_tpnt;
790 int (*dl_elf_fini) (void);
791 void (*dl_brk) (void);
792 struct dyn_elf *handle;
793 unsigned int end = 0, start = 0xffffffff;
795 struct r_scope_elem *ls, *ls_next = NULL;
796 struct elf_resolve **handle_rlist;
798 #if defined(USE_TLS) && USE_TLS
799 bool any_tls = false;
800 size_t tls_free_start = NO_TLS_OFFSET;
801 size_t tls_free_end = NO_TLS_OFFSET;
802 struct link_map *tls_lmap;
805 handle = (struct dyn_elf *) vhandle;
806 if (handle == _dl_symbol_tables)
809 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
816 _dl_error_number = LD_BAD_HANDLE;
820 rpnt1->next_handle = rpnt->next_handle;
822 _dl_handles = rpnt->next_handle;
823 _dl_if_debug_print("%s: usage count: %d\n",
824 handle->dyn->libname, handle->dyn->usage_count);
825 if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & RTLD_NODELETE)) {
826 handle->dyn->usage_count--;
831 /* Store the handle's local scope array for later removal */
832 handle_rlist = handle->dyn->symbol_scope.r_list;
834 /* Store references to the local scope entries for later removal */
835 for (ls = &_dl_loaded_modules->symbol_scope; ls && ls->next; ls = ls->next)
836 if (ls->next->r_list[0] == handle->dyn) {
839 /* ls points to the previous local symbol scope */
841 ls_next = ls->next->next;
843 /* OK, this is a valid handle - now close out the file */
844 for (j = 0; j < handle->init_fini.nlist; ++j) {
845 tpnt = handle->init_fini.init_fini[j];
847 if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) {
848 if ((tpnt->dynamic_info[DT_FINI]
849 || tpnt->dynamic_info[DT_FINI_ARRAY])
851 && !(tpnt->init_flag & FINI_FUNCS_CALLED)
853 tpnt->init_flag |= FINI_FUNCS_CALLED;
854 _dl_run_fini_array(tpnt);
856 if (tpnt->dynamic_info[DT_FINI]) {
857 dl_elf_fini = (int (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_FINI]);
858 _dl_if_debug_print("running dtors for library %s at '%p'\n",
859 tpnt->libname, dl_elf_fini);
860 DL_CALL_FUNC_AT_ADDR (dl_elf_fini, tpnt->loadaddr, (int (*)(void)));
864 _dl_if_debug_print("unmapping: %s\n", tpnt->libname);
866 for (i = 0, ppnt = tpnt->ppnt;
867 i < tpnt->n_phent; ppnt++, i++) {
868 if (ppnt->p_type != PT_LOAD)
870 if (ppnt->p_vaddr < start)
871 start = ppnt->p_vaddr;
872 if (end < ppnt->p_vaddr + ppnt->p_memsz)
873 end = ppnt->p_vaddr + ppnt->p_memsz;
876 #if defined(USE_TLS) && USE_TLS
877 /* Do the cast to make things easy. */
878 tls_lmap = (struct link_map *) tpnt;
880 /* Remove the object from the dtv slotinfo array if it uses TLS. */
881 if (__builtin_expect (tls_lmap->l_tls_blocksize > 0, 0)) {
884 if (_dl_tls_dtv_slotinfo_list != NULL
885 && ! remove_slotinfo (tls_lmap->l_tls_modid,
886 _dl_tls_dtv_slotinfo_list, 0,
887 (tpnt->init_flag & INIT_FUNCS_CALLED)))
888 /* All dynamically loaded modules with TLS are unloaded. */
889 _dl_tls_max_dtv_idx = _dl_tls_static_nelem;
891 if (tls_lmap->l_tls_offset != NO_TLS_OFFSET) {
893 * Collect a contiguous chunk built from the objects in
894 * this search list, going in either direction. When the
895 * whole chunk is at the end of the used area then we can
898 # if defined(TLS_TCB_AT_TP)
899 if (tls_free_start == NO_TLS_OFFSET
900 || (size_t) tls_lmap->l_tls_offset == tls_free_start) {
901 /* Extend the contiguous chunk being reclaimed. */
903 = tls_lmap->l_tls_offset -
904 tls_lmap->l_tls_blocksize;
906 if (tls_free_end == NO_TLS_OFFSET)
907 tls_free_end = tls_lmap->l_tls_offset;
908 } else if (tls_lmap->l_tls_offset - tls_lmap->l_tls_blocksize
910 /* Extend the chunk backwards. */
911 tls_free_end = tls_lmap->l_tls_offset;
914 * This isn't contiguous with the last chunk freed.
915 * One of them will be leaked unless we can free
916 * one block right away.
918 if (tls_free_end == _dl_tls_static_used) {
919 _dl_tls_static_used = tls_free_start;
920 tls_free_end = tls_lmap->l_tls_offset;
922 = tls_free_end - tls_lmap->l_tls_blocksize;
923 } else if ((size_t) tls_lmap->l_tls_offset
924 == _dl_tls_static_used)
925 _dl_tls_static_used = tls_lmap->l_tls_offset -
926 tls_lmap->l_tls_blocksize;
927 else if (tls_free_end < (size_t) tls_lmap->l_tls_offset) {
929 * We pick the later block. It has a chance
932 tls_free_end = tls_lmap->l_tls_offset;
933 tls_free_start = tls_free_end -
934 tls_lmap->l_tls_blocksize;
937 # elif defined(TLS_DTV_AT_TP)
938 if ((size_t) tls_lmap->l_tls_offset == tls_free_end)
939 /* Extend the contiguous chunk being reclaimed. */
940 tls_free_end -= tls_lmap->l_tls_blocksize;
941 else if (tls_lmap->l_tls_offset + tls_lmap->l_tls_blocksize
943 /* Extend the chunk backwards. */
944 tls_free_start = tls_lmap->l_tls_offset;
947 * This isn't contiguous with the last chunk
948 * freed. One of them will be leaked.
950 if (tls_free_end == _dl_tls_static_used)
951 _dl_tls_static_used = tls_free_start;
952 tls_free_start = tls_lmap->l_tls_offset;
953 tls_free_end = tls_free_start +
954 tls_lmap->l_tls_blocksize;
957 # error Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined
961 #define TLS_DTV_UNALLOCATED ((void *) -1l)
963 dtv_t *dtv = THREAD_DTV ();
965 _dl_assert(!(dtv[tls_lmap->l_tls_modid].pointer.is_static));
966 if (dtv[tls_lmap->l_tls_modid].pointer.val != TLS_DTV_UNALLOCATED) {
967 /* Note that free is called for NULL is well. We
968 deallocate even if it is this dtv entry we are
969 supposed to load. The reason is that we call
970 memalign and not malloc. */
971 _dl_free (dtv[tls_lmap->l_tls_modid].pointer.val);
972 dtv[tls_lmap->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
978 end = (end + ADDR_ALIGN) & PAGE_ALIGN;
979 start = start & ~ADDR_ALIGN;
980 DL_LIB_UNMAP (tpnt, end - start);
981 /* Free elements in RTLD_LOCAL scope list */
982 for (runp = tpnt->rtld_local; runp; runp = tmp) {
987 /* Next, remove tpnt from the loaded_module list */
988 if (_dl_loaded_modules == tpnt) {
989 _dl_loaded_modules = tpnt->next;
990 if (_dl_loaded_modules)
991 _dl_loaded_modules->prev = 0;
993 for (run_tpnt = _dl_loaded_modules; run_tpnt; run_tpnt = run_tpnt->next) {
994 if (run_tpnt->next == tpnt) {
995 _dl_if_debug_print("removing loaded_modules: %s\n", tpnt->libname);
996 run_tpnt->next = run_tpnt->next->next;
998 run_tpnt->next->prev = run_tpnt;
1004 /* Next, remove tpnt from the global symbol table list */
1005 if (_dl_symbol_tables) {
1006 if (_dl_symbol_tables->dyn == tpnt) {
1007 _dl_symbol_tables = _dl_symbol_tables->next;
1008 if (_dl_symbol_tables)
1009 _dl_symbol_tables->prev = 0;
1011 for (rpnt1 = _dl_symbol_tables; rpnt1->next; rpnt1 = rpnt1->next) {
1012 if (rpnt1->next->dyn == tpnt) {
1013 _dl_if_debug_print("removing symbol_tables: %s\n", tpnt->libname);
1014 rpnt1_tmp = rpnt1->next->next;
1016 rpnt1->next = rpnt1_tmp;
1018 rpnt1->next->prev = rpnt1;
1024 free(tpnt->libname);
1025 if (handle->dyn != tpnt)
1026 free(tpnt->symbol_scope.r_list);
1030 /* Unlink and release the handle's local scope from global one */
1035 for (rpnt1 = handle->next; rpnt1; rpnt1 = rpnt1_tmp) {
1036 rpnt1_tmp = rpnt1->next;
1039 free(handle->init_fini.init_fini);
1042 #if defined(USE_TLS) && USE_TLS
1043 /* If we removed any object which uses TLS bump the generation counter. */
1045 if (__builtin_expect(++_dl_tls_generation == 0, 0)) {
1046 _dl_debug_early("TLS generation counter wrapped! Please report to the uClibc mailing list.\n");
1050 if (tls_free_end == _dl_tls_static_used)
1051 _dl_tls_static_used = tls_free_start;
1055 if (_dl_debug_addr) {
1056 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
1057 if (dl_brk != NULL) {
1058 _dl_debug_addr->r_state = RT_DELETE;
1061 _dl_debug_addr->r_state = RT_CONSISTENT;
1069 int dlclose(void *vhandle)
1073 __UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
1074 ret = do_dlclose(vhandle, 1);
1075 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
1084 if (!_dl_error_number)
1086 retval = dl_error_names[_dl_error_number];
1087 _dl_error_number = 0;
1088 return (char *)retval;
1092 * Dump information to stderr about the current loaded modules
1096 static const char type[][4] = { "Lib", "Exe", "Int", "Mod" };
1098 /* reimplement this, being a GNU extension it should be the same as on glibc */
1101 struct elf_resolve *tpnt;
1102 struct dyn_elf *rpnt, *hpnt;
1104 fprintf(stderr, "List of loaded modules\n");
1105 /* First start with a complete list of all of the loaded files. */
1106 for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
1107 fprintf(stderr, "\t%p %p %p %s %d %s\n",
1108 DL_LOADADDR_BASE(tpnt->loadaddr), tpnt, tpnt->symbol_scope,
1109 type[tpnt->libtype],
1110 tpnt->usage_count, tpnt->libname);
1113 /* Next dump the module list for the application itself */
1114 fprintf(stderr, "\nModules for application (%p):\n", _dl_symbol_tables);
1115 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
1116 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1118 for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
1119 fprintf(stderr, "Modules for handle %p\n", hpnt);
1120 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
1121 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1127 static int do_dladdr(const void *__address, Dl_info * __info)
1129 struct elf_resolve *pelf;
1130 struct elf_resolve *rpnt;
1135 * Try and locate the module address is in
1139 _dl_if_debug_print("__address: %p __info: %p\n", __address, __info);
1141 __address = DL_LOOKUP_ADDRESS (__address);
1143 for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
1144 struct elf_resolve *tpnt;
1148 _dl_if_debug_print("Module \"%s\" at %p\n",
1149 tpnt->libname, DL_LOADADDR_BASE(tpnt->loadaddr));
1151 if (DL_ADDR_IN_LOADADDR((ElfW(Addr)) __address, tpnt, pelf))
1160 * Try and locate the symbol of address
1166 unsigned int hn, si, sn, sf;
1169 /* Set the info for the object the address lies in */
1170 __info->dli_fname = pelf->libname;
1171 __info->dli_fbase = (void *)pelf->mapaddr;
1173 symtab = (ElfW(Sym) *) (pelf->dynamic_info[DT_SYMTAB]);
1174 strtab = (char *) (pelf->dynamic_info[DT_STRTAB]);
1178 #ifdef __LDSO_GNU_HASH_SUPPORT__
1179 if (pelf->l_gnu_bitmask) {
1180 for (hn = 0; hn < pelf->nbucket; hn++) {
1181 si = pelf->l_gnu_buckets[hn];
1185 const Elf32_Word *hasharr = &pelf->l_gnu_chain_zero[si];
1187 ElfW(Addr) symbol_addr;
1189 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1190 if ((symtab[si].st_shndx != SHN_UNDEF
1191 || symtab[si].st_value != 0)
1192 && ELF_ST_TYPE(symtab[si].st_info) != STT_TLS
1193 && DL_ADDR_SYM_MATCH(symbol_addr, &symtab[si], sa,
1194 (ElfW(Addr)) __address)) {
1199 _dl_if_debug_print("Symbol \"%s\" at %p\n", strtab + symtab[si].st_name, symbol_addr);
1201 } while ((*hasharr++ & 1u) == 0);
1205 for (hn = 0; hn < pelf->nbucket; hn++) {
1206 for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
1207 ElfW(Addr) symbol_addr;
1209 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1210 if ((symtab[si].st_shndx != SHN_UNDEF
1211 || symtab[si].st_value != 0)
1212 && ELF_ST_TYPE(symtab[si].st_info) != STT_TLS
1213 && DL_ADDR_SYM_MATCH(symbol_addr, &symtab[si], sa,
1214 (ElfW(Addr)) __address)) {
1220 _dl_if_debug_print("Symbol \"%s\" at %p\n",
1221 strtab + symtab[si].st_name, symbol_addr);
1226 /* A nearest symbol has been found; fill the entries */
1227 __info->dli_sname = strtab + symtab[sn].st_name;
1228 __info->dli_saddr = (void *)sa;
1230 /* No symbol found, fill entries with NULL value,
1231 only the containing object will be returned. */
1232 __info->dli_sname = NULL;
1233 __info->dli_saddr = NULL;
1240 int dladdr(const void *__address, Dl_info * __info)
1244 __UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
1245 ret = do_dladdr(__address, __info);
1246 __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);