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
35 #include <string.h> /* Needed for 'strstr' prototype' */
37 #include <sys/stat.h> // L4 addition but needed for struct stat (?!)
39 #ifdef __UCLIBC_HAS_TLS__
43 #if defined(USE_TLS) && USE_TLS
45 extern void _dl_add_to_slotinfo(struct link_map *l);
49 # if defined(USE_TLS) && USE_TLS
51 extern struct link_map *_dl_update_slotinfo(unsigned long int req_modid);
54 /* When libdl is loaded as a shared library, we need to load in
55 * and use a pile of symbols from ldso... */
57 extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **,
58 struct elf_resolve *, char *, int);
59 extern int _dl_fixup(struct dyn_elf *rpnt, int lazy);
60 extern void _dl_protect_relro(struct elf_resolve * tpnt);
62 extern struct dyn_elf *_dl_symbol_tables;
63 extern struct dyn_elf *_dl_handles;
64 extern struct elf_resolve *_dl_loaded_modules;
65 extern void _dl_free (void *__ptr);
66 extern struct r_debug *_dl_debug_addr;
67 extern unsigned long _dl_error_number;
68 extern void *(*_dl_malloc_function)(size_t);
69 extern void (*_dl_free_function) (void *p);
70 extern void _dl_run_init_array(struct elf_resolve *);
71 extern void _dl_run_fini_array(struct elf_resolve *);
72 #ifdef __LDSO_CACHE_SUPPORT__
73 int _dl_map_cache(void);
74 int _dl_unmap_cache(void);
77 extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy);
79 #ifdef __SUPPORT_LD_DEBUG__
80 extern char *_dl_debug;
85 #define _dl_malloc malloc
88 /* When libdl is linked as a static library, we need to replace all
89 * the symbols that otherwise would have been loaded in from ldso... */
91 #ifdef __SUPPORT_LD_DEBUG__
92 char *_dl_debug = NULL;
93 char *_dl_debug_symbols = NULL;
94 char *_dl_debug_move = NULL;
95 char *_dl_debug_reloc = NULL;
96 char *_dl_debug_detail = NULL;
97 char *_dl_debug_nofixups = NULL;
98 char *_dl_debug_bindings = NULL;
99 int _dl_debug_file /*= 2*/;
101 const char *_dl_progname = ""; /* Program name */
102 void *(*_dl_malloc_function)(size_t);
103 void (*_dl_free_function) (void *p);
104 char *_dl_library_path = NULL; /* Where we look for libraries */
105 char *_dl_ldsopath = NULL; /* Location of the shared lib loader */
106 int _dl_errno = 0; /* We can't use the real errno in ldso */
107 size_t _dl_pagesize = PAGE_SIZE; /* Store the page size for use later */
108 /* This global variable is also to communicate with debuggers such as gdb. */
109 struct r_debug *_dl_debug_addr = NULL;
111 #include "../ldso/dl-array.c"
112 #include "../ldso/dl-debug.c"
115 # if defined(USE_TLS) && USE_TLS
117 * Giving this initialized value preallocates some surplus bytes in the
118 * static TLS area, see __libc_setup_tls (libc-tls.c).
120 size_t _dl_tls_static_size = 2048;
122 #include LDSO_ELFINTERP
123 #include "../ldso/dl-hash.c"
124 #define _dl_trace_loaded_objects 0
125 #include "../ldso/dl-elf.c"
128 #ifdef __SUPPORT_LD_DEBUG__
129 # define _dl_if_debug_print(fmt, args...) \
132 fprintf(stderr, "%s():%i: " fmt, __FUNCTION__, __LINE__, ## args); \
135 # define _dl_if_debug_print(fmt, args...)
138 static int do_dlclose(void *, int need_fini);
141 static const char *const dl_error_names[] = {
144 "Unable to open /dev/zero",
146 #if defined (__i386__)
148 #elif defined (__sparc__)
150 #elif defined (__mc68000__)
153 "Unrecognized binary type",
155 "Not an ELF shared library",
156 "Unable to mmap file",
157 "No dynamic section",
158 "Library contains unsupported TLS",
159 #ifdef ELF_USES_RELOCA
160 "Unable to process REL relocs",
162 "Unable to process RELA relocs",
165 "Unable to resolve symbol"
169 #if defined(USE_TLS) && USE_TLS
172 * Systems which do not have tls_index also probably have to define
173 * DONT_USE_TLS_INDEX.
176 # ifndef __TLS_GET_ADDR
177 # define __TLS_GET_ADDR __tls_get_addr
181 * Return the symbol address given the map of the module it is in and
182 * the symbol record. This is used in dl-sym.c.
186 _dl_tls_symaddr(struct link_map *map, const Elf32_Addr st_value)
188 # ifndef DONT_USE_TLS_INDEX
191 .ti_module = map->l_tls_modid,
192 .ti_offset = st_value
195 return __TLS_GET_ADDR (&tmp);
197 return __TLS_GET_ADDR (map->l_tls_modid, st_value);
202 /* Returns true when a non-empty entry was found. */
204 remove_slotinfo(size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
205 bool should_be_there)
207 if (idx - disp >= listp->len) {
208 if (listp->next == NULL) {
210 * The index is not actually valid in the slotinfo list,
211 * because this object was closed before it was fully set
212 * up due to some error.
214 _dl_assert(!should_be_there);
216 if (remove_slotinfo(idx, listp->next, disp + listp->len,
221 * No non-empty entry. Search from the end of this element's
224 idx = disp + listp->len;
227 struct link_map *old_map = listp->slotinfo[idx - disp].map;
230 * The entry might still be in its unused state if we are
231 * closing an object that wasn't fully set up.
233 if (__builtin_expect(old_map != NULL, 1)) {
234 _dl_assert(old_map->l_tls_modid == idx);
236 /* Mark the entry as unused. */
237 listp->slotinfo[idx - disp].gen = _dl_tls_generation + 1;
238 listp->slotinfo[idx - disp].map = NULL;
242 * If this is not the last currently used entry no need to
245 if (idx != _dl_tls_max_dtv_idx)
249 while (idx - disp > (disp == 0 ? 1 + _dl_tls_static_nelem : 0)) {
252 if (listp->slotinfo[idx - disp].map != NULL) {
253 /* Found a new last used index. */
254 _dl_tls_max_dtv_idx = idx;
259 /* No non-entry in this list element. */
264 void dl_cleanup(void) __attribute__ ((destructor));
265 void dl_cleanup(void)
267 struct dyn_elf *h, *n;
269 for (h = _dl_handles; h; h = n) {
275 /* l4: */ void *dlopen(const char *libname, int flag);
276 void *dlopen(const char *libname, int flag)
278 struct elf_resolve *tpnt, *tfrom;
279 struct dyn_elf *dyn_chain, *rpnt = NULL, *dyn_ptr, *relro_ptr, *handle;
281 struct elf_resolve *tpnt1;
282 void (*dl_brk) (void);
284 struct init_fini_list *tmp, *runp, *runp2, *dep_list;
285 unsigned int nlist, i;
286 struct elf_resolve **init_fini_list;
287 static bool _dl_init;
288 #if defined(USE_TLS) && USE_TLS
289 bool any_tls = false;
292 /* A bit of sanity checking... */
293 if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
294 _dl_error_number = LD_BAD_HANDLE;
298 from = (ElfW(Addr)) __builtin_return_address(0);
302 _dl_malloc_function = malloc;
303 _dl_free_function = free;
305 /* Cover the trivial case first */
307 return _dl_symbol_tables;
310 # ifdef __SUPPORT_LD_DEBUG__
311 _dl_debug = getenv("LD_DEBUG");
313 if (_dl_strstr(_dl_debug, "all")) {
314 _dl_debug_detail = _dl_debug_move = _dl_debug_symbols
315 = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = (void*)1;
317 _dl_debug_detail = strstr(_dl_debug, "detail");
318 _dl_debug_move = strstr(_dl_debug, "move");
319 _dl_debug_symbols = strstr(_dl_debug, "sym");
320 _dl_debug_reloc = strstr(_dl_debug, "reloc");
321 _dl_debug_nofixups = strstr(_dl_debug, "nofix");
322 _dl_debug_bindings = strstr(_dl_debug, "bind");
331 * Try and locate the module we were called from - we
332 * need this so that we get the correct RPATH/RUNPATH. Note that
333 * this is the current behavior under Solaris, but the
334 * ABI+ specifies that we should only use the RPATH from
335 * the application. Thus this may go away at some time
339 struct dyn_elf *dpnt;
341 for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
343 if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom))
347 for (rpnt = _dl_symbol_tables; rpnt && rpnt->next; rpnt = rpnt->next)
351 now_flag = (flag & RTLD_NOW) ? RTLD_NOW : 0;
352 if (getenv("LD_BIND_NOW"))
356 /* When statically linked, the _dl_library_path is not yet initialized */
357 _dl_library_path = getenv("LD_LIBRARY_PATH");
360 /* Try to load the specified library */
361 _dl_if_debug_print("Trying to dlopen '%s', RTLD_GLOBAL:%d RTLD_NOW:%d\n",
362 (char*)libname, (flag & RTLD_GLOBAL ? 1:0), (now_flag & RTLD_NOW ? 1:0));
363 tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname, 0);
369 dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
370 _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
371 dyn_chain->dyn = tpnt;
372 tpnt->rtld_flags |= (flag & RTLD_GLOBAL);
374 dyn_chain->next_handle = _dl_handles;
375 _dl_handles = dyn_ptr = dyn_chain;
377 if (tpnt->usage_count > 1) {
378 _dl_if_debug_print("Lib: %s already opened\n", libname);
379 /* see if there is a handle from a earlier dlopen */
380 for (handle = _dl_handles->next_handle; handle; handle = handle->next_handle) {
381 if (handle->dyn == tpnt) {
382 dyn_chain->init_fini.init_fini = handle->init_fini.init_fini;
383 dyn_chain->init_fini.nlist = handle->init_fini.nlist;
384 for (i = 0; i < dyn_chain->init_fini.nlist; i++)
385 dyn_chain->init_fini.init_fini[i]->rtld_flags |= (flag & RTLD_GLOBAL);
386 dyn_chain->next = handle->next;
393 tpnt->init_flag |= DL_OPENED;
395 _dl_if_debug_print("Looking for needed libraries\n");
397 runp = alloca(sizeof(*runp));
400 dep_list = runp2 = runp;
401 for (; runp; runp = runp->next) {
406 runp->tpnt->init_fini = NULL; /* clear any previous dependcies */
407 for (dpnt = (ElfW(Dyn) *) runp->tpnt->dynamic_addr; dpnt->d_tag; dpnt++) {
408 if (dpnt->d_tag == DT_NEEDED) {
409 lpntstr = (char*) (runp->tpnt->dynamic_info[DT_STRTAB] +
411 _dl_if_debug_print("Trying to load '%s', needed by '%s'\n",
412 lpntstr, runp->tpnt->libname);
413 tpnt1 = _dl_load_shared_library(0, &rpnt, runp->tpnt, lpntstr, 0);
417 tpnt1->rtld_flags |= (flag & RTLD_GLOBAL);
419 /* This list is for dlsym() and relocation */
420 dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
421 _dl_memset (dyn_ptr->next, 0, sizeof (struct dyn_elf));
422 dyn_ptr = dyn_ptr->next;
423 dyn_ptr->dyn = tpnt1;
424 /* Used to record RTLD_LOCAL scope */
425 tmp = alloca(sizeof(struct init_fini_list));
427 tmp->next = runp->tpnt->init_fini;
428 runp->tpnt->init_fini = tmp;
430 for (tmp=dep_list; tmp; tmp = tmp->next) {
431 if (tpnt1 == tmp->tpnt) { /* if match => cirular dependency, drop it */
432 _dl_if_debug_print("Circular dependency, skipping '%s',\n",
434 tpnt1->usage_count--;
438 if (!tmp) { /* Don't add if circular dependency detected */
439 runp2->next = alloca(sizeof(*runp));
447 init_fini_list = malloc(nlist * sizeof(struct elf_resolve *));
448 dyn_chain->init_fini.init_fini = init_fini_list;
449 dyn_chain->init_fini.nlist = nlist;
451 for (runp2 = dep_list; runp2; runp2 = runp2->next) {
452 init_fini_list[i++] = runp2->tpnt;
453 for (runp = runp2->tpnt->init_fini; runp; runp = runp->next) {
454 if (!(runp->tpnt->rtld_flags & RTLD_GLOBAL)) {
455 tmp = malloc(sizeof(struct init_fini_list));
456 tmp->tpnt = runp->tpnt;
457 tmp->next = runp2->tpnt->rtld_local;
458 runp2->tpnt->rtld_local = tmp;
463 /* Sort the INIT/FINI list in dependency order. */
464 for (runp2 = dep_list; runp2; runp2 = runp2->next) {
466 for (j = 0; init_fini_list[j] != runp2->tpnt; ++j)
468 for (k = j + 1; k < nlist; ++k) {
469 struct init_fini_list *ele = init_fini_list[k]->init_fini;
471 for (; ele; ele = ele->next) {
472 if (ele->tpnt == runp2->tpnt) {
473 struct elf_resolve *here = init_fini_list[k];
474 _dl_if_debug_print("Move %s from pos %d to %d in INIT/FINI list.\n", here->libname, k, j);
475 for (i = (k - j); i; --i)
476 init_fini_list[i+j] = init_fini_list[i+j-1];
477 init_fini_list[j] = here;
484 #ifdef __SUPPORT_LD_DEBUG__
486 fprintf(stderr, "\nINIT/FINI order and dependencies:\n");
487 for (i = 0; i < nlist; i++) {
488 fprintf(stderr, "lib: %s has deps:\n", init_fini_list[i]->libname);
489 runp = init_fini_list[i]->init_fini;
490 for (; runp; runp = runp->next)
491 fprintf(stderr, " %s ", runp->tpnt->libname);
492 fprintf(stderr, "\n");
497 _dl_if_debug_print("Beginning dlopen relocation fixups\n");
499 * OK, now all of the kids are tucked into bed in their proper addresses.
500 * Now we go through and look for REL and RELA records that indicate fixups
501 * to the GOT tables. We need to do this in reverse order so that COPY
502 * directives work correctly */
505 * Relocation of the GOT entries for MIPS have to be done
506 * after all the libraries have been loaded.
508 _dl_perform_mips_global_got_relocations(tpnt, !now_flag);
511 if (_dl_fixup(dyn_chain, now_flag))
515 for (rpnt = relro_ptr->next; rpnt; rpnt = rpnt->next) {
516 if (rpnt->dyn->relro_size)
517 _dl_protect_relro(rpnt->dyn);
520 /* TODO: Should we set the protections of all pages back to R/O now ? */
523 #if defined(USE_TLS) && USE_TLS
525 for (i=0; i < nlist; i++) {
526 struct elf_resolve *tmp_tpnt = init_fini_list[i];
527 /* Only add TLS memory if this object is loaded now and
528 therefore is not yet initialized. */
530 if (!(tmp_tpnt->init_flag & INIT_FUNCS_CALLED)
531 /* Only if the module defines thread local data. */
532 && __builtin_expect (tmp_tpnt->l_tls_blocksize > 0, 0)) {
534 /* Now that we know the object is loaded successfully add
535 modules containing TLS data to the slot info table. We
536 might have to increase its size. */
537 _dl_add_to_slotinfo ((struct link_map*)tmp_tpnt);
539 /* It is the case in which we couldn't perform TLS static
540 initialization at relocation time, and we delayed it until
541 the relocation has been completed. */
543 if (tmp_tpnt->l_need_tls_init) {
544 tmp_tpnt->l_need_tls_init = 0;
546 /* Update the slot information data for at least the
547 generation of the DSO we are allocating data for. */
548 _dl_update_slotinfo (tmp_tpnt->l_tls_modid);
551 _dl_init_static_tls((struct link_map*)tmp_tpnt);
552 _dl_assert (tmp_tpnt->l_need_tls_init == 0);
555 /* We have to bump the generation counter. */
560 /* Bump the generation number if necessary. */
561 if (any_tls && __builtin_expect (++_dl_tls_generation == 0, 0)) {
562 _dl_debug_early("TLS generation counter wrapped! Please report this.");
568 /* Notify the debugger we have added some objects. */
569 if (_dl_debug_addr) {
570 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
571 if (dl_brk != NULL) {
572 _dl_debug_addr->r_state = RT_ADD;
575 _dl_debug_addr->r_state = RT_CONSISTENT;
580 /* Run the ctors and setup the dtors */
581 for (i = nlist; i; --i) {
582 tpnt = init_fini_list[i-1];
583 if (tpnt->init_flag & INIT_FUNCS_CALLED)
585 tpnt->init_flag |= INIT_FUNCS_CALLED;
587 if (tpnt->dynamic_info[DT_INIT]) {
588 void (*dl_elf_func) (void);
589 dl_elf_func = (void (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_INIT]);
591 _dl_if_debug_print("running ctors for library %s at '%p'\n",
592 tpnt->libname, dl_elf_func);
593 DL_CALL_FUNC_AT_ADDR (dl_elf_func, tpnt->loadaddr, (void(*)(void)));
597 _dl_run_init_array(tpnt);
601 return (void *) dyn_chain;
604 /* Something went wrong. Clean up and return NULL. */
606 do_dlclose(dyn_chain, 0);
610 /* l4: */ void *dlsym(void *vhandle, const char *name);
611 void *dlsym(void *vhandle, const char *name)
613 struct elf_resolve *tpnt, *tfrom;
614 struct dyn_elf *handle;
616 struct dyn_elf *rpnt;
618 struct elf_resolve *tls_tpnt = NULL;
619 /* Nastiness to support underscore prefixes. */
620 #ifdef __UCLIBC_UNDERSCORES__
622 char *name2 = tmp_buf;
623 size_t nlen = strlen (name) + 1;
624 if (nlen + 1 > sizeof (tmp_buf))
625 name2 = malloc (nlen + 1);
627 _dl_error_number = LD_ERROR_MMAP_FAILED;
631 memcpy (name2 + 1, name, nlen);
633 const char *name2 = name;
635 handle = (struct dyn_elf *) vhandle;
637 /* First of all verify that we have a real handle
638 of some kind. Return NULL if not a valid handle. */
641 handle = _dl_symbol_tables;
642 else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
643 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
647 _dl_error_number = LD_BAD_HANDLE;
651 } else if (handle == RTLD_NEXT) {
653 * Try and locate the module we were called from - we
654 * need this so that we know where to start searching
655 * from. We never pass RTLD_NEXT down into the actual
656 * dynamic loader itself, as it doesn't know
657 * how to properly treat it.
659 from = (ElfW(Addr)) __builtin_return_address(0);
662 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
664 if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom)) {
671 if (handle == _dl_symbol_tables)
672 tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
673 ret = _dl_find_hash(name2, handle, NULL, 0, &tls_tpnt);
675 #if defined(USE_TLS) && USE_TLS && defined SHARED
677 /* The found symbol is a thread-local storage variable.
678 Return the address for to the current thread. */
679 ret = _dl_tls_symaddr ((struct link_map *)tls_tpnt, (Elf32_Addr)ret);
687 _dl_error_number = LD_NO_SYMBOL;
689 #ifdef __UCLIBC_UNDERSCORES__
690 if (name2 != tmp_buf)
697 void *dlvsym(void *vhandle, const char *name, const char *version)
699 return dlsym(vhandle, name);
703 static int do_dlclose(void *vhandle, int need_fini)
705 struct dyn_elf *rpnt, *rpnt1, *rpnt1_tmp;
706 struct init_fini_list *runp, *tmp;
708 struct elf_resolve *tpnt, *run_tpnt;
709 int (*dl_elf_fini) (void);
710 void (*dl_brk) (void);
711 struct dyn_elf *handle;
714 #if defined(USE_TLS) && USE_TLS
715 bool any_tls = false;
716 size_t tls_free_start = NO_TLS_OFFSET;
717 size_t tls_free_end = NO_TLS_OFFSET;
718 struct link_map *tls_lmap;
721 handle = (struct dyn_elf *) vhandle;
722 if (handle == _dl_symbol_tables)
725 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
732 _dl_error_number = LD_BAD_HANDLE;
736 rpnt1->next_handle = rpnt->next_handle;
738 _dl_handles = rpnt->next_handle;
739 _dl_if_debug_print("%s: usage count: %d\n",
740 handle->dyn->libname, handle->dyn->usage_count);
741 if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & RTLD_NODELETE)) {
742 handle->dyn->usage_count--;
746 /* OK, this is a valid handle - now close out the file */
747 for (j = 0; j < handle->init_fini.nlist; ++j) {
748 tpnt = handle->init_fini.init_fini[j];
750 if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) {
751 if ((tpnt->dynamic_info[DT_FINI]
752 || tpnt->dynamic_info[DT_FINI_ARRAY])
754 && !(tpnt->init_flag & FINI_FUNCS_CALLED)
756 tpnt->init_flag |= FINI_FUNCS_CALLED;
757 _dl_run_fini_array(tpnt);
759 if (tpnt->dynamic_info[DT_FINI]) {
760 dl_elf_fini = (int (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_FINI]);
761 _dl_if_debug_print("running dtors for library %s at '%p'\n",
762 tpnt->libname, dl_elf_fini);
763 DL_CALL_FUNC_AT_ADDR (dl_elf_fini, tpnt->loadaddr, (int (*)(void)));
767 _dl_if_debug_print("unmapping: %s\n", tpnt->libname);
769 for (i = 0, ppnt = tpnt->ppnt;
770 i < tpnt->n_phent; ppnt++, i++) {
771 if (ppnt->p_type != PT_LOAD)
773 if (end < ppnt->p_vaddr + ppnt->p_memsz)
774 end = ppnt->p_vaddr + ppnt->p_memsz;
777 #if defined(USE_TLS) && USE_TLS
778 /* Do the cast to make things easy. */
779 tls_lmap = (struct link_map *) tpnt;
781 /* Remove the object from the dtv slotinfo array if it uses TLS. */
782 if (__builtin_expect (tls_lmap->l_tls_blocksize > 0, 0)) {
785 if (_dl_tls_dtv_slotinfo_list != NULL
786 && ! remove_slotinfo (tls_lmap->l_tls_modid,
787 _dl_tls_dtv_slotinfo_list, 0,
788 (tpnt->init_flag & INIT_FUNCS_CALLED)))
789 /* All dynamically loaded modules with TLS are unloaded. */
790 _dl_tls_max_dtv_idx = _dl_tls_static_nelem;
792 if (tls_lmap->l_tls_offset != NO_TLS_OFFSET) {
794 * Collect a contiguous chunk built from the objects in
795 * this search list, going in either direction. When the
796 * whole chunk is at the end of the used area then we can
799 # if defined(TLS_TCB_AT_TP)
800 if (tls_free_start == NO_TLS_OFFSET
801 || (size_t) tls_lmap->l_tls_offset == tls_free_start) {
802 /* Extend the contiguous chunk being reclaimed. */
804 = tls_lmap->l_tls_offset -
805 tls_lmap->l_tls_blocksize;
807 if (tls_free_end == NO_TLS_OFFSET)
808 tls_free_end = tls_lmap->l_tls_offset;
809 } else if (tls_lmap->l_tls_offset - tls_lmap->l_tls_blocksize
811 /* Extend the chunk backwards. */
812 tls_free_end = tls_lmap->l_tls_offset;
815 * This isn't contiguous with the last chunk freed.
816 * One of them will be leaked unless we can free
817 * one block right away.
819 if (tls_free_end == _dl_tls_static_used) {
820 _dl_tls_static_used = tls_free_start;
821 tls_free_end = tls_lmap->l_tls_offset;
823 = tls_free_end - tls_lmap->l_tls_blocksize;
824 } else if ((size_t) tls_lmap->l_tls_offset
825 == _dl_tls_static_used)
826 _dl_tls_static_used = tls_lmap->l_tls_offset -
827 tls_lmap->l_tls_blocksize;
828 else if (tls_free_end < (size_t) tls_lmap->l_tls_offset) {
830 * We pick the later block. It has a chance
833 tls_free_end = tls_lmap->l_tls_offset;
834 tls_free_start = tls_free_end -
835 tls_lmap->l_tls_blocksize;
838 # elif defined(TLS_DTV_AT_TP)
839 if ((size_t) tls_lmap->l_tls_offset == tls_free_end)
840 /* Extend the contiguous chunk being reclaimed. */
841 tls_free_end -= tls_lmap->l_tls_blocksize;
842 else if (tls_lmap->l_tls_offset + tls_lmap->l_tls_blocksize
844 /* Extend the chunk backwards. */
845 tls_free_start = tls_lmap->l_tls_offset;
848 * This isn't contiguous with the last chunk
849 * freed. One of them will be leaked.
851 if (tls_free_end == _dl_tls_static_used)
852 _dl_tls_static_used = tls_free_start;
853 tls_free_start = tls_lmap->l_tls_offset;
854 tls_free_end = tls_free_start +
855 tls_lmap->l_tls_blocksize;
858 # error Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined
862 #define TLS_DTV_UNALLOCATED ((void *) -1l)
864 dtv_t *dtv = THREAD_DTV ();
866 _dl_assert(!(dtv[tls_lmap->l_tls_modid].pointer.is_static));
867 if (dtv[tls_lmap->l_tls_modid].pointer.val != TLS_DTV_UNALLOCATED) {
868 /* Note that free is called for NULL is well. We
869 deallocate even if it is this dtv entry we are
870 supposed to load. The reason is that we call
871 memalign and not malloc. */
872 _dl_free (dtv[tls_lmap->l_tls_modid].pointer.val);
873 dtv[tls_lmap->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
879 DL_LIB_UNMAP (tpnt, end);
880 /* Free elements in RTLD_LOCAL scope list */
881 for (runp = tpnt->rtld_local; runp; runp = tmp) {
886 /* Next, remove tpnt from the loaded_module list */
887 if (_dl_loaded_modules == tpnt) {
888 _dl_loaded_modules = tpnt->next;
889 if (_dl_loaded_modules)
890 _dl_loaded_modules->prev = 0;
892 for (run_tpnt = _dl_loaded_modules; run_tpnt; run_tpnt = run_tpnt->next) {
893 if (run_tpnt->next == tpnt) {
894 _dl_if_debug_print("removing loaded_modules: %s\n", tpnt->libname);
895 run_tpnt->next = run_tpnt->next->next;
897 run_tpnt->next->prev = run_tpnt;
903 /* Next, remove tpnt from the global symbol table list */
904 if (_dl_symbol_tables) {
905 if (_dl_symbol_tables->dyn == tpnt) {
906 _dl_symbol_tables = _dl_symbol_tables->next;
907 if (_dl_symbol_tables)
908 _dl_symbol_tables->prev = 0;
910 for (rpnt1 = _dl_symbol_tables; rpnt1->next; rpnt1 = rpnt1->next) {
911 if (rpnt1->next->dyn == tpnt) {
912 _dl_if_debug_print("removing symbol_tables: %s\n", tpnt->libname);
913 rpnt1_tmp = rpnt1->next->next;
915 rpnt1->next = rpnt1_tmp;
917 rpnt1->next->prev = rpnt1;
927 free(handle->init_fini.init_fini);
930 #if defined(USE_TLS) && USE_TLS
931 /* If we removed any object which uses TLS bump the generation counter. */
933 if (__builtin_expect(++_dl_tls_generation == 0, 0)) {
934 _dl_debug_early("TLS generation counter wrapped! Please report to the uClibc mailing list.\n");
938 if (tls_free_end == _dl_tls_static_used)
939 _dl_tls_static_used = tls_free_start;
943 if (_dl_debug_addr) {
944 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
945 if (dl_brk != NULL) {
946 _dl_debug_addr->r_state = RT_DELETE;
949 _dl_debug_addr->r_state = RT_CONSISTENT;
957 /* l4: */ int dlclose(void *vhandle);
958 int dlclose(void *vhandle)
960 return do_dlclose(vhandle, 1);
963 /* l4: */ char *dlerror(void);
968 if (!_dl_error_number)
970 retval = dl_error_names[_dl_error_number];
971 _dl_error_number = 0;
972 return (char *)retval;
976 * Dump information to stderr about the current loaded modules
979 static const char type[][4] = { "Lib", "Exe", "Int", "Mod" };
981 /* l4: */int dlinfo(void);
984 struct elf_resolve *tpnt;
985 struct dyn_elf *rpnt, *hpnt;
987 fprintf(stderr, "List of loaded modules\n");
988 /* First start with a complete list of all of the loaded files. */
989 for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
990 fprintf(stderr, "\t%p %p %p %s %d %s\n",
991 (void *)DL_LOADADDR_BASE(tpnt->loadaddr), tpnt, tpnt->symbol_scope,
993 tpnt->usage_count, tpnt->libname);
996 /* Next dump the module list for the application itself */
997 fprintf(stderr, "\nModules for application (%p):\n", _dl_symbol_tables);
998 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
999 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1001 for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
1002 fprintf(stderr, "Modules for handle %p\n", hpnt);
1003 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
1004 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1009 /* l4: */int dladdr(const void *__address, Dl_info * __info);
1010 int dladdr(const void *__address, Dl_info * __info)
1012 struct elf_resolve *pelf;
1013 struct elf_resolve *rpnt;
1018 * Try and locate the module address is in
1022 _dl_if_debug_print("__address: %p __info: %p\n", __address, __info);
1024 __address = DL_LOOKUP_ADDRESS (__address);
1026 for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
1027 struct elf_resolve *tpnt;
1031 _dl_if_debug_print("Module \"%s\" at %p\n",
1032 tpnt->libname, (void *)DL_LOADADDR_BASE(tpnt->loadaddr));
1034 if (DL_ADDR_IN_LOADADDR((ElfW(Addr)) __address, tpnt, pelf))
1043 * Try and locate the symbol of address
1049 unsigned int hn, si, sn, sf;
1052 /* Set the info for the object the address lies in */
1053 __info->dli_fname = pelf->libname;
1054 __info->dli_fbase = (void *)pelf->mapaddr;
1056 symtab = (ElfW(Sym) *) (pelf->dynamic_info[DT_SYMTAB]);
1057 strtab = (char *) (pelf->dynamic_info[DT_STRTAB]);
1061 #ifdef __LDSO_GNU_HASH_SUPPORT__
1062 if (pelf->l_gnu_bitmask) {
1063 for (hn = 0; hn < pelf->nbucket; hn++) {
1064 si = pelf->l_gnu_buckets[hn];
1068 const Elf32_Word *hasharr = &pelf->l_gnu_chain_zero[si];
1070 ElfW(Addr) symbol_addr;
1072 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1073 if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
1078 _dl_if_debug_print("Symbol \"%s\" at %p\n", strtab + symtab[si].st_name, (void *)symbol_addr);
1080 } while ((*hasharr++ & 1u) == 0);
1084 for (hn = 0; hn < pelf->nbucket; hn++) {
1085 for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
1086 ElfW(Addr) symbol_addr;
1088 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1089 if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
1095 _dl_if_debug_print("Symbol \"%s\" at %p\n",
1096 strtab + symtab[si].st_name, (void *)symbol_addr);
1101 /* A nearest symbol has been found; fill the entries */
1102 __info->dli_sname = strtab + symtab[sn].st_name;
1103 __info->dli_saddr = (void *)sa;
1105 /* No symbol found, fill entries with NULL value,
1106 only the containing object will be returned. */
1107 __info->dli_sname = NULL;
1108 __info->dli_saddr = NULL;