Add protected symbols support for all architectures
[uclibc-ng.git] / ldso / libdl / libdl.c
blobb88bc4819745caa7cbafa1c168ea3dac392a0166
1 /* vi: set sw=4 ts=4: */
2 /*
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
12 * are met:
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
29 * SUCH DAMAGE.
33 #include <ldso.h>
34 #include <stdio.h>
35 #include <string.h> /* Needed for 'strstr' prototype' */
36 #include <stdbool.h>
38 #ifdef __UCLIBC_HAS_TLS__
39 #include <tls.h>
40 #endif
42 #if defined(USE_TLS) && USE_TLS
43 #include <ldsodefs.h>
44 extern void _dl_add_to_slotinfo(struct link_map *l);
45 #endif
47 #ifdef SHARED
48 # if defined(USE_TLS) && USE_TLS
49 # include <dl-tls.h>
50 extern struct link_map *_dl_update_slotinfo(unsigned long int req_modid);
51 # endif
53 /* When libdl is loaded as a shared library, we need to load in
54 * and use a pile of symbols from ldso... */
56 extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **,
57 struct elf_resolve *, char *, int);
58 extern int _dl_fixup(struct dyn_elf *rpnt, int lazy);
59 extern void _dl_protect_relro(struct elf_resolve * tpnt);
60 extern int _dl_errno;
61 extern struct dyn_elf *_dl_symbol_tables;
62 extern struct dyn_elf *_dl_handles;
63 extern struct elf_resolve *_dl_loaded_modules;
64 extern void _dl_free (void *__ptr);
65 extern struct r_debug *_dl_debug_addr;
66 extern unsigned long _dl_error_number;
67 extern void *(*_dl_malloc_function)(size_t);
68 extern void (*_dl_free_function) (void *p);
69 extern void _dl_run_init_array(struct elf_resolve *);
70 extern void _dl_run_fini_array(struct elf_resolve *);
71 #ifdef __LDSO_CACHE_SUPPORT__
72 int _dl_map_cache(void);
73 int _dl_unmap_cache(void);
74 #endif
75 #ifdef __mips__
76 extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy);
77 #endif
78 #ifdef __SUPPORT_LD_DEBUG__
79 extern char *_dl_debug;
80 #endif
82 #else /* !SHARED */
84 #define _dl_malloc malloc
85 #define _dl_free free
87 /* When libdl is linked as a static library, we need to replace all
88 * the symbols that otherwise would have been loaded in from ldso... */
90 #ifdef __SUPPORT_LD_DEBUG__
91 char *_dl_debug = NULL;
92 char *_dl_debug_symbols = NULL;
93 char *_dl_debug_move = NULL;
94 char *_dl_debug_reloc = NULL;
95 char *_dl_debug_detail = NULL;
96 char *_dl_debug_nofixups = NULL;
97 char *_dl_debug_bindings = NULL;
98 int _dl_debug_file = 2;
99 #endif
100 const char *_dl_progname = ""; /* Program name */
101 void *(*_dl_malloc_function)(size_t);
102 void (*_dl_free_function) (void *p);
103 char *_dl_library_path = NULL; /* Where we look for libraries */
104 char *_dl_ldsopath = NULL; /* Location of the shared lib loader */
105 int _dl_errno = 0; /* We can't use the real errno in ldso */
106 size_t _dl_pagesize = PAGE_SIZE; /* Store the page size for use later */
107 /* This global variable is also to communicate with debuggers such as gdb. */
108 struct r_debug *_dl_debug_addr = NULL;
110 #include "../ldso/dl-array.c"
111 #include "../ldso/dl-debug.c"
114 # if defined(USE_TLS) && USE_TLS
116 * Giving this initialized value preallocates some surplus bytes in the
117 * static TLS area, see __libc_setup_tls (libc-tls.c).
119 size_t _dl_tls_static_size = 2048;
120 # endif
121 #include LDSO_ELFINTERP
122 #include "../ldso/dl-hash.c"
123 #define _dl_trace_loaded_objects 0
124 #include "../ldso/dl-elf.c"
125 #endif /* SHARED */
127 #ifdef __SUPPORT_LD_DEBUG__
128 # define _dl_if_debug_print(fmt, args...) \
129 do { \
130 if (_dl_debug) \
131 fprintf(stderr, "%s():%i: " fmt, __FUNCTION__, __LINE__, ## args); \
132 } while (0)
133 #else
134 # define _dl_if_debug_print(fmt, args...)
135 #endif
137 static int do_dlclose(void *, int need_fini);
140 static const char *const dl_error_names[] = {
142 "File not found",
143 "Unable to open /dev/zero",
144 "Not an ELF file",
145 #if defined (__i386__)
146 "Not i386 binary",
147 #elif defined (__sparc__)
148 "Not sparc binary",
149 #elif defined (__mc68000__)
150 "Not m68k binary",
151 #else
152 "Unrecognized binary type",
153 #endif
154 "Not an ELF shared library",
155 "Unable to mmap file",
156 "No dynamic section",
157 "Library contains unsupported TLS",
158 #ifdef ELF_USES_RELOCA
159 "Unable to process REL relocs",
160 #else
161 "Unable to process RELA relocs",
162 #endif
163 "Bad handle",
164 "Unable to resolve symbol"
168 #if defined(USE_TLS) && USE_TLS
169 #ifdef SHARED
171 * Systems which do not have tls_index also probably have to define
172 * DONT_USE_TLS_INDEX.
175 # ifndef __TLS_GET_ADDR
176 # define __TLS_GET_ADDR __tls_get_addr
177 # endif
180 * Return the symbol address given the map of the module it is in and
181 * the symbol record. This is used in dl-sym.c.
183 static void *
184 internal_function
185 _dl_tls_symaddr(struct link_map *map, const Elf32_Addr st_value)
187 # ifndef DONT_USE_TLS_INDEX
188 tls_index tmp =
190 .ti_module = map->l_tls_modid,
191 .ti_offset = st_value
194 return __TLS_GET_ADDR (&tmp);
195 # else
196 return __TLS_GET_ADDR (map->l_tls_modid, st_value);
197 # endif
199 #endif
201 /* Returns true when a non-empty entry was found. */
202 static bool
203 remove_slotinfo(size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
204 bool should_be_there)
206 if (idx - disp >= listp->len) {
207 if (listp->next == NULL) {
209 * The index is not actually valid in the slotinfo list,
210 * because this object was closed before it was fully set
211 * up due to some error.
213 _dl_assert(!should_be_there);
214 } else {
215 if (remove_slotinfo(idx, listp->next, disp + listp->len,
216 should_be_there))
217 return true;
220 * No non-empty entry. Search from the end of this element's
221 * slotinfo array.
223 idx = disp + listp->len;
225 } else {
226 struct link_map *old_map = listp->slotinfo[idx - disp].map;
229 * The entry might still be in its unused state if we are
230 * closing an object that wasn't fully set up.
232 if (__builtin_expect(old_map != NULL, 1)) {
233 _dl_assert(old_map->l_tls_modid == idx);
235 /* Mark the entry as unused. */
236 listp->slotinfo[idx - disp].gen = _dl_tls_generation + 1;
237 listp->slotinfo[idx - disp].map = NULL;
241 * If this is not the last currently used entry no need to
242 * look further.
244 if (idx != _dl_tls_max_dtv_idx)
245 return true;
248 while (idx - disp > (disp == 0 ? 1 + _dl_tls_static_nelem : 0)) {
249 --idx;
251 if (listp->slotinfo[idx - disp].map != NULL) {
252 /* Found a new last used index. */
253 _dl_tls_max_dtv_idx = idx;
254 return true;
258 /* No non-entry in this list element. */
259 return false;
261 #endif
263 void dl_cleanup(void) __attribute__ ((destructor));
264 void dl_cleanup(void)
266 struct dyn_elf *h, *n;
268 for (h = _dl_handles; h; h = n) {
269 n = h->next_handle;
270 do_dlclose(h, 1);
274 void *dlopen(const char *libname, int flag)
276 struct elf_resolve *tpnt, *tfrom;
277 struct dyn_elf *dyn_chain, *rpnt = NULL, *dyn_ptr, *relro_ptr, *handle;
278 ElfW(Addr) from;
279 struct elf_resolve *tpnt1;
280 void (*dl_brk) (void);
281 int now_flag;
282 struct init_fini_list *tmp, *runp, *runp2, *dep_list;
283 unsigned int nlist, i;
284 struct elf_resolve **init_fini_list;
285 static bool _dl_init;
286 #if defined(USE_TLS) && USE_TLS
287 bool any_tls = false;
288 #endif
290 /* A bit of sanity checking... */
291 if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
292 _dl_error_number = LD_BAD_HANDLE;
293 return NULL;
296 from = (ElfW(Addr)) __builtin_return_address(0);
298 if (!_dl_init) {
299 _dl_init = true;
300 _dl_malloc_function = malloc;
301 _dl_free_function = free;
303 /* Cover the trivial case first */
304 if (!libname)
305 return _dl_symbol_tables;
307 #ifndef SHARED
308 # ifdef __SUPPORT_LD_DEBUG__
309 _dl_debug = getenv("LD_DEBUG");
310 if (_dl_debug) {
311 if (_dl_strstr(_dl_debug, "all")) {
312 _dl_debug_detail = _dl_debug_move = _dl_debug_symbols
313 = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = (void*)1;
314 } else {
315 _dl_debug_detail = strstr(_dl_debug, "detail");
316 _dl_debug_move = strstr(_dl_debug, "move");
317 _dl_debug_symbols = strstr(_dl_debug, "sym");
318 _dl_debug_reloc = strstr(_dl_debug, "reloc");
319 _dl_debug_nofixups = strstr(_dl_debug, "nofix");
320 _dl_debug_bindings = strstr(_dl_debug, "bind");
323 # endif
324 #endif
326 _dl_map_cache();
329 * Try and locate the module we were called from - we
330 * need this so that we get the correct RPATH/RUNPATH. Note that
331 * this is the current behavior under Solaris, but the
332 * ABI+ specifies that we should only use the RPATH from
333 * the application. Thus this may go away at some time
334 * in the future.
337 struct dyn_elf *dpnt;
338 tfrom = NULL;
339 for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
340 tpnt = dpnt->dyn;
341 if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom))
342 tfrom = tpnt;
345 for (rpnt = _dl_symbol_tables; rpnt && rpnt->next; rpnt = rpnt->next)
346 continue;
348 relro_ptr = rpnt;
349 now_flag = (flag & RTLD_NOW) ? RTLD_NOW : 0;
350 if (getenv("LD_BIND_NOW"))
351 now_flag = RTLD_NOW;
353 #ifndef SHARED
354 /* When statically linked, the _dl_library_path is not yet initialized */
355 _dl_library_path = getenv("LD_LIBRARY_PATH");
356 #endif
358 /* Try to load the specified library */
359 _dl_if_debug_print("Trying to dlopen '%s', RTLD_GLOBAL:%d RTLD_NOW:%d\n",
360 (char*)libname, (flag & RTLD_GLOBAL ? 1:0), (now_flag & RTLD_NOW ? 1:0));
361 tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname, 0);
363 if (tpnt == NULL) {
364 _dl_unmap_cache();
365 return NULL;
367 dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
368 _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
369 dyn_chain->dyn = tpnt;
370 tpnt->rtld_flags |= (flag & RTLD_GLOBAL);
372 dyn_chain->next_handle = _dl_handles;
373 _dl_handles = dyn_ptr = dyn_chain;
375 if (tpnt->usage_count > 1) {
376 _dl_if_debug_print("Lib: %s already opened\n", libname);
377 /* see if there is a handle from a earlier dlopen */
378 for (handle = _dl_handles->next_handle; handle; handle = handle->next_handle) {
379 if (handle->dyn == tpnt) {
380 dyn_chain->init_fini.init_fini = handle->init_fini.init_fini;
381 dyn_chain->init_fini.nlist = handle->init_fini.nlist;
382 for (i = 0; i < dyn_chain->init_fini.nlist; i++)
383 dyn_chain->init_fini.init_fini[i]->rtld_flags |= (flag & RTLD_GLOBAL);
384 dyn_chain->next = handle->next;
385 break;
388 return dyn_chain;
391 tpnt->init_flag |= DL_OPENED;
393 _dl_if_debug_print("Looking for needed libraries\n");
394 nlist = 0;
395 runp = alloca(sizeof(*runp));
396 runp->tpnt = tpnt;
397 runp->next = NULL;
398 dep_list = runp2 = runp;
399 for (; runp; runp = runp->next) {
400 ElfW(Dyn) *dpnt;
401 char *lpntstr;
403 nlist++;
404 runp->tpnt->init_fini = NULL; /* clear any previous dependcies */
405 for (dpnt = (ElfW(Dyn) *) runp->tpnt->dynamic_addr; dpnt->d_tag; dpnt++) {
406 if (dpnt->d_tag == DT_NEEDED) {
407 lpntstr = (char*) (runp->tpnt->dynamic_info[DT_STRTAB] +
408 dpnt->d_un.d_val);
409 _dl_if_debug_print("Trying to load '%s', needed by '%s'\n",
410 lpntstr, runp->tpnt->libname);
411 tpnt1 = _dl_load_shared_library(0, &rpnt, runp->tpnt, lpntstr, 0);
412 if (!tpnt1)
413 goto oops;
415 tpnt1->rtld_flags |= (flag & RTLD_GLOBAL);
417 /* This list is for dlsym() and relocation */
418 dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
419 _dl_memset (dyn_ptr->next, 0, sizeof (struct dyn_elf));
420 dyn_ptr = dyn_ptr->next;
421 dyn_ptr->dyn = tpnt1;
422 /* Used to record RTLD_LOCAL scope */
423 tmp = alloca(sizeof(struct init_fini_list));
424 tmp->tpnt = tpnt1;
425 tmp->next = runp->tpnt->init_fini;
426 runp->tpnt->init_fini = tmp;
428 for (tmp=dep_list; tmp; tmp = tmp->next) {
429 if (tpnt1 == tmp->tpnt) { /* if match => cirular dependency, drop it */
430 _dl_if_debug_print("Circular dependency, skipping '%s',\n",
431 tmp->tpnt->libname);
432 tpnt1->usage_count--;
433 break;
436 if (!tmp) { /* Don't add if circular dependency detected */
437 runp2->next = alloca(sizeof(*runp));
438 runp2 = runp2->next;
439 runp2->tpnt = tpnt1;
440 runp2->next = NULL;
445 init_fini_list = malloc(nlist * sizeof(struct elf_resolve *));
446 dyn_chain->init_fini.init_fini = init_fini_list;
447 dyn_chain->init_fini.nlist = nlist;
448 i = 0;
449 for (runp2 = dep_list; runp2; runp2 = runp2->next) {
450 init_fini_list[i++] = runp2->tpnt;
451 for (runp = runp2->tpnt->init_fini; runp; runp = runp->next) {
452 if (!(runp->tpnt->rtld_flags & RTLD_GLOBAL)) {
453 tmp = malloc(sizeof(struct init_fini_list));
454 tmp->tpnt = runp->tpnt;
455 tmp->next = runp2->tpnt->rtld_local;
456 runp2->tpnt->rtld_local = tmp;
461 /* Sort the INIT/FINI list in dependency order. */
462 for (runp2 = dep_list; runp2; runp2 = runp2->next) {
463 unsigned int j, k;
464 for (j = 0; init_fini_list[j] != runp2->tpnt; ++j)
465 /* Empty */;
466 for (k = j + 1; k < nlist; ++k) {
467 struct init_fini_list *ele = init_fini_list[k]->init_fini;
469 for (; ele; ele = ele->next) {
470 if (ele->tpnt == runp2->tpnt) {
471 struct elf_resolve *here = init_fini_list[k];
472 _dl_if_debug_print("Move %s from pos %d to %d in INIT/FINI list.\n", here->libname, k, j);
473 for (i = (k - j); i; --i)
474 init_fini_list[i+j] = init_fini_list[i+j-1];
475 init_fini_list[j] = here;
476 ++j;
477 break;
482 #ifdef __SUPPORT_LD_DEBUG__
483 if (_dl_debug) {
484 fprintf(stderr, "\nINIT/FINI order and dependencies:\n");
485 for (i = 0; i < nlist; i++) {
486 fprintf(stderr, "lib: %s has deps:\n", init_fini_list[i]->libname);
487 runp = init_fini_list[i]->init_fini;
488 for (; runp; runp = runp->next)
489 fprintf(stderr, " %s ", runp->tpnt->libname);
490 fprintf(stderr, "\n");
493 #endif
495 _dl_if_debug_print("Beginning dlopen relocation fixups\n");
497 * OK, now all of the kids are tucked into bed in their proper addresses.
498 * Now we go through and look for REL and RELA records that indicate fixups
499 * to the GOT tables. We need to do this in reverse order so that COPY
500 * directives work correctly */
501 #ifdef __mips__
503 * Relocation of the GOT entries for MIPS have to be done
504 * after all the libraries have been loaded.
506 _dl_perform_mips_global_got_relocations(tpnt, !now_flag);
507 #endif
509 if (_dl_fixup(dyn_chain, now_flag))
510 goto oops;
512 if (relro_ptr) {
513 for (rpnt = relro_ptr->next; rpnt; rpnt = rpnt->next) {
514 if (rpnt->dyn->relro_size)
515 _dl_protect_relro(rpnt->dyn);
518 /* TODO: Should we set the protections of all pages back to R/O now ? */
521 #if defined(USE_TLS) && USE_TLS
523 for (i=0; i < nlist; i++) {
524 struct elf_resolve *tmp_tpnt = init_fini_list[i];
525 /* Only add TLS memory if this object is loaded now and
526 therefore is not yet initialized. */
528 if (!(tmp_tpnt->init_flag & INIT_FUNCS_CALLED)
529 /* Only if the module defines thread local data. */
530 && __builtin_expect (tmp_tpnt->l_tls_blocksize > 0, 0)) {
532 /* Now that we know the object is loaded successfully add
533 modules containing TLS data to the slot info table. We
534 might have to increase its size. */
535 _dl_add_to_slotinfo ((struct link_map*)tmp_tpnt);
537 /* It is the case in which we couldn't perform TLS static
538 initialization at relocation time, and we delayed it until
539 the relocation has been completed. */
541 if (tmp_tpnt->l_need_tls_init) {
542 tmp_tpnt->l_need_tls_init = 0;
543 # ifdef SHARED
544 /* Update the slot information data for at least the
545 generation of the DSO we are allocating data for. */
546 _dl_update_slotinfo (tmp_tpnt->l_tls_modid);
547 # endif
549 _dl_init_static_tls((struct link_map*)tmp_tpnt);
550 _dl_assert (tmp_tpnt->l_need_tls_init == 0);
553 /* We have to bump the generation counter. */
554 any_tls = true;
558 /* Bump the generation number if necessary. */
559 if (any_tls && __builtin_expect (++_dl_tls_generation == 0, 0)) {
560 _dl_debug_early("TLS generation counter wrapped! Please report this.");
561 _dl_exit(30);
564 #endif
566 /* Notify the debugger we have added some objects. */
567 if (_dl_debug_addr) {
568 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
569 if (dl_brk != NULL) {
570 _dl_debug_addr->r_state = RT_ADD;
571 (*dl_brk) ();
573 _dl_debug_addr->r_state = RT_CONSISTENT;
574 (*dl_brk) ();
578 /* Run the ctors and setup the dtors */
579 for (i = nlist; i; --i) {
580 tpnt = init_fini_list[i-1];
581 if (tpnt->init_flag & INIT_FUNCS_CALLED)
582 continue;
583 tpnt->init_flag |= INIT_FUNCS_CALLED;
585 if (tpnt->dynamic_info[DT_INIT]) {
586 void (*dl_elf_func) (void);
587 dl_elf_func = (void (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_INIT]);
588 if (dl_elf_func) {
589 _dl_if_debug_print("running ctors for library %s at '%p'\n",
590 tpnt->libname, dl_elf_func);
591 DL_CALL_FUNC_AT_ADDR (dl_elf_func, tpnt->loadaddr, (void(*)(void)));
595 _dl_run_init_array(tpnt);
598 _dl_unmap_cache();
599 return (void *) dyn_chain;
601 oops:
602 /* Something went wrong. Clean up and return NULL. */
603 _dl_unmap_cache();
604 do_dlclose(dyn_chain, 0);
605 return NULL;
608 void *dlsym(void *vhandle, const char *name)
610 struct elf_resolve *tpnt, *tfrom;
611 struct dyn_elf *handle;
612 ElfW(Addr) from;
613 struct dyn_elf *rpnt;
614 void *ret;
615 struct elf_resolve *tls_tpnt = NULL;
616 struct symbol_ref sym_ref = { NULL, NULL };
617 /* Nastiness to support underscore prefixes. */
618 #ifdef __UCLIBC_UNDERSCORES__
619 char tmp_buf[80];
620 char *name2 = tmp_buf;
621 size_t nlen = strlen (name) + 1;
622 if (nlen + 1 > sizeof (tmp_buf))
623 name2 = malloc (nlen + 1);
624 if (name2 == 0) {
625 _dl_error_number = LD_ERROR_MMAP_FAILED;
626 return 0;
628 name2[0] = '_';
629 memcpy (name2 + 1, name, nlen);
630 #else
631 const char *name2 = name;
632 #endif
633 handle = (struct dyn_elf *) vhandle;
635 /* First of all verify that we have a real handle
636 of some kind. Return NULL if not a valid handle. */
638 if (handle == NULL)
639 handle = _dl_symbol_tables;
640 else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
641 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
642 if (rpnt == handle)
643 break;
644 if (!rpnt) {
645 _dl_error_number = LD_BAD_HANDLE;
646 ret = NULL;
647 goto out;
649 } else if (handle == RTLD_NEXT) {
651 * Try and locate the module we were called from - we
652 * need this so that we know where to start searching
653 * from. We never pass RTLD_NEXT down into the actual
654 * dynamic loader itself, as it doesn't know
655 * how to properly treat it.
657 from = (ElfW(Addr)) __builtin_return_address(0);
659 tfrom = NULL;
660 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
661 tpnt = rpnt->dyn;
662 if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom)) {
663 tfrom = tpnt;
664 handle = rpnt->next;
668 tpnt = NULL;
669 if (handle == _dl_symbol_tables)
670 tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
671 ret = _dl_find_hash(name2, handle, tpnt, 0, &sym_ref);
673 #if defined(USE_TLS) && USE_TLS && defined SHARED
674 if (sym_ref.tpnt) {
675 /* The found symbol is a thread-local storage variable.
676 Return the address for to the current thread. */
677 ret = _dl_tls_symaddr ((struct link_map *)sym_ref.tpnt, (Elf32_Addr)ret);
679 #endif
682 * Nothing found.
684 if (!ret)
685 _dl_error_number = LD_NO_SYMBOL;
686 out:
687 #ifdef __UCLIBC_UNDERSCORES__
688 if (name2 != tmp_buf)
689 free (name2);
690 #endif
691 return ret;
694 #if 0
695 void *dlvsym(void *vhandle, const char *name, const char *version)
697 return dlsym(vhandle, name);
699 #endif
701 static int do_dlclose(void *vhandle, int need_fini)
703 struct dyn_elf *rpnt, *rpnt1, *rpnt1_tmp;
704 struct init_fini_list *runp, *tmp;
705 ElfW(Phdr) *ppnt;
706 struct elf_resolve *tpnt, *run_tpnt;
707 int (*dl_elf_fini) (void);
708 void (*dl_brk) (void);
709 struct dyn_elf *handle;
710 unsigned int end;
711 unsigned int i, j;
712 #if defined(USE_TLS) && USE_TLS
713 bool any_tls = false;
714 size_t tls_free_start = NO_TLS_OFFSET;
715 size_t tls_free_end = NO_TLS_OFFSET;
716 struct link_map *tls_lmap;
717 #endif
719 handle = (struct dyn_elf *) vhandle;
720 if (handle == _dl_symbol_tables)
721 return 0;
722 rpnt1 = NULL;
723 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
724 if (rpnt == handle)
725 break;
726 rpnt1 = rpnt;
729 if (!rpnt) {
730 _dl_error_number = LD_BAD_HANDLE;
731 return 1;
733 if (rpnt1)
734 rpnt1->next_handle = rpnt->next_handle;
735 else
736 _dl_handles = rpnt->next_handle;
737 _dl_if_debug_print("%s: usage count: %d\n",
738 handle->dyn->libname, handle->dyn->usage_count);
739 if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & RTLD_NODELETE)) {
740 handle->dyn->usage_count--;
741 free(handle);
742 return 0;
744 /* OK, this is a valid handle - now close out the file */
745 for (j = 0; j < handle->init_fini.nlist; ++j) {
746 tpnt = handle->init_fini.init_fini[j];
747 tpnt->usage_count--;
748 if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) {
749 if ((tpnt->dynamic_info[DT_FINI]
750 || tpnt->dynamic_info[DT_FINI_ARRAY])
751 && need_fini
752 && !(tpnt->init_flag & FINI_FUNCS_CALLED)
754 tpnt->init_flag |= FINI_FUNCS_CALLED;
755 _dl_run_fini_array(tpnt);
757 if (tpnt->dynamic_info[DT_FINI]) {
758 dl_elf_fini = (int (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_FINI]);
759 _dl_if_debug_print("running dtors for library %s at '%p'\n",
760 tpnt->libname, dl_elf_fini);
761 DL_CALL_FUNC_AT_ADDR (dl_elf_fini, tpnt->loadaddr, (int (*)(void)));
765 _dl_if_debug_print("unmapping: %s\n", tpnt->libname);
766 end = 0;
767 for (i = 0, ppnt = tpnt->ppnt;
768 i < tpnt->n_phent; ppnt++, i++) {
769 if (ppnt->p_type != PT_LOAD)
770 continue;
771 if (end < ppnt->p_vaddr + ppnt->p_memsz)
772 end = ppnt->p_vaddr + ppnt->p_memsz;
775 #if defined(USE_TLS) && USE_TLS
776 /* Do the cast to make things easy. */
777 tls_lmap = (struct link_map *) tpnt;
779 /* Remove the object from the dtv slotinfo array if it uses TLS. */
780 if (__builtin_expect (tls_lmap->l_tls_blocksize > 0, 0)) {
781 any_tls = true;
783 if (_dl_tls_dtv_slotinfo_list != NULL
784 && ! remove_slotinfo (tls_lmap->l_tls_modid,
785 _dl_tls_dtv_slotinfo_list, 0,
786 (tpnt->init_flag & INIT_FUNCS_CALLED)))
787 /* All dynamically loaded modules with TLS are unloaded. */
788 _dl_tls_max_dtv_idx = _dl_tls_static_nelem;
790 if (tls_lmap->l_tls_offset != NO_TLS_OFFSET) {
792 * Collect a contiguous chunk built from the objects in
793 * this search list, going in either direction. When the
794 * whole chunk is at the end of the used area then we can
795 * reclaim it.
797 # if defined(TLS_TCB_AT_TP)
798 if (tls_free_start == NO_TLS_OFFSET
799 || (size_t) tls_lmap->l_tls_offset == tls_free_start) {
800 /* Extend the contiguous chunk being reclaimed. */
801 tls_free_start
802 = tls_lmap->l_tls_offset -
803 tls_lmap->l_tls_blocksize;
805 if (tls_free_end == NO_TLS_OFFSET)
806 tls_free_end = tls_lmap->l_tls_offset;
807 } else if (tls_lmap->l_tls_offset - tls_lmap->l_tls_blocksize
808 == tls_free_end)
809 /* Extend the chunk backwards. */
810 tls_free_end = tls_lmap->l_tls_offset;
811 else {
813 * This isn't contiguous with the last chunk freed.
814 * One of them will be leaked unless we can free
815 * one block right away.
817 if (tls_free_end == _dl_tls_static_used) {
818 _dl_tls_static_used = tls_free_start;
819 tls_free_end = tls_lmap->l_tls_offset;
820 tls_free_start
821 = tls_free_end - tls_lmap->l_tls_blocksize;
822 } else if ((size_t) tls_lmap->l_tls_offset
823 == _dl_tls_static_used)
824 _dl_tls_static_used = tls_lmap->l_tls_offset -
825 tls_lmap->l_tls_blocksize;
826 else if (tls_free_end < (size_t) tls_lmap->l_tls_offset) {
828 * We pick the later block. It has a chance
829 * to be freed.
831 tls_free_end = tls_lmap->l_tls_offset;
832 tls_free_start = tls_free_end -
833 tls_lmap->l_tls_blocksize;
836 # elif defined(TLS_DTV_AT_TP)
837 if ((size_t) tls_lmap->l_tls_offset == tls_free_end)
838 /* Extend the contiguous chunk being reclaimed. */
839 tls_free_end -= tls_lmap->l_tls_blocksize;
840 else if (tls_lmap->l_tls_offset + tls_lmap->l_tls_blocksize
841 == tls_free_start)
842 /* Extend the chunk backwards. */
843 tls_free_start = tls_lmap->l_tls_offset;
844 else {
846 * This isn't contiguous with the last chunk
847 * freed. One of them will be leaked.
849 if (tls_free_end == _dl_tls_static_used)
850 _dl_tls_static_used = tls_free_start;
851 tls_free_start = tls_lmap->l_tls_offset;
852 tls_free_end = tls_free_start +
853 tls_lmap->l_tls_blocksize;
855 # else
856 # error Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined
857 # endif
858 } else {
860 #define TLS_DTV_UNALLOCATED ((void *) -1l)
862 dtv_t *dtv = THREAD_DTV ();
864 _dl_assert(!(dtv[tls_lmap->l_tls_modid].pointer.is_static));
865 if (dtv[tls_lmap->l_tls_modid].pointer.val != TLS_DTV_UNALLOCATED) {
866 /* Note that free is called for NULL is well. We
867 deallocate even if it is this dtv entry we are
868 supposed to load. The reason is that we call
869 memalign and not malloc. */
870 _dl_free (dtv[tls_lmap->l_tls_modid].pointer.val);
871 dtv[tls_lmap->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
875 #endif
877 DL_LIB_UNMAP (tpnt, end);
878 /* Free elements in RTLD_LOCAL scope list */
879 for (runp = tpnt->rtld_local; runp; runp = tmp) {
880 tmp = runp->next;
881 free(runp);
884 /* Next, remove tpnt from the loaded_module list */
885 if (_dl_loaded_modules == tpnt) {
886 _dl_loaded_modules = tpnt->next;
887 if (_dl_loaded_modules)
888 _dl_loaded_modules->prev = 0;
889 } else {
890 for (run_tpnt = _dl_loaded_modules; run_tpnt; run_tpnt = run_tpnt->next) {
891 if (run_tpnt->next == tpnt) {
892 _dl_if_debug_print("removing loaded_modules: %s\n", tpnt->libname);
893 run_tpnt->next = run_tpnt->next->next;
894 if (run_tpnt->next)
895 run_tpnt->next->prev = run_tpnt;
896 break;
901 /* Next, remove tpnt from the global symbol table list */
902 if (_dl_symbol_tables) {
903 if (_dl_symbol_tables->dyn == tpnt) {
904 _dl_symbol_tables = _dl_symbol_tables->next;
905 if (_dl_symbol_tables)
906 _dl_symbol_tables->prev = 0;
907 } else {
908 for (rpnt1 = _dl_symbol_tables; rpnt1->next; rpnt1 = rpnt1->next) {
909 if (rpnt1->next->dyn == tpnt) {
910 _dl_if_debug_print("removing symbol_tables: %s\n", tpnt->libname);
911 rpnt1_tmp = rpnt1->next->next;
912 free(rpnt1->next);
913 rpnt1->next = rpnt1_tmp;
914 if (rpnt1->next)
915 rpnt1->next->prev = rpnt1;
916 break;
921 free(tpnt->libname);
922 free(tpnt);
925 free(handle->init_fini.init_fini);
926 free(handle);
928 #if defined(USE_TLS) && USE_TLS
929 /* If we removed any object which uses TLS bump the generation counter. */
930 if (any_tls) {
931 if (__builtin_expect(++_dl_tls_generation == 0, 0)) {
932 _dl_debug_early("TLS generation counter wrapped! Please report to the uClibc mailing list.\n");
933 _dl_exit(30);
936 if (tls_free_end == _dl_tls_static_used)
937 _dl_tls_static_used = tls_free_start;
939 #endif
941 if (_dl_debug_addr) {
942 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
943 if (dl_brk != NULL) {
944 _dl_debug_addr->r_state = RT_DELETE;
945 (*dl_brk) ();
947 _dl_debug_addr->r_state = RT_CONSISTENT;
948 (*dl_brk) ();
952 return 0;
955 int dlclose(void *vhandle)
957 return do_dlclose(vhandle, 1);
960 char *dlerror(void)
962 const char *retval;
964 if (!_dl_error_number)
965 return NULL;
966 retval = dl_error_names[_dl_error_number];
967 _dl_error_number = 0;
968 return (char *)retval;
972 * Dump information to stderr about the current loaded modules
974 #ifdef __USE_GNU
975 static const char type[][4] = { "Lib", "Exe", "Int", "Mod" };
977 int dlinfo(void)
979 struct elf_resolve *tpnt;
980 struct dyn_elf *rpnt, *hpnt;
982 fprintf(stderr, "List of loaded modules\n");
983 /* First start with a complete list of all of the loaded files. */
984 for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
985 fprintf(stderr, "\t%p %p %p %s %d %s\n",
986 DL_LOADADDR_BASE(tpnt->loadaddr), tpnt, tpnt->symbol_scope,
987 type[tpnt->libtype],
988 tpnt->usage_count, tpnt->libname);
991 /* Next dump the module list for the application itself */
992 fprintf(stderr, "\nModules for application (%p):\n", _dl_symbol_tables);
993 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
994 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
996 for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
997 fprintf(stderr, "Modules for handle %p\n", hpnt);
998 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
999 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1001 return 0;
1004 int dladdr(const void *__address, Dl_info * __info)
1006 struct elf_resolve *pelf;
1007 struct elf_resolve *rpnt;
1009 _dl_map_cache();
1012 * Try and locate the module address is in
1014 pelf = NULL;
1016 _dl_if_debug_print("__address: %p __info: %p\n", __address, __info);
1018 __address = DL_LOOKUP_ADDRESS (__address);
1020 for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
1021 struct elf_resolve *tpnt;
1023 tpnt = rpnt;
1025 _dl_if_debug_print("Module \"%s\" at %p\n",
1026 tpnt->libname, DL_LOADADDR_BASE(tpnt->loadaddr));
1028 if (DL_ADDR_IN_LOADADDR((ElfW(Addr)) __address, tpnt, pelf))
1029 pelf = tpnt;
1032 if (!pelf) {
1033 return 0;
1037 * Try and locate the symbol of address
1041 char *strtab;
1042 ElfW(Sym) *symtab;
1043 unsigned int hn, si, sn, sf;
1044 ElfW(Addr) sa = 0;
1046 /* Set the info for the object the address lies in */
1047 __info->dli_fname = pelf->libname;
1048 __info->dli_fbase = (void *)pelf->mapaddr;
1050 symtab = (ElfW(Sym) *) (pelf->dynamic_info[DT_SYMTAB]);
1051 strtab = (char *) (pelf->dynamic_info[DT_STRTAB]);
1053 sf = sn = 0;
1055 #ifdef __LDSO_GNU_HASH_SUPPORT__
1056 if (pelf->l_gnu_bitmask) {
1057 for (hn = 0; hn < pelf->nbucket; hn++) {
1058 si = pelf->l_gnu_buckets[hn];
1059 if (!si)
1060 continue;
1062 const Elf32_Word *hasharr = &pelf->l_gnu_chain_zero[si];
1063 do {
1064 ElfW(Addr) symbol_addr;
1066 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1067 if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
1068 sa = symbol_addr;
1069 sn = si;
1070 sf = 1;
1072 _dl_if_debug_print("Symbol \"%s\" at %p\n", strtab + symtab[si].st_name, symbol_addr);
1073 ++si;
1074 } while ((*hasharr++ & 1u) == 0);
1076 } else
1077 #endif
1078 for (hn = 0; hn < pelf->nbucket; hn++) {
1079 for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
1080 ElfW(Addr) symbol_addr;
1082 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1083 if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
1084 sa = symbol_addr;
1085 sn = si;
1086 sf = 1;
1089 _dl_if_debug_print("Symbol \"%s\" at %p\n",
1090 strtab + symtab[si].st_name, symbol_addr);
1094 if (sf) {
1095 /* A nearest symbol has been found; fill the entries */
1096 __info->dli_sname = strtab + symtab[sn].st_name;
1097 __info->dli_saddr = (void *)sa;
1098 } else {
1099 /* No symbol found, fill entries with NULL value,
1100 only the containing object will be returned. */
1101 __info->dli_sname = NULL;
1102 __info->dli_saddr = NULL;
1104 return 1;
1107 #endif