OSDN Git Service

silence warning about incompatible types with _dl_init_static_tls
[uclinux-h8/uClibc.git] / ldso / libdl / libdl.c
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
5  *
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
9  *
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.
18  *
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.
30  */
31
32
33 #include <ldso.h>
34 #include <stdio.h>
35 #include <string.h> /* Needed for 'strstr' prototype' */
36 #include <stdbool.h>
37
38 #ifdef __UCLIBC_HAS_TLS__
39 #include <tls.h>
40 #endif
41
42 #if defined(USE_TLS) && USE_TLS
43 #include <ldsodefs.h>
44 extern void _dl_add_to_slotinfo(struct link_map  *l);
45 #endif
46
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
52
53 /* When libdl is loaded as a shared library, we need to load in
54  * and use a pile of symbols from ldso... */
55
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
81
82 #else /* !SHARED */
83
84 #define _dl_malloc malloc
85 #define _dl_free free
86
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... */
89
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;
109
110 #include "../ldso/dl-array.c"
111 #include "../ldso/dl-debug.c"
112
113
114 # if defined(USE_TLS) && USE_TLS
115 /*
116  * Giving this initialized value preallocates some surplus bytes in the
117  * static TLS area, see __libc_setup_tls (libc-tls.c).
118  */
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 */
126
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
136
137 static int do_dlclose(void *, int need_fini);
138
139
140 static const char *const dl_error_names[] = {
141         "",
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"
165 };
166
167
168 #if defined(USE_TLS) && USE_TLS
169 #ifdef SHARED
170 /*
171  * Systems which do not have tls_index also probably have to define
172  * DONT_USE_TLS_INDEX.
173  */
174
175 # ifndef __TLS_GET_ADDR
176 #  define __TLS_GET_ADDR __tls_get_addr
177 # endif
178
179 /*
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.
182  */
183 static void *
184 internal_function
185 _dl_tls_symaddr(struct link_map *map, const Elf32_Addr st_value)
186 {
187 # ifndef DONT_USE_TLS_INDEX
188         tls_index tmp =
189         {
190                 .ti_module = map->l_tls_modid,
191                 .ti_offset = st_value
192         };
193
194         return __TLS_GET_ADDR (&tmp);
195 # else
196         return __TLS_GET_ADDR (map->l_tls_modid, st_value);
197 # endif
198 }
199 #endif
200
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)
205 {
206         if (idx - disp >= listp->len) {
207                 if (listp->next == NULL) {
208                         /*
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.
212                          */
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;
218
219                         /*
220                          * No non-empty entry. Search from the end of this element's
221                          * slotinfo array.
222                          */
223                         idx = disp + listp->len;
224                 }
225         } else {
226                 struct link_map *old_map = listp->slotinfo[idx - disp].map;
227
228                 /*
229                  * The entry might still be in its unused state if we are
230                  * closing an object that wasn't fully set up.
231                  */
232                 if (__builtin_expect(old_map != NULL, 1)) {
233                         _dl_assert(old_map->l_tls_modid == idx);
234
235                         /* Mark the entry as unused. */
236                         listp->slotinfo[idx - disp].gen = _dl_tls_generation + 1;
237                         listp->slotinfo[idx - disp].map = NULL;
238                 }
239
240                 /*
241                  * If this is not the last currently used entry no need to
242                  * look further.
243                  */
244                 if (idx != _dl_tls_max_dtv_idx)
245                         return true;
246         }
247
248         while (idx - disp > (disp == 0 ? 1 + _dl_tls_static_nelem : 0)) {
249                 --idx;
250
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;
255                 }
256         }
257
258         /* No non-entry in this list element.  */
259         return false;
260 }
261 #endif
262
263 void dl_cleanup(void) __attribute__ ((destructor));
264 void dl_cleanup(void)
265 {
266         struct dyn_elf *h, *n;
267
268         for (h = _dl_handles; h; h = n) {
269                 n = h->next_handle;
270                 do_dlclose(h, 1);
271         }
272 }
273
274 void *dlopen(const char *libname, int flag)
275 {
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
289
290         /* A bit of sanity checking... */
291         if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
292                 _dl_error_number = LD_BAD_HANDLE;
293                 return NULL;
294         }
295
296         from = (ElfW(Addr)) __builtin_return_address(0);
297
298         if (!_dl_init) {
299                 _dl_init = true;
300                 _dl_malloc_function = malloc;
301                 _dl_free_function = free;
302         }
303         /* Cover the trivial case first */
304         if (!libname)
305                 return _dl_symbol_tables;
306
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");
321                 }
322         }
323 # endif
324 #endif
325
326         _dl_map_cache();
327
328         /*
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.
335          */
336         {
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;
343                 }
344         }
345         for (rpnt = _dl_symbol_tables; rpnt && rpnt->next; rpnt = rpnt->next)
346                 continue;
347
348         relro_ptr = rpnt;
349         now_flag = (flag & RTLD_NOW) ? RTLD_NOW : 0;
350         if (getenv("LD_BIND_NOW"))
351                 now_flag = RTLD_NOW;
352
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
357
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);
362
363         if (tpnt == NULL) {
364                 _dl_unmap_cache();
365                 return NULL;
366         }
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);
371
372         dyn_chain->next_handle = _dl_handles;
373         _dl_handles = dyn_ptr = dyn_chain;
374
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;
386                         }
387                 }
388                 return dyn_chain;
389         }
390
391         tpnt->init_flag |= DL_OPENED;
392
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;
402
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;
414
415                                 tpnt1->rtld_flags |= (flag & RTLD_GLOBAL);
416
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;
427
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;
434                                         }
435                                 }
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;
441                                 }
442                         }
443                 }
444         }
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;
457                         }
458                 }
459
460         }
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;
468
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;
478                                 }
479                         }
480                 }
481         }
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");
491                 }
492         }
493 #endif
494
495         _dl_if_debug_print("Beginning dlopen relocation fixups\n");
496         /*
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__
502         /*
503          * Relocation of the GOT entries for MIPS have to be done
504          * after all the libraries have been loaded.
505          */
506         _dl_perform_mips_global_got_relocations(tpnt, !now_flag);
507 #endif
508
509         if (_dl_fixup(dyn_chain, now_flag))
510                 goto oops;
511
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);
516                 }
517         }
518         /* TODO:  Should we set the protections of all pages back to R/O now ? */
519
520
521 #if defined(USE_TLS) && USE_TLS
522
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.  */
527
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)) {
531
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);
536
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. */
540
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
548
549                                 _dl_init_static_tls((struct link_map*)tmp_tpnt);
550                                 _dl_assert (tmp_tpnt->l_need_tls_init == 0);
551                 }
552
553                 /* We have to bump the generation counter. */
554                 any_tls = true;
555                 }
556         }
557
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);
562         }
563
564 #endif
565
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) ();
572
573                         _dl_debug_addr->r_state = RT_CONSISTENT;
574                         (*dl_brk) ();
575                 }
576         }
577
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;
584
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)));
592                         }
593                 }
594
595                 _dl_run_init_array(tpnt);
596         }
597
598         _dl_unmap_cache();
599         return (void *) dyn_chain;
600
601 oops:
602         /* Something went wrong.  Clean up and return NULL. */
603         _dl_unmap_cache();
604         do_dlclose(dyn_chain, 0);
605         return NULL;
606 }
607
608 void *dlsym(void *vhandle, const char *name)
609 {
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         /* Nastiness to support underscore prefixes.  */
617 #ifdef __UCLIBC_UNDERSCORES__
618         char tmp_buf[80];
619         char *name2 = tmp_buf;
620         size_t nlen = strlen (name) + 1;
621         if (nlen + 1 > sizeof (tmp_buf))
622                 name2 = malloc (nlen + 1);
623         if (name2 == 0) {
624                 _dl_error_number = LD_ERROR_MMAP_FAILED;
625                 return 0;
626         }
627         name2[0] = '_';
628         memcpy (name2 + 1, name, nlen);
629 #else
630         const char *name2 = name;
631 #endif
632         handle = (struct dyn_elf *) vhandle;
633
634         /* First of all verify that we have a real handle
635            of some kind.  Return NULL if not a valid handle. */
636
637         if (handle == NULL)
638                 handle = _dl_symbol_tables;
639         else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
640                 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
641                         if (rpnt == handle)
642                                 break;
643                 if (!rpnt) {
644                         _dl_error_number = LD_BAD_HANDLE;
645                         ret = NULL;
646                         goto out;
647                 }
648         } else if (handle == RTLD_NEXT) {
649                 /*
650                  * Try and locate the module we were called from - we
651                  * need this so that we know where to start searching
652                  * from.  We never pass RTLD_NEXT down into the actual
653                  * dynamic loader itself, as it doesn't know
654                  * how to properly treat it.
655                  */
656                 from = (ElfW(Addr)) __builtin_return_address(0);
657
658                 tfrom = NULL;
659                 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
660                         tpnt = rpnt->dyn;
661                         if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom)) {
662                                 tfrom = tpnt;
663                                 handle = rpnt->next;
664                         }
665                 }
666         }
667         tpnt = NULL;
668         if (handle == _dl_symbol_tables)
669                 tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
670         ret = _dl_find_hash(name2, handle, NULL, 0, &tls_tpnt);
671
672 #if defined(USE_TLS) && USE_TLS && defined SHARED
673         if (tls_tpnt) {
674                 /* The found symbol is a thread-local storage variable.
675                 Return the address for to the current thread.  */
676                 ret = _dl_tls_symaddr ((struct link_map *)tls_tpnt, (Elf32_Addr)ret);
677         }
678 #endif
679
680         /*
681          * Nothing found.
682          */
683         if (!ret)
684                 _dl_error_number = LD_NO_SYMBOL;
685 out:
686 #ifdef __UCLIBC_UNDERSCORES__
687         if (name2 != tmp_buf)
688                 free (name2);
689 #endif
690         return ret;
691 }
692
693 #if 0
694 void *dlvsym(void *vhandle, const char *name, const char *version)
695 {
696         return dlsym(vhandle, name);
697 }
698 #endif
699
700 static int do_dlclose(void *vhandle, int need_fini)
701 {
702         struct dyn_elf *rpnt, *rpnt1, *rpnt1_tmp;
703         struct init_fini_list *runp, *tmp;
704         ElfW(Phdr) *ppnt;
705         struct elf_resolve *tpnt, *run_tpnt;
706         int (*dl_elf_fini) (void);
707         void (*dl_brk) (void);
708         struct dyn_elf *handle;
709         unsigned int end;
710         unsigned int i, j;
711 #if defined(USE_TLS) && USE_TLS
712         bool any_tls = false;
713         size_t tls_free_start = NO_TLS_OFFSET;
714         size_t tls_free_end = NO_TLS_OFFSET;
715         struct link_map *tls_lmap;
716 #endif
717
718         handle = (struct dyn_elf *) vhandle;
719         if (handle == _dl_symbol_tables)
720                 return 0;
721         rpnt1 = NULL;
722         for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
723                 if (rpnt == handle)
724                         break;
725                 rpnt1 = rpnt;
726         }
727
728         if (!rpnt) {
729                 _dl_error_number = LD_BAD_HANDLE;
730                 return 1;
731         }
732         if (rpnt1)
733                 rpnt1->next_handle = rpnt->next_handle;
734         else
735                 _dl_handles = rpnt->next_handle;
736         _dl_if_debug_print("%s: usage count: %d\n",
737                         handle->dyn->libname, handle->dyn->usage_count);
738         if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & RTLD_NODELETE)) {
739                 handle->dyn->usage_count--;
740                 free(handle);
741                 return 0;
742         }
743         /* OK, this is a valid handle - now close out the file */
744         for (j = 0; j < handle->init_fini.nlist; ++j) {
745                 tpnt = handle->init_fini.init_fini[j];
746                 tpnt->usage_count--;
747                 if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) {
748                         if ((tpnt->dynamic_info[DT_FINI]
749                              || tpnt->dynamic_info[DT_FINI_ARRAY])
750                          && need_fini
751                          && !(tpnt->init_flag & FINI_FUNCS_CALLED)
752                         ) {
753                                 tpnt->init_flag |= FINI_FUNCS_CALLED;
754                                 _dl_run_fini_array(tpnt);
755
756                                 if (tpnt->dynamic_info[DT_FINI]) {
757                                         dl_elf_fini = (int (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_FINI]);
758                                         _dl_if_debug_print("running dtors for library %s at '%p'\n",
759                                                         tpnt->libname, dl_elf_fini);
760                                         DL_CALL_FUNC_AT_ADDR (dl_elf_fini, tpnt->loadaddr, (int (*)(void)));
761                                 }
762                         }
763
764                         _dl_if_debug_print("unmapping: %s\n", tpnt->libname);
765                         end = 0;
766                         for (i = 0, ppnt = tpnt->ppnt;
767                                         i < tpnt->n_phent; ppnt++, i++) {
768                                 if (ppnt->p_type != PT_LOAD)
769                                         continue;
770                                 if (end < ppnt->p_vaddr + ppnt->p_memsz)
771                                         end = ppnt->p_vaddr + ppnt->p_memsz;
772                         }
773
774 #if defined(USE_TLS) && USE_TLS
775                         /* Do the cast to make things easy. */
776                         tls_lmap = (struct link_map *) tpnt;
777
778                         /* Remove the object from the dtv slotinfo array if it uses TLS. */
779                         if (__builtin_expect (tls_lmap->l_tls_blocksize > 0, 0)) {
780                                 any_tls = true;
781
782                                 if (_dl_tls_dtv_slotinfo_list != NULL
783                                                 && ! remove_slotinfo (tls_lmap->l_tls_modid,
784                                                 _dl_tls_dtv_slotinfo_list, 0,
785                                                 (tpnt->init_flag & INIT_FUNCS_CALLED)))
786                                         /* All dynamically loaded modules with TLS are unloaded. */
787                                         _dl_tls_max_dtv_idx = _dl_tls_static_nelem;
788
789                                 if (tls_lmap->l_tls_offset != NO_TLS_OFFSET) {
790                                         /*
791                                          * Collect a contiguous chunk built from the objects in
792                                          * this search list, going in either direction.  When the
793                                          * whole chunk is at the end of the used area then we can
794                                          * reclaim it.
795                                          */
796 # if defined(TLS_TCB_AT_TP)
797                                         if (tls_free_start == NO_TLS_OFFSET
798                                                 || (size_t) tls_lmap->l_tls_offset == tls_free_start) {
799                                                 /* Extend the contiguous chunk being reclaimed. */
800                                                 tls_free_start
801                                                         = tls_lmap->l_tls_offset -
802                                                           tls_lmap->l_tls_blocksize;
803
804                                                 if (tls_free_end == NO_TLS_OFFSET)
805                                                         tls_free_end = tls_lmap->l_tls_offset;
806                                         } else if (tls_lmap->l_tls_offset - tls_lmap->l_tls_blocksize
807                                                         == tls_free_end)
808                                                 /* Extend the chunk backwards.  */
809                                                 tls_free_end = tls_lmap->l_tls_offset;
810                                         else {
811                                                 /*
812                                                  * This isn't contiguous with the last chunk freed.
813                                                  * One of them will be leaked unless we can free
814                                                  * one block right away.
815                                                  */
816                                                 if (tls_free_end == _dl_tls_static_used) {
817                                                         _dl_tls_static_used = tls_free_start;
818                                                         tls_free_end = tls_lmap->l_tls_offset;
819                                                         tls_free_start
820                                                                 = tls_free_end - tls_lmap->l_tls_blocksize;
821                                                 } else if ((size_t) tls_lmap->l_tls_offset
822                                                                 == _dl_tls_static_used)
823                                                         _dl_tls_static_used = tls_lmap->l_tls_offset -
824                                                                 tls_lmap->l_tls_blocksize;
825                                                 else if (tls_free_end < (size_t) tls_lmap->l_tls_offset) {
826                                                         /*
827                                                          * We pick the later block. It has a chance
828                                                          * to be freed.
829                                                          */
830                                                         tls_free_end = tls_lmap->l_tls_offset;
831                                                         tls_free_start = tls_free_end -
832                                                                 tls_lmap->l_tls_blocksize;
833                                                 }
834                                         }
835 # elif defined(TLS_DTV_AT_TP)
836                                         if ((size_t) tls_lmap->l_tls_offset == tls_free_end)
837                                                 /* Extend the contiguous chunk being reclaimed. */
838                                                 tls_free_end -= tls_lmap->l_tls_blocksize;
839                                         else if (tls_lmap->l_tls_offset + tls_lmap->l_tls_blocksize
840                                                         == tls_free_start)
841                                                 /* Extend the chunk backwards. */
842                                                 tls_free_start = tls_lmap->l_tls_offset;
843                                         else {
844                                                 /*
845                                                  * This isn't contiguous with the last chunk
846                                                  * freed. One of them will be leaked.
847                                                  */
848                                                 if (tls_free_end == _dl_tls_static_used)
849                                                         _dl_tls_static_used = tls_free_start;
850                                                 tls_free_start = tls_lmap->l_tls_offset;
851                                                 tls_free_end = tls_free_start +
852                                                         tls_lmap->l_tls_blocksize;
853                                         }
854 # else
855 #  error Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined
856 # endif
857                                 } else {
858
859 #define TLS_DTV_UNALLOCATED     ((void *) -1l)
860
861                                         dtv_t *dtv = THREAD_DTV ();
862
863                                         _dl_assert(!(dtv[tls_lmap->l_tls_modid].pointer.is_static));
864                                         if (dtv[tls_lmap->l_tls_modid].pointer.val != TLS_DTV_UNALLOCATED) {
865                                                 /* Note that free is called for NULL is well.  We
866                                                 deallocate even if it is this dtv entry we are
867                                                 supposed to load.  The reason is that we call
868                                                 memalign and not malloc.  */
869                                                 _dl_free (dtv[tls_lmap->l_tls_modid].pointer.val);
870                                                 dtv[tls_lmap->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
871                                         }
872                                 }
873                         }
874 #endif
875
876                         DL_LIB_UNMAP (tpnt, end);
877                         /* Free elements in RTLD_LOCAL scope list */
878                         for (runp = tpnt->rtld_local; runp; runp = tmp) {
879                                 tmp = runp->next;
880                                 free(runp);
881                         }
882
883                         /* Next, remove tpnt from the loaded_module list */
884                         if (_dl_loaded_modules == tpnt) {
885                                 _dl_loaded_modules = tpnt->next;
886                                 if (_dl_loaded_modules)
887                                         _dl_loaded_modules->prev = 0;
888                         } else {
889                                 for (run_tpnt = _dl_loaded_modules; run_tpnt; run_tpnt = run_tpnt->next) {
890                                         if (run_tpnt->next == tpnt) {
891                                                 _dl_if_debug_print("removing loaded_modules: %s\n", tpnt->libname);
892                                                 run_tpnt->next = run_tpnt->next->next;
893                                                 if (run_tpnt->next)
894                                                         run_tpnt->next->prev = run_tpnt;
895                                                 break;
896                                         }
897                                 }
898                         }
899
900                         /* Next, remove tpnt from the global symbol table list */
901                         if (_dl_symbol_tables) {
902                                 if (_dl_symbol_tables->dyn == tpnt) {
903                                         _dl_symbol_tables = _dl_symbol_tables->next;
904                                         if (_dl_symbol_tables)
905                                                 _dl_symbol_tables->prev = 0;
906                                 } else {
907                                         for (rpnt1 = _dl_symbol_tables; rpnt1->next; rpnt1 = rpnt1->next) {
908                                                 if (rpnt1->next->dyn == tpnt) {
909                                                         _dl_if_debug_print("removing symbol_tables: %s\n", tpnt->libname);
910                                                         rpnt1_tmp = rpnt1->next->next;
911                                                         free(rpnt1->next);
912                                                         rpnt1->next = rpnt1_tmp;
913                                                         if (rpnt1->next)
914                                                                 rpnt1->next->prev = rpnt1;
915                                                         break;
916                                                 }
917                                         }
918                                 }
919                         }
920                         free(tpnt->libname);
921                         free(tpnt);
922                 }
923         }
924         free(handle->init_fini.init_fini);
925         free(handle);
926
927 #if defined(USE_TLS) && USE_TLS
928         /* If we removed any object which uses TLS bump the generation counter.  */
929         if (any_tls) {
930                 if (__builtin_expect(++_dl_tls_generation == 0, 0)) {
931                         _dl_debug_early("TLS generation counter wrapped!  Please report to the uClibc mailing list.\n");
932                         _dl_exit(30);
933                 }
934
935                 if (tls_free_end == _dl_tls_static_used)
936                         _dl_tls_static_used = tls_free_start;
937         }
938 #endif
939
940         if (_dl_debug_addr) {
941                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
942                 if (dl_brk != NULL) {
943                         _dl_debug_addr->r_state = RT_DELETE;
944                         (*dl_brk) ();
945
946                         _dl_debug_addr->r_state = RT_CONSISTENT;
947                         (*dl_brk) ();
948                 }
949         }
950
951         return 0;
952 }
953
954 int dlclose(void *vhandle)
955 {
956         return do_dlclose(vhandle, 1);
957 }
958
959 char *dlerror(void)
960 {
961         const char *retval;
962
963         if (!_dl_error_number)
964                 return NULL;
965         retval = dl_error_names[_dl_error_number];
966         _dl_error_number = 0;
967         return (char *)retval;
968 }
969
970 /*
971  * Dump information to stderr about the current loaded modules
972  */
973 #ifdef __USE_GNU
974 static const char type[][4] = { "Lib", "Exe", "Int", "Mod" };
975
976 int dlinfo(void)
977 {
978         struct elf_resolve *tpnt;
979         struct dyn_elf *rpnt, *hpnt;
980
981         fprintf(stderr, "List of loaded modules\n");
982         /* First start with a complete list of all of the loaded files. */
983         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
984                 fprintf(stderr, "\t%p %p %p %s %d %s\n",
985                         DL_LOADADDR_BASE(tpnt->loadaddr), tpnt, tpnt->symbol_scope,
986                         type[tpnt->libtype],
987                         tpnt->usage_count, tpnt->libname);
988         }
989
990         /* Next dump the module list for the application itself */
991         fprintf(stderr, "\nModules for application (%p):\n", _dl_symbol_tables);
992         for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
993                 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
994
995         for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
996                 fprintf(stderr, "Modules for handle %p\n", hpnt);
997                 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
998                         fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
999         }
1000         return 0;
1001 }
1002
1003 int dladdr(const void *__address, Dl_info * __info)
1004 {
1005         struct elf_resolve *pelf;
1006         struct elf_resolve *rpnt;
1007
1008         _dl_map_cache();
1009
1010         /*
1011          * Try and locate the module address is in
1012          */
1013         pelf = NULL;
1014
1015         _dl_if_debug_print("__address: %p  __info: %p\n", __address, __info);
1016
1017         __address = DL_LOOKUP_ADDRESS (__address);
1018
1019         for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
1020                 struct elf_resolve *tpnt;
1021
1022                 tpnt = rpnt;
1023
1024                 _dl_if_debug_print("Module \"%s\" at %p\n",
1025                                    tpnt->libname, DL_LOADADDR_BASE(tpnt->loadaddr));
1026
1027                 if (DL_ADDR_IN_LOADADDR((ElfW(Addr)) __address, tpnt, pelf))
1028                         pelf = tpnt;
1029         }
1030
1031         if (!pelf) {
1032                 return 0;
1033         }
1034
1035         /*
1036          * Try and locate the symbol of address
1037          */
1038
1039         {
1040                 char *strtab;
1041                 ElfW(Sym) *symtab;
1042                 unsigned int hn, si, sn, sf;
1043                 ElfW(Addr) sa = 0;
1044
1045                 /* Set the info for the object the address lies in */
1046                 __info->dli_fname = pelf->libname;
1047                 __info->dli_fbase = (void *)pelf->mapaddr;
1048
1049                 symtab = (ElfW(Sym) *) (pelf->dynamic_info[DT_SYMTAB]);
1050                 strtab = (char *) (pelf->dynamic_info[DT_STRTAB]);
1051
1052                 sf = sn = 0;
1053
1054 #ifdef __LDSO_GNU_HASH_SUPPORT__
1055                 if (pelf->l_gnu_bitmask) {
1056                         for (hn = 0; hn < pelf->nbucket; hn++) {
1057                                 si = pelf->l_gnu_buckets[hn];
1058                                 if (!si)
1059                                         continue;
1060
1061                                 const Elf32_Word *hasharr = &pelf->l_gnu_chain_zero[si];
1062                                 do {
1063                                         ElfW(Addr) symbol_addr;
1064
1065                                         symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1066                                         if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
1067                                                 sa = symbol_addr;
1068                                                 sn = si;
1069                                                 sf = 1;
1070                                         }
1071                                         _dl_if_debug_print("Symbol \"%s\" at %p\n", strtab + symtab[si].st_name, symbol_addr);
1072                                         ++si;
1073                                 } while ((*hasharr++ & 1u) == 0);
1074                         }
1075                 } else
1076 #endif
1077                 for (hn = 0; hn < pelf->nbucket; hn++) {
1078                         for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
1079                                 ElfW(Addr) symbol_addr;
1080
1081                                 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1082                                 if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
1083                                         sa = symbol_addr;
1084                                         sn = si;
1085                                         sf = 1;
1086                                 }
1087
1088                                 _dl_if_debug_print("Symbol \"%s\" at %p\n",
1089                                                    strtab + symtab[si].st_name, symbol_addr);
1090                         }
1091                 }
1092
1093                 if (sf) {
1094                         /* A nearest symbol has been found; fill the entries */
1095                         __info->dli_sname = strtab + symtab[sn].st_name;
1096                         __info->dli_saddr = (void *)sa;
1097                 } else {
1098                         /* No symbol found, fill entries with NULL value,
1099                         only the containing object will be returned. */
1100                         __info->dli_sname = NULL;
1101                         __info->dli_saddr = NULL;
1102                 }
1103                 return 1;
1104         }
1105 }
1106 #endif