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 */
308 // L4: Fix the case that a static program does not have a symbol table for
309 // the main program but needs to set the error code. LD_NO_SYMBOL has been
310 // taken because it sounds useful for that case. glibc does seem to have a
311 // rather strange handling in the static case.
313 return _dl_symbol_tables;
315 _dl_error_number = LD_NO_SYMBOL;
321 # ifdef __SUPPORT_LD_DEBUG__
322 _dl_debug = getenv("LD_DEBUG");
324 if (_dl_strstr(_dl_debug, "all")) {
325 _dl_debug_detail = _dl_debug_move = _dl_debug_symbols
326 = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = (void*)1;
328 _dl_debug_detail = strstr(_dl_debug, "detail");
329 _dl_debug_move = strstr(_dl_debug, "move");
330 _dl_debug_symbols = strstr(_dl_debug, "sym");
331 _dl_debug_reloc = strstr(_dl_debug, "reloc");
332 _dl_debug_nofixups = strstr(_dl_debug, "nofix");
333 _dl_debug_bindings = strstr(_dl_debug, "bind");
342 * Try and locate the module we were called from - we
343 * need this so that we get the correct RPATH/RUNPATH. Note that
344 * this is the current behavior under Solaris, but the
345 * ABI+ specifies that we should only use the RPATH from
346 * the application. Thus this may go away at some time
350 struct dyn_elf *dpnt;
352 for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
354 if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom))
358 for (rpnt = _dl_symbol_tables; rpnt && rpnt->next; rpnt = rpnt->next)
362 now_flag = (flag & RTLD_NOW) ? RTLD_NOW : 0;
363 if (getenv("LD_BIND_NOW"))
367 /* When statically linked, the _dl_library_path is not yet initialized */
368 _dl_library_path = getenv("LD_LIBRARY_PATH");
371 /* Try to load the specified library */
372 _dl_if_debug_print("Trying to dlopen '%s', RTLD_GLOBAL:%d RTLD_NOW:%d\n",
373 (char*)libname, (flag & RTLD_GLOBAL ? 1:0), (now_flag & RTLD_NOW ? 1:0));
374 tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname, 0);
380 dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
381 _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
382 dyn_chain->dyn = tpnt;
383 tpnt->rtld_flags |= (flag & RTLD_GLOBAL);
385 dyn_chain->next_handle = _dl_handles;
386 _dl_handles = dyn_ptr = dyn_chain;
388 if (tpnt->usage_count > 1) {
389 _dl_if_debug_print("Lib: %s already opened\n", libname);
390 /* see if there is a handle from a earlier dlopen */
391 for (handle = _dl_handles->next_handle; handle; handle = handle->next_handle) {
392 if (handle->dyn == tpnt) {
393 dyn_chain->init_fini.init_fini = handle->init_fini.init_fini;
394 dyn_chain->init_fini.nlist = handle->init_fini.nlist;
395 for (i = 0; i < dyn_chain->init_fini.nlist; i++)
396 dyn_chain->init_fini.init_fini[i]->rtld_flags |= (flag & RTLD_GLOBAL);
397 dyn_chain->next = handle->next;
404 tpnt->init_flag |= DL_OPENED;
406 _dl_if_debug_print("Looking for needed libraries\n");
408 runp = alloca(sizeof(*runp));
411 dep_list = runp2 = runp;
412 for (; runp; runp = runp->next) {
417 runp->tpnt->init_fini = NULL; /* clear any previous dependcies */
418 for (dpnt = (ElfW(Dyn) *) runp->tpnt->dynamic_addr; dpnt->d_tag; dpnt++) {
419 if (dpnt->d_tag == DT_NEEDED) {
420 lpntstr = (char*) (runp->tpnt->dynamic_info[DT_STRTAB] +
422 _dl_if_debug_print("Trying to load '%s', needed by '%s'\n",
423 lpntstr, runp->tpnt->libname);
424 tpnt1 = _dl_load_shared_library(0, &rpnt, runp->tpnt, lpntstr, 0);
428 tpnt1->rtld_flags |= (flag & RTLD_GLOBAL);
430 /* This list is for dlsym() and relocation */
431 dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
432 _dl_memset (dyn_ptr->next, 0, sizeof (struct dyn_elf));
433 dyn_ptr = dyn_ptr->next;
434 dyn_ptr->dyn = tpnt1;
435 /* Used to record RTLD_LOCAL scope */
436 tmp = alloca(sizeof(struct init_fini_list));
438 tmp->next = runp->tpnt->init_fini;
439 runp->tpnt->init_fini = tmp;
441 for (tmp=dep_list; tmp; tmp = tmp->next) {
442 if (tpnt1 == tmp->tpnt) { /* if match => cirular dependency, drop it */
443 _dl_if_debug_print("Circular dependency, skipping '%s',\n",
445 tpnt1->usage_count--;
449 if (!tmp) { /* Don't add if circular dependency detected */
450 runp2->next = alloca(sizeof(*runp));
458 init_fini_list = malloc(nlist * sizeof(struct elf_resolve *));
459 dyn_chain->init_fini.init_fini = init_fini_list;
460 dyn_chain->init_fini.nlist = nlist;
462 for (runp2 = dep_list; runp2; runp2 = runp2->next) {
463 init_fini_list[i++] = runp2->tpnt;
464 for (runp = runp2->tpnt->init_fini; runp; runp = runp->next) {
465 if (!(runp->tpnt->rtld_flags & RTLD_GLOBAL)) {
466 tmp = malloc(sizeof(struct init_fini_list));
467 tmp->tpnt = runp->tpnt;
468 tmp->next = runp2->tpnt->rtld_local;
469 runp2->tpnt->rtld_local = tmp;
474 /* Sort the INIT/FINI list in dependency order. */
475 for (runp2 = dep_list; runp2; runp2 = runp2->next) {
477 for (j = 0; init_fini_list[j] != runp2->tpnt; ++j)
479 for (k = j + 1; k < nlist; ++k) {
480 struct init_fini_list *ele = init_fini_list[k]->init_fini;
482 for (; ele; ele = ele->next) {
483 if (ele->tpnt == runp2->tpnt) {
484 struct elf_resolve *here = init_fini_list[k];
485 _dl_if_debug_print("Move %s from pos %d to %d in INIT/FINI list.\n", here->libname, k, j);
486 for (i = (k - j); i; --i)
487 init_fini_list[i+j] = init_fini_list[i+j-1];
488 init_fini_list[j] = here;
495 #ifdef __SUPPORT_LD_DEBUG__
497 fprintf(stderr, "\nINIT/FINI order and dependencies:\n");
498 for (i = 0; i < nlist; i++) {
499 fprintf(stderr, "lib: %s has deps:\n", init_fini_list[i]->libname);
500 runp = init_fini_list[i]->init_fini;
501 for (; runp; runp = runp->next)
502 fprintf(stderr, " %s ", runp->tpnt->libname);
503 fprintf(stderr, "\n");
508 _dl_if_debug_print("Beginning dlopen relocation fixups\n");
510 * OK, now all of the kids are tucked into bed in their proper addresses.
511 * Now we go through and look for REL and RELA records that indicate fixups
512 * to the GOT tables. We need to do this in reverse order so that COPY
513 * directives work correctly */
516 * Relocation of the GOT entries for MIPS have to be done
517 * after all the libraries have been loaded.
519 _dl_perform_mips_global_got_relocations(tpnt, !now_flag);
522 if (_dl_fixup(dyn_chain, now_flag))
526 for (rpnt = relro_ptr->next; rpnt; rpnt = rpnt->next) {
527 if (rpnt->dyn->relro_size)
528 _dl_protect_relro(rpnt->dyn);
531 /* TODO: Should we set the protections of all pages back to R/O now ? */
534 #if defined(USE_TLS) && USE_TLS
536 for (i=0; i < nlist; i++) {
537 struct elf_resolve *tmp_tpnt = init_fini_list[i];
538 /* Only add TLS memory if this object is loaded now and
539 therefore is not yet initialized. */
541 if (!(tmp_tpnt->init_flag & INIT_FUNCS_CALLED)
542 /* Only if the module defines thread local data. */
543 && __builtin_expect (tmp_tpnt->l_tls_blocksize > 0, 0)) {
545 /* Now that we know the object is loaded successfully add
546 modules containing TLS data to the slot info table. We
547 might have to increase its size. */
548 _dl_add_to_slotinfo ((struct link_map*)tmp_tpnt);
550 /* It is the case in which we couldn't perform TLS static
551 initialization at relocation time, and we delayed it until
552 the relocation has been completed. */
554 if (tmp_tpnt->l_need_tls_init) {
555 tmp_tpnt->l_need_tls_init = 0;
557 /* Update the slot information data for at least the
558 generation of the DSO we are allocating data for. */
559 _dl_update_slotinfo (tmp_tpnt->l_tls_modid);
562 _dl_init_static_tls((struct link_map*)tmp_tpnt);
563 _dl_assert (tmp_tpnt->l_need_tls_init == 0);
566 /* We have to bump the generation counter. */
571 /* Bump the generation number if necessary. */
572 if (any_tls && __builtin_expect (++_dl_tls_generation == 0, 0)) {
573 _dl_debug_early("TLS generation counter wrapped! Please report this.");
579 /* Notify the debugger we have added some objects. */
580 if (_dl_debug_addr) {
581 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
582 if (dl_brk != NULL) {
583 _dl_debug_addr->r_state = RT_ADD;
586 _dl_debug_addr->r_state = RT_CONSISTENT;
591 /* Run the ctors and setup the dtors */
592 for (i = nlist; i; --i) {
593 tpnt = init_fini_list[i-1];
594 if (tpnt->init_flag & INIT_FUNCS_CALLED)
596 tpnt->init_flag |= INIT_FUNCS_CALLED;
598 if (tpnt->dynamic_info[DT_INIT]) {
599 void (*dl_elf_func) (void);
600 dl_elf_func = (void (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_INIT]);
602 _dl_if_debug_print("running ctors for library %s at '%p'\n",
603 tpnt->libname, dl_elf_func);
604 DL_CALL_FUNC_AT_ADDR (dl_elf_func, tpnt->loadaddr, (void(*)(void)));
608 _dl_run_init_array(tpnt);
612 return (void *) dyn_chain;
615 /* Something went wrong. Clean up and return NULL. */
617 do_dlclose(dyn_chain, 0);
621 /* l4: */ void *dlsym(void *vhandle, const char *name);
622 void *dlsym(void *vhandle, const char *name)
624 struct elf_resolve *tpnt, *tfrom;
625 struct dyn_elf *handle;
627 struct dyn_elf *rpnt;
629 struct symbol_ref sym_ref = { NULL, NULL };
630 /* Nastiness to support underscore prefixes. */
631 #ifdef __UCLIBC_UNDERSCORES__
633 char *name2 = tmp_buf;
634 size_t nlen = strlen (name) + 1;
635 if (nlen + 1 > sizeof (tmp_buf))
636 name2 = malloc (nlen + 1);
638 _dl_error_number = LD_ERROR_MMAP_FAILED;
642 memcpy (name2 + 1, name, nlen);
644 const char *name2 = name;
646 handle = (struct dyn_elf *) vhandle;
648 /* First of all verify that we have a real handle
649 of some kind. Return NULL if not a valid handle. */
652 handle = _dl_symbol_tables;
653 else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
654 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
658 _dl_error_number = LD_BAD_HANDLE;
662 } else if (handle == RTLD_NEXT) {
664 * Try and locate the module we were called from - we
665 * need this so that we know where to start searching
666 * from. We never pass RTLD_NEXT down into the actual
667 * dynamic loader itself, as it doesn't know
668 * how to properly treat it.
670 from = (ElfW(Addr)) __builtin_return_address(0);
673 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
675 if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom)) {
682 if (handle == _dl_symbol_tables)
683 tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
684 ret = _dl_find_hash(name2, handle, tpnt, 0, &sym_ref);
686 #if defined(USE_TLS) && USE_TLS && defined SHARED
688 /* The found symbol is a thread-local storage variable.
689 Return the address for to the current thread. */
690 ret = _dl_tls_symaddr ((struct link_map *)sym_ref.tpnt, (Elf32_Addr)ret);
698 _dl_error_number = LD_NO_SYMBOL;
700 #ifdef __UCLIBC_UNDERSCORES__
701 if (name2 != tmp_buf)
708 void *dlvsym(void *vhandle, const char *name, const char *version)
710 return dlsym(vhandle, name);
714 static int do_dlclose(void *vhandle, int need_fini)
716 struct dyn_elf *rpnt, *rpnt1, *rpnt1_tmp;
717 struct init_fini_list *runp, *tmp;
719 struct elf_resolve *tpnt, *run_tpnt;
720 int (*dl_elf_fini) (void);
721 void (*dl_brk) (void);
722 struct dyn_elf *handle;
725 #if defined(USE_TLS) && USE_TLS
726 bool any_tls = false;
727 size_t tls_free_start = NO_TLS_OFFSET;
728 size_t tls_free_end = NO_TLS_OFFSET;
729 struct link_map *tls_lmap;
732 handle = (struct dyn_elf *) vhandle;
733 if (handle == _dl_symbol_tables)
736 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
743 _dl_error_number = LD_BAD_HANDLE;
747 rpnt1->next_handle = rpnt->next_handle;
749 _dl_handles = rpnt->next_handle;
750 _dl_if_debug_print("%s: usage count: %d\n",
751 handle->dyn->libname, handle->dyn->usage_count);
752 if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & RTLD_NODELETE)) {
753 handle->dyn->usage_count--;
757 /* OK, this is a valid handle - now close out the file */
758 for (j = 0; j < handle->init_fini.nlist; ++j) {
759 tpnt = handle->init_fini.init_fini[j];
761 if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) {
762 if ((tpnt->dynamic_info[DT_FINI]
763 || tpnt->dynamic_info[DT_FINI_ARRAY])
765 && !(tpnt->init_flag & FINI_FUNCS_CALLED)
767 tpnt->init_flag |= FINI_FUNCS_CALLED;
768 _dl_run_fini_array(tpnt);
770 if (tpnt->dynamic_info[DT_FINI]) {
771 dl_elf_fini = (int (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_FINI]);
772 _dl_if_debug_print("running dtors for library %s at '%p'\n",
773 tpnt->libname, dl_elf_fini);
774 DL_CALL_FUNC_AT_ADDR (dl_elf_fini, tpnt->loadaddr, (int (*)(void)));
778 _dl_if_debug_print("unmapping: %s\n", tpnt->libname);
780 for (i = 0, ppnt = tpnt->ppnt;
781 i < tpnt->n_phent; ppnt++, i++) {
782 if (ppnt->p_type != PT_LOAD)
784 if (end < ppnt->p_vaddr + ppnt->p_memsz)
785 end = ppnt->p_vaddr + ppnt->p_memsz;
788 #if defined(USE_TLS) && USE_TLS
789 /* Do the cast to make things easy. */
790 tls_lmap = (struct link_map *) tpnt;
792 /* Remove the object from the dtv slotinfo array if it uses TLS. */
793 if (__builtin_expect (tls_lmap->l_tls_blocksize > 0, 0)) {
796 if (_dl_tls_dtv_slotinfo_list != NULL
797 && ! remove_slotinfo (tls_lmap->l_tls_modid,
798 _dl_tls_dtv_slotinfo_list, 0,
799 (tpnt->init_flag & INIT_FUNCS_CALLED)))
800 /* All dynamically loaded modules with TLS are unloaded. */
801 _dl_tls_max_dtv_idx = _dl_tls_static_nelem;
803 if (tls_lmap->l_tls_offset != NO_TLS_OFFSET) {
805 * Collect a contiguous chunk built from the objects in
806 * this search list, going in either direction. When the
807 * whole chunk is at the end of the used area then we can
810 # if defined(TLS_TCB_AT_TP)
811 if (tls_free_start == NO_TLS_OFFSET
812 || (size_t) tls_lmap->l_tls_offset == tls_free_start) {
813 /* Extend the contiguous chunk being reclaimed. */
815 = tls_lmap->l_tls_offset -
816 tls_lmap->l_tls_blocksize;
818 if (tls_free_end == NO_TLS_OFFSET)
819 tls_free_end = tls_lmap->l_tls_offset;
820 } else if (tls_lmap->l_tls_offset - tls_lmap->l_tls_blocksize
822 /* Extend the chunk backwards. */
823 tls_free_end = tls_lmap->l_tls_offset;
826 * This isn't contiguous with the last chunk freed.
827 * One of them will be leaked unless we can free
828 * one block right away.
830 if (tls_free_end == _dl_tls_static_used) {
831 _dl_tls_static_used = tls_free_start;
832 tls_free_end = tls_lmap->l_tls_offset;
834 = tls_free_end - tls_lmap->l_tls_blocksize;
835 } else if ((size_t) tls_lmap->l_tls_offset
836 == _dl_tls_static_used)
837 _dl_tls_static_used = tls_lmap->l_tls_offset -
838 tls_lmap->l_tls_blocksize;
839 else if (tls_free_end < (size_t) tls_lmap->l_tls_offset) {
841 * We pick the later block. It has a chance
844 tls_free_end = tls_lmap->l_tls_offset;
845 tls_free_start = tls_free_end -
846 tls_lmap->l_tls_blocksize;
849 # elif defined(TLS_DTV_AT_TP)
850 if ((size_t) tls_lmap->l_tls_offset == tls_free_end)
851 /* Extend the contiguous chunk being reclaimed. */
852 tls_free_end -= tls_lmap->l_tls_blocksize;
853 else if (tls_lmap->l_tls_offset + tls_lmap->l_tls_blocksize
855 /* Extend the chunk backwards. */
856 tls_free_start = tls_lmap->l_tls_offset;
859 * This isn't contiguous with the last chunk
860 * freed. One of them will be leaked.
862 if (tls_free_end == _dl_tls_static_used)
863 _dl_tls_static_used = tls_free_start;
864 tls_free_start = tls_lmap->l_tls_offset;
865 tls_free_end = tls_free_start +
866 tls_lmap->l_tls_blocksize;
869 # error Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined
873 #define TLS_DTV_UNALLOCATED ((void *) -1l)
875 dtv_t *dtv = THREAD_DTV ();
877 _dl_assert(!(dtv[tls_lmap->l_tls_modid].pointer.is_static));
878 if (dtv[tls_lmap->l_tls_modid].pointer.val != TLS_DTV_UNALLOCATED) {
879 /* Note that free is called for NULL is well. We
880 deallocate even if it is this dtv entry we are
881 supposed to load. The reason is that we call
882 memalign and not malloc. */
883 _dl_free (dtv[tls_lmap->l_tls_modid].pointer.val);
884 dtv[tls_lmap->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
890 DL_LIB_UNMAP (tpnt, end);
891 /* Free elements in RTLD_LOCAL scope list */
892 for (runp = tpnt->rtld_local; runp; runp = tmp) {
897 /* Next, remove tpnt from the loaded_module list */
898 if (_dl_loaded_modules == tpnt) {
899 _dl_loaded_modules = tpnt->next;
900 if (_dl_loaded_modules)
901 _dl_loaded_modules->prev = 0;
903 for (run_tpnt = _dl_loaded_modules; run_tpnt; run_tpnt = run_tpnt->next) {
904 if (run_tpnt->next == tpnt) {
905 _dl_if_debug_print("removing loaded_modules: %s\n", tpnt->libname);
906 run_tpnt->next = run_tpnt->next->next;
908 run_tpnt->next->prev = run_tpnt;
914 /* Next, remove tpnt from the global symbol table list */
915 if (_dl_symbol_tables) {
916 if (_dl_symbol_tables->dyn == tpnt) {
917 _dl_symbol_tables = _dl_symbol_tables->next;
918 if (_dl_symbol_tables)
919 _dl_symbol_tables->prev = 0;
921 for (rpnt1 = _dl_symbol_tables; rpnt1->next; rpnt1 = rpnt1->next) {
922 if (rpnt1->next->dyn == tpnt) {
923 _dl_if_debug_print("removing symbol_tables: %s\n", tpnt->libname);
924 rpnt1_tmp = rpnt1->next->next;
926 rpnt1->next = rpnt1_tmp;
928 rpnt1->next->prev = rpnt1;
938 for (rpnt1 = handle->next; rpnt1; rpnt1 = rpnt1_tmp) {
939 rpnt1_tmp = rpnt1->next;
942 free(handle->init_fini.init_fini);
945 #if defined(USE_TLS) && USE_TLS
946 /* If we removed any object which uses TLS bump the generation counter. */
948 if (__builtin_expect(++_dl_tls_generation == 0, 0)) {
949 _dl_debug_early("TLS generation counter wrapped! Please report to the uClibc mailing list.\n");
953 if (tls_free_end == _dl_tls_static_used)
954 _dl_tls_static_used = tls_free_start;
958 if (_dl_debug_addr) {
959 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
960 if (dl_brk != NULL) {
961 _dl_debug_addr->r_state = RT_DELETE;
964 _dl_debug_addr->r_state = RT_CONSISTENT;
972 /* l4: */ int dlclose(void *vhandle);
973 int dlclose(void *vhandle)
975 return do_dlclose(vhandle, 1);
978 /* l4: */ char *dlerror(void);
983 if (!_dl_error_number)
985 retval = dl_error_names[_dl_error_number];
986 _dl_error_number = 0;
987 return (char *)retval;
991 * Dump information to stderr about the current loaded modules
994 static const char type[][4] = { "Lib", "Exe", "Int", "Mod" };
996 /* l4: */int dlinfo(void);
999 struct elf_resolve *tpnt;
1000 struct dyn_elf *rpnt, *hpnt;
1002 fprintf(stderr, "List of loaded modules\n");
1003 /* First start with a complete list of all of the loaded files. */
1004 for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
1005 fprintf(stderr, "\t%p %p %p %s %d %s\n",
1006 (void *)DL_LOADADDR_BASE(tpnt->loadaddr), tpnt, tpnt->symbol_scope,
1007 type[tpnt->libtype],
1008 tpnt->usage_count, tpnt->libname);
1011 /* Next dump the module list for the application itself */
1012 fprintf(stderr, "\nModules for application (%p):\n", _dl_symbol_tables);
1013 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
1014 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1016 for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
1017 fprintf(stderr, "Modules for handle %p\n", hpnt);
1018 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
1019 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1024 /* l4: */int dladdr(const void *__address, Dl_info * __info);
1025 int dladdr(const void *__address, Dl_info * __info)
1027 struct elf_resolve *pelf;
1028 struct elf_resolve *rpnt;
1033 * Try and locate the module address is in
1037 _dl_if_debug_print("__address: %p __info: %p\n", __address, __info);
1039 __address = DL_LOOKUP_ADDRESS (__address);
1041 for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
1042 struct elf_resolve *tpnt;
1046 _dl_if_debug_print("Module \"%s\" at %p\n",
1047 tpnt->libname, (void *)DL_LOADADDR_BASE(tpnt->loadaddr));
1049 if (DL_ADDR_IN_LOADADDR((ElfW(Addr)) __address, tpnt, pelf))
1058 * Try and locate the symbol of address
1064 unsigned int hn, si, sn, sf;
1067 /* Set the info for the object the address lies in */
1068 __info->dli_fname = pelf->libname;
1069 __info->dli_fbase = (void *)pelf->mapaddr;
1071 symtab = (ElfW(Sym) *) (pelf->dynamic_info[DT_SYMTAB]);
1072 strtab = (char *) (pelf->dynamic_info[DT_STRTAB]);
1076 #ifdef __LDSO_GNU_HASH_SUPPORT__
1077 if (pelf->l_gnu_bitmask) {
1078 for (hn = 0; hn < pelf->nbucket; hn++) {
1079 si = pelf->l_gnu_buckets[hn];
1083 const Elf32_Word *hasharr = &pelf->l_gnu_chain_zero[si];
1085 ElfW(Addr) symbol_addr;
1087 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1088 if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
1093 _dl_if_debug_print("Symbol \"%s\" at %p\n", strtab + symtab[si].st_name, (void *)symbol_addr);
1095 } while ((*hasharr++ & 1u) == 0);
1099 for (hn = 0; hn < pelf->nbucket; hn++) {
1100 for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
1101 ElfW(Addr) symbol_addr;
1103 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1104 if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
1110 _dl_if_debug_print("Symbol \"%s\" at %p\n",
1111 strtab + symtab[si].st_name, (void *)symbol_addr);
1116 /* A nearest symbol has been found; fill the entries */
1117 __info->dli_sname = strtab + symtab[sn].st_name;
1118 __info->dli_saddr = (void *)sa;
1120 /* No symbol found, fill entries with NULL value,
1121 only the containing object will be returned. */
1122 __info->dli_sname = NULL;
1123 __info->dli_saddr = NULL;