]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/ldso/libdl/libdl.c.orig
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / ldso / libdl / libdl.c.orig
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 #include <sys/stat.h> // L4 addition but needed for struct stat (?!)
38
39 #ifdef __UCLIBC_HAS_TLS__
40 #include <tls.h>
41 #endif
42
43 #if defined(USE_TLS) && USE_TLS
44 #include <ldsodefs.h>
45 extern void _dl_add_to_slotinfo(struct link_map  *l);
46 #endif
47
48 #ifdef SHARED
49 # if defined(USE_TLS) && USE_TLS
50 # include <dl-tls.h>
51 extern struct link_map *_dl_update_slotinfo(unsigned long int req_modid);
52 # endif
53
54 /* When libdl is loaded as a shared library, we need to load in
55  * and use a pile of symbols from ldso... */
56
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);
61 extern int _dl_errno;
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);
75 #endif
76 #ifdef __mips__
77 extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy);
78 #endif
79 #ifdef __SUPPORT_LD_DEBUG__
80 extern char *_dl_debug;
81 #endif
82
83 #else /* !SHARED */
84
85 #define _dl_malloc malloc
86 #define _dl_free free
87
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... */
90
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*/;
100 #endif
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;
110
111 #include "../ldso/dl-array.c"
112 #include "../ldso/dl-debug.c"
113
114
115 # if defined(USE_TLS) && USE_TLS
116 /*
117  * Giving this initialized value preallocates some surplus bytes in the
118  * static TLS area, see __libc_setup_tls (libc-tls.c).
119  */
120 size_t _dl_tls_static_size = 2048;
121 # endif
122 #include LDSO_ELFINTERP
123 #include "../ldso/dl-hash.c"
124 #define _dl_trace_loaded_objects    0
125 #include "../ldso/dl-elf.c"
126 #endif /* SHARED */
127
128 #ifdef __SUPPORT_LD_DEBUG__
129 # define _dl_if_debug_print(fmt, args...) \
130         do { \
131         if (_dl_debug) \
132                 fprintf(stderr, "%s():%i: " fmt, __FUNCTION__, __LINE__, ## args); \
133         } while (0)
134 #else
135 # define _dl_if_debug_print(fmt, args...)
136 #endif
137
138 static int do_dlclose(void *, int need_fini);
139
140
141 static const char *const dl_error_names[] = {
142         "",
143         "File not found",
144         "Unable to open /dev/zero",
145         "Not an ELF file",
146 #if defined (__i386__)
147         "Not i386 binary",
148 #elif defined (__sparc__)
149         "Not sparc binary",
150 #elif defined (__mc68000__)
151         "Not m68k binary",
152 #else
153         "Unrecognized binary type",
154 #endif
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",
161 #else
162         "Unable to process RELA relocs",
163 #endif
164         "Bad handle",
165         "Unable to resolve symbol"
166 };
167
168
169 #if defined(USE_TLS) && USE_TLS
170 #ifdef SHARED
171 /*
172  * Systems which do not have tls_index also probably have to define
173  * DONT_USE_TLS_INDEX.
174  */
175
176 # ifndef __TLS_GET_ADDR
177 #  define __TLS_GET_ADDR __tls_get_addr
178 # endif
179
180 /*
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.
183  */
184 static void *
185 internal_function
186 _dl_tls_symaddr(struct link_map *map, const Elf32_Addr st_value)
187 {
188 # ifndef DONT_USE_TLS_INDEX
189         tls_index tmp =
190         {
191                 .ti_module = map->l_tls_modid,
192                 .ti_offset = st_value
193         };
194
195         return __TLS_GET_ADDR (&tmp);
196 # else
197         return __TLS_GET_ADDR (map->l_tls_modid, st_value);
198 # endif
199 }
200 #endif
201
202 /* Returns true when a non-empty entry was found.  */
203 static bool
204 remove_slotinfo(size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
205          bool should_be_there)
206 {
207         if (idx - disp >= listp->len) {
208                 if (listp->next == NULL) {
209                         /*
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.
213                          */
214                         _dl_assert(!should_be_there);
215                 } else {
216                         if (remove_slotinfo(idx, listp->next, disp + listp->len,
217                                         should_be_there))
218                                 return true;
219
220                         /*
221                          * No non-empty entry. Search from the end of this element's
222                          * slotinfo array.
223                          */
224                         idx = disp + listp->len;
225                 }
226         } else {
227                 struct link_map *old_map = listp->slotinfo[idx - disp].map;
228
229                 /*
230                  * The entry might still be in its unused state if we are
231                  * closing an object that wasn't fully set up.
232                  */
233                 if (__builtin_expect(old_map != NULL, 1)) {
234                         _dl_assert(old_map->l_tls_modid == idx);
235
236                         /* Mark the entry as unused. */
237                         listp->slotinfo[idx - disp].gen = _dl_tls_generation + 1;
238                         listp->slotinfo[idx - disp].map = NULL;
239                 }
240
241                 /*
242                  * If this is not the last currently used entry no need to
243                  * look further.
244                  */
245                 if (idx != _dl_tls_max_dtv_idx)
246                         return true;
247         }
248
249         while (idx - disp > (disp == 0 ? 1 + _dl_tls_static_nelem : 0)) {
250                 --idx;
251
252                 if (listp->slotinfo[idx - disp].map != NULL) {
253                         /* Found a new last used index.  */
254                         _dl_tls_max_dtv_idx = idx;
255                         return true;
256                 }
257         }
258
259         /* No non-entry in this list element.  */
260         return false;
261 }
262 #endif
263
264 void dl_cleanup(void) __attribute__ ((destructor));
265 void dl_cleanup(void)
266 {
267         struct dyn_elf *h, *n;
268
269         for (h = _dl_handles; h; h = n) {
270                 n = h->next_handle;
271                 do_dlclose(h, 1);
272         }
273 }
274
275 /* l4: */ void *dlopen(const char *libname, int flag);
276 void *dlopen(const char *libname, int flag)
277 {
278         struct elf_resolve *tpnt, *tfrom;
279         struct dyn_elf *dyn_chain, *rpnt = NULL, *dyn_ptr, *relro_ptr, *handle;
280         ElfW(Addr) from;
281         struct elf_resolve *tpnt1;
282         void (*dl_brk) (void);
283         int now_flag;
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;
290 #endif
291
292         /* A bit of sanity checking... */
293         if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
294                 _dl_error_number = LD_BAD_HANDLE;
295                 return NULL;
296         }
297
298         from = (ElfW(Addr)) __builtin_return_address(0);
299
300         if (!_dl_init) {
301                 _dl_init = true;
302                 _dl_malloc_function = malloc;
303                 _dl_free_function = free;
304         }
305         /* Cover the trivial case first */
306         if (!libname)
307                 return _dl_symbol_tables;
308
309 #ifndef SHARED
310 # ifdef __SUPPORT_LD_DEBUG__
311         _dl_debug = getenv("LD_DEBUG");
312         if (_dl_debug) {
313                 if (_dl_strstr(_dl_debug, "all")) {
314                         _dl_debug_detail = _dl_debug_move = _dl_debug_symbols
315                                 = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = (void*)1;
316                 } else {
317                         _dl_debug_detail   = strstr(_dl_debug, "detail");
318                         _dl_debug_move     = strstr(_dl_debug, "move");
319                         _dl_debug_symbols  = strstr(_dl_debug, "sym");
320                         _dl_debug_reloc    = strstr(_dl_debug, "reloc");
321                         _dl_debug_nofixups = strstr(_dl_debug, "nofix");
322                         _dl_debug_bindings = strstr(_dl_debug, "bind");
323                 }
324         }
325 # endif
326 #endif
327
328         _dl_map_cache();
329
330         /*
331          * Try and locate the module we were called from - we
332          * need this so that we get the correct RPATH/RUNPATH.  Note that
333          * this is the current behavior under Solaris, but the
334          * ABI+ specifies that we should only use the RPATH from
335          * the application.  Thus this may go away at some time
336          * in the future.
337          */
338         {
339                 struct dyn_elf *dpnt;
340                 tfrom = NULL;
341                 for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
342                         tpnt = dpnt->dyn;
343                         if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom))
344                                 tfrom = tpnt;
345                 }
346         }
347         for (rpnt = _dl_symbol_tables; rpnt && rpnt->next; rpnt = rpnt->next)
348                 continue;
349
350         relro_ptr = rpnt;
351         now_flag = (flag & RTLD_NOW) ? RTLD_NOW : 0;
352         if (getenv("LD_BIND_NOW"))
353                 now_flag = RTLD_NOW;
354
355 #ifndef SHARED
356         /* When statically linked, the _dl_library_path is not yet initialized */
357         _dl_library_path = getenv("LD_LIBRARY_PATH");
358 #endif
359
360         /* Try to load the specified library */
361         _dl_if_debug_print("Trying to dlopen '%s', RTLD_GLOBAL:%d RTLD_NOW:%d\n",
362                         (char*)libname, (flag & RTLD_GLOBAL ? 1:0), (now_flag & RTLD_NOW ? 1:0));
363         tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname, 0);
364
365         if (tpnt == NULL) {
366                 _dl_unmap_cache();
367                 return NULL;
368         }
369         dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
370         _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
371         dyn_chain->dyn = tpnt;
372         tpnt->rtld_flags |= (flag & RTLD_GLOBAL);
373
374         dyn_chain->next_handle = _dl_handles;
375         _dl_handles = dyn_ptr = dyn_chain;
376
377         if (tpnt->usage_count > 1) {
378                 _dl_if_debug_print("Lib: %s already opened\n", libname);
379                 /* see if there is a handle from a earlier dlopen */
380                 for (handle = _dl_handles->next_handle; handle; handle = handle->next_handle) {
381                         if (handle->dyn == tpnt) {
382                                 dyn_chain->init_fini.init_fini = handle->init_fini.init_fini;
383                                 dyn_chain->init_fini.nlist = handle->init_fini.nlist;
384                                 for (i = 0; i < dyn_chain->init_fini.nlist; i++)
385                                         dyn_chain->init_fini.init_fini[i]->rtld_flags |= (flag & RTLD_GLOBAL);
386                                 dyn_chain->next = handle->next;
387                                 break;
388                         }
389                 }
390                 return dyn_chain;
391         }
392
393         tpnt->init_flag |= DL_OPENED;
394
395         _dl_if_debug_print("Looking for needed libraries\n");
396         nlist = 0;
397         runp = alloca(sizeof(*runp));
398         runp->tpnt = tpnt;
399         runp->next = NULL;
400         dep_list = runp2 = runp;
401         for (; runp; runp = runp->next) {
402                 ElfW(Dyn) *dpnt;
403                 char *lpntstr;
404
405                 nlist++;
406                 runp->tpnt->init_fini = NULL; /* clear any previous dependcies */
407                 for (dpnt = (ElfW(Dyn) *) runp->tpnt->dynamic_addr; dpnt->d_tag; dpnt++) {
408                         if (dpnt->d_tag == DT_NEEDED) {
409                                 lpntstr = (char*) (runp->tpnt->dynamic_info[DT_STRTAB] +
410                                                 dpnt->d_un.d_val);
411                                 _dl_if_debug_print("Trying to load '%s', needed by '%s'\n",
412                                                 lpntstr, runp->tpnt->libname);
413                                 tpnt1 = _dl_load_shared_library(0, &rpnt, runp->tpnt, lpntstr, 0);
414                                 if (!tpnt1)
415                                         goto oops;
416
417                                 tpnt1->rtld_flags |= (flag & RTLD_GLOBAL);
418
419                                 /* This list is for dlsym() and relocation */
420                                 dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
421                                 _dl_memset (dyn_ptr->next, 0, sizeof (struct dyn_elf));
422                                 dyn_ptr = dyn_ptr->next;
423                                 dyn_ptr->dyn = tpnt1;
424                                 /* Used to record RTLD_LOCAL scope */
425                                 tmp = alloca(sizeof(struct init_fini_list));
426                                 tmp->tpnt = tpnt1;
427                                 tmp->next = runp->tpnt->init_fini;
428                                 runp->tpnt->init_fini = tmp;
429
430                                 for (tmp=dep_list; tmp; tmp = tmp->next) {
431                                         if (tpnt1 == tmp->tpnt) { /* if match => cirular dependency, drop it */
432                                                 _dl_if_debug_print("Circular dependency, skipping '%s',\n",
433                                                                    tmp->tpnt->libname);
434                                                 tpnt1->usage_count--;
435                                                 break;
436                                         }
437                                 }
438                                 if (!tmp) { /* Don't add if circular dependency detected */
439                                         runp2->next = alloca(sizeof(*runp));
440                                         runp2 = runp2->next;
441                                         runp2->tpnt = tpnt1;
442                                         runp2->next = NULL;
443                                 }
444                         }
445                 }
446         }
447         init_fini_list = malloc(nlist * sizeof(struct elf_resolve *));
448         dyn_chain->init_fini.init_fini = init_fini_list;
449         dyn_chain->init_fini.nlist = nlist;
450         i = 0;
451         for (runp2 = dep_list; runp2; runp2 = runp2->next) {
452                 init_fini_list[i++] = runp2->tpnt;
453                 for (runp = runp2->tpnt->init_fini; runp; runp = runp->next) {
454                         if (!(runp->tpnt->rtld_flags & RTLD_GLOBAL)) {
455                                 tmp = malloc(sizeof(struct init_fini_list));
456                                 tmp->tpnt = runp->tpnt;
457                                 tmp->next = runp2->tpnt->rtld_local;
458                                 runp2->tpnt->rtld_local = tmp;
459                         }
460                 }
461
462         }
463         /* Sort the INIT/FINI list in dependency order. */
464         for (runp2 = dep_list; runp2; runp2 = runp2->next) {
465                 unsigned int j, k;
466                 for (j = 0; init_fini_list[j] != runp2->tpnt; ++j)
467                         /* Empty */;
468                 for (k = j + 1; k < nlist; ++k) {
469                         struct init_fini_list *ele = init_fini_list[k]->init_fini;
470
471                         for (; ele; ele = ele->next) {
472                                 if (ele->tpnt == runp2->tpnt) {
473                                         struct elf_resolve *here = init_fini_list[k];
474                                         _dl_if_debug_print("Move %s from pos %d to %d in INIT/FINI list.\n", here->libname, k, j);
475                                         for (i = (k - j); i; --i)
476                                                 init_fini_list[i+j] = init_fini_list[i+j-1];
477                                         init_fini_list[j] = here;
478                                         ++j;
479                                         break;
480                                 }
481                         }
482                 }
483         }
484 #ifdef __SUPPORT_LD_DEBUG__
485         if (_dl_debug) {
486                 fprintf(stderr, "\nINIT/FINI order and dependencies:\n");
487                 for (i = 0; i < nlist; i++) {
488                         fprintf(stderr, "lib: %s has deps:\n", init_fini_list[i]->libname);
489                         runp = init_fini_list[i]->init_fini;
490                         for (; runp; runp = runp->next)
491                                 fprintf(stderr, " %s ", runp->tpnt->libname);
492                         fprintf(stderr, "\n");
493                 }
494         }
495 #endif
496
497         _dl_if_debug_print("Beginning dlopen relocation fixups\n");
498         /*
499          * OK, now all of the kids are tucked into bed in their proper addresses.
500          * Now we go through and look for REL and RELA records that indicate fixups
501          * to the GOT tables.  We need to do this in reverse order so that COPY
502          * directives work correctly */
503 #ifdef __mips__
504         /*
505          * Relocation of the GOT entries for MIPS have to be done
506          * after all the libraries have been loaded.
507          */
508         _dl_perform_mips_global_got_relocations(tpnt, !now_flag);
509 #endif
510
511         if (_dl_fixup(dyn_chain, now_flag))
512                 goto oops;
513
514         if (relro_ptr) {
515                 for (rpnt = relro_ptr->next; rpnt; rpnt = rpnt->next) {
516                         if (rpnt->dyn->relro_size)
517                                 _dl_protect_relro(rpnt->dyn);
518                 }
519         }
520         /* TODO:  Should we set the protections of all pages back to R/O now ? */
521
522
523 #if defined(USE_TLS) && USE_TLS
524
525         for (i=0; i < nlist; i++) {
526                 struct elf_resolve *tmp_tpnt = init_fini_list[i];
527                 /* Only add TLS memory if this object is loaded now and
528                    therefore is not yet initialized.  */
529
530                 if (!(tmp_tpnt->init_flag & INIT_FUNCS_CALLED)
531                 /* Only if the module defines thread local data. */
532                         && __builtin_expect (tmp_tpnt->l_tls_blocksize > 0, 0)) {
533
534                         /* Now that we know the object is loaded successfully add
535                         modules containing TLS data to the slot info table.  We
536                         might have to increase its size.  */
537                         _dl_add_to_slotinfo ((struct link_map*)tmp_tpnt);
538
539                         /* It is the case in which we couldn't perform TLS static
540                            initialization at relocation time, and we delayed it until
541                            the relocation has been completed. */
542
543                         if (tmp_tpnt->l_need_tls_init) {
544                                 tmp_tpnt->l_need_tls_init = 0;
545 # ifdef SHARED
546                                 /* Update the slot information data for at least the
547                                 generation of the DSO we are allocating data for.  */
548                                 _dl_update_slotinfo (tmp_tpnt->l_tls_modid);
549 # endif
550
551                                 _dl_init_static_tls((struct link_map*)tmp_tpnt);
552                                 _dl_assert (tmp_tpnt->l_need_tls_init == 0);
553                 }
554
555                 /* We have to bump the generation counter. */
556                 any_tls = true;
557                 }
558         }
559
560         /* Bump the generation number if necessary.  */
561         if (any_tls && __builtin_expect (++_dl_tls_generation == 0, 0)) {
562                 _dl_debug_early("TLS generation counter wrapped! Please report this.");
563                 _dl_exit(30);
564         }
565
566 #endif
567
568         /* Notify the debugger we have added some objects. */
569         if (_dl_debug_addr) {
570                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
571                 if (dl_brk != NULL) {
572                         _dl_debug_addr->r_state = RT_ADD;
573                         (*dl_brk) ();
574
575                         _dl_debug_addr->r_state = RT_CONSISTENT;
576                         (*dl_brk) ();
577                 }
578         }
579
580         /* Run the ctors and setup the dtors */
581         for (i = nlist; i; --i) {
582                 tpnt = init_fini_list[i-1];
583                 if (tpnt->init_flag & INIT_FUNCS_CALLED)
584                         continue;
585                 tpnt->init_flag |= INIT_FUNCS_CALLED;
586
587                 if (tpnt->dynamic_info[DT_INIT]) {
588                         void (*dl_elf_func) (void);
589                         dl_elf_func = (void (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_INIT]);
590                         if (dl_elf_func) {
591                                 _dl_if_debug_print("running ctors for library %s at '%p'\n",
592                                                 tpnt->libname, dl_elf_func);
593                                 DL_CALL_FUNC_AT_ADDR (dl_elf_func, tpnt->loadaddr, (void(*)(void)));
594                         }
595                 }
596
597                 _dl_run_init_array(tpnt);
598         }
599
600         _dl_unmap_cache();
601         return (void *) dyn_chain;
602
603 oops:
604         /* Something went wrong.  Clean up and return NULL. */
605         _dl_unmap_cache();
606         do_dlclose(dyn_chain, 0);
607         return NULL;
608 }
609
610 /* l4: */ void *dlsym(void *vhandle, const char *name);
611 void *dlsym(void *vhandle, const char *name)
612 {
613         struct elf_resolve *tpnt, *tfrom;
614         struct dyn_elf *handle;
615         ElfW(Addr) from;
616         struct dyn_elf *rpnt;
617         void *ret;
618         struct elf_resolve *tls_tpnt = NULL;
619         /* Nastiness to support underscore prefixes.  */
620 #ifdef __UCLIBC_UNDERSCORES__
621         char tmp_buf[80];
622         char *name2 = tmp_buf;
623         size_t nlen = strlen (name) + 1;
624         if (nlen + 1 > sizeof (tmp_buf))
625                 name2 = malloc (nlen + 1);
626         if (name2 == 0) {
627                 _dl_error_number = LD_ERROR_MMAP_FAILED;
628                 return 0;
629         }
630         name2[0] = '_';
631         memcpy (name2 + 1, name, nlen);
632 #else
633         const char *name2 = name;
634 #endif
635         handle = (struct dyn_elf *) vhandle;
636
637         /* First of all verify that we have a real handle
638            of some kind.  Return NULL if not a valid handle. */
639
640         if (handle == NULL)
641                 handle = _dl_symbol_tables;
642         else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
643                 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
644                         if (rpnt == handle)
645                                 break;
646                 if (!rpnt) {
647                         _dl_error_number = LD_BAD_HANDLE;
648                         ret = NULL;
649                         goto out;
650                 }
651         } else if (handle == RTLD_NEXT) {
652                 /*
653                  * Try and locate the module we were called from - we
654                  * need this so that we know where to start searching
655                  * from.  We never pass RTLD_NEXT down into the actual
656                  * dynamic loader itself, as it doesn't know
657                  * how to properly treat it.
658                  */
659                 from = (ElfW(Addr)) __builtin_return_address(0);
660
661                 tfrom = NULL;
662                 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
663                         tpnt = rpnt->dyn;
664                         if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom)) {
665                                 tfrom = tpnt;
666                                 handle = rpnt->next;
667                         }
668                 }
669         }
670         tpnt = NULL;
671         if (handle == _dl_symbol_tables)
672                 tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
673         ret = _dl_find_hash(name2, handle, NULL, 0, &tls_tpnt);
674
675 #if defined(USE_TLS) && USE_TLS && defined SHARED
676         if (tls_tpnt) {
677                 /* The found symbol is a thread-local storage variable.
678                 Return the address for to the current thread.  */
679                 ret = _dl_tls_symaddr ((struct link_map *)tls_tpnt, (Elf32_Addr)ret);
680         }
681 #endif
682
683         /*
684          * Nothing found.
685          */
686         if (!ret)
687                 _dl_error_number = LD_NO_SYMBOL;
688 out:
689 #ifdef __UCLIBC_UNDERSCORES__
690         if (name2 != tmp_buf)
691                 free (name2);
692 #endif
693         return ret;
694 }
695
696 #if 0
697 void *dlvsym(void *vhandle, const char *name, const char *version)
698 {
699         return dlsym(vhandle, name);
700 }
701 #endif
702
703 static int do_dlclose(void *vhandle, int need_fini)
704 {
705         struct dyn_elf *rpnt, *rpnt1, *rpnt1_tmp;
706         struct init_fini_list *runp, *tmp;
707         ElfW(Phdr) *ppnt;
708         struct elf_resolve *tpnt, *run_tpnt;
709         int (*dl_elf_fini) (void);
710         void (*dl_brk) (void);
711         struct dyn_elf *handle;
712         unsigned int end;
713         unsigned int i, j;
714 #if defined(USE_TLS) && USE_TLS
715         bool any_tls = false;
716         size_t tls_free_start = NO_TLS_OFFSET;
717         size_t tls_free_end = NO_TLS_OFFSET;
718         struct link_map *tls_lmap;
719 #endif
720
721         handle = (struct dyn_elf *) vhandle;
722         if (handle == _dl_symbol_tables)
723                 return 0;
724         rpnt1 = NULL;
725         for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
726                 if (rpnt == handle)
727                         break;
728                 rpnt1 = rpnt;
729         }
730
731         if (!rpnt) {
732                 _dl_error_number = LD_BAD_HANDLE;
733                 return 1;
734         }
735         if (rpnt1)
736                 rpnt1->next_handle = rpnt->next_handle;
737         else
738                 _dl_handles = rpnt->next_handle;
739         _dl_if_debug_print("%s: usage count: %d\n",
740                         handle->dyn->libname, handle->dyn->usage_count);
741         if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & RTLD_NODELETE)) {
742                 handle->dyn->usage_count--;
743                 free(handle);
744                 return 0;
745         }
746         /* OK, this is a valid handle - now close out the file */
747         for (j = 0; j < handle->init_fini.nlist; ++j) {
748                 tpnt = handle->init_fini.init_fini[j];
749                 tpnt->usage_count--;
750                 if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) {
751                         if ((tpnt->dynamic_info[DT_FINI]
752                              || tpnt->dynamic_info[DT_FINI_ARRAY])
753                          && need_fini
754                          && !(tpnt->init_flag & FINI_FUNCS_CALLED)
755                         ) {
756                                 tpnt->init_flag |= FINI_FUNCS_CALLED;
757                                 _dl_run_fini_array(tpnt);
758
759                                 if (tpnt->dynamic_info[DT_FINI]) {
760                                         dl_elf_fini = (int (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_FINI]);
761                                         _dl_if_debug_print("running dtors for library %s at '%p'\n",
762                                                         tpnt->libname, dl_elf_fini);
763                                         DL_CALL_FUNC_AT_ADDR (dl_elf_fini, tpnt->loadaddr, (int (*)(void)));
764                                 }
765                         }
766
767                         _dl_if_debug_print("unmapping: %s\n", tpnt->libname);
768                         end = 0;
769                         for (i = 0, ppnt = tpnt->ppnt;
770                                         i < tpnt->n_phent; ppnt++, i++) {
771                                 if (ppnt->p_type != PT_LOAD)
772                                         continue;
773                                 if (end < ppnt->p_vaddr + ppnt->p_memsz)
774                                         end = ppnt->p_vaddr + ppnt->p_memsz;
775                         }
776
777 #if defined(USE_TLS) && USE_TLS
778                         /* Do the cast to make things easy. */
779                         tls_lmap = (struct link_map *) tpnt;
780
781                         /* Remove the object from the dtv slotinfo array if it uses TLS. */
782                         if (__builtin_expect (tls_lmap->l_tls_blocksize > 0, 0)) {
783                                 any_tls = true;
784
785                                 if (_dl_tls_dtv_slotinfo_list != NULL
786                                                 && ! remove_slotinfo (tls_lmap->l_tls_modid,
787                                                 _dl_tls_dtv_slotinfo_list, 0,
788                                                 (tpnt->init_flag & INIT_FUNCS_CALLED)))
789                                         /* All dynamically loaded modules with TLS are unloaded. */
790                                         _dl_tls_max_dtv_idx = _dl_tls_static_nelem;
791
792                                 if (tls_lmap->l_tls_offset != NO_TLS_OFFSET) {
793                                         /*
794                                          * Collect a contiguous chunk built from the objects in
795                                          * this search list, going in either direction.  When the
796                                          * whole chunk is at the end of the used area then we can
797                                          * reclaim it.
798                                          */
799 # if defined(TLS_TCB_AT_TP)
800                                         if (tls_free_start == NO_TLS_OFFSET
801                                                 || (size_t) tls_lmap->l_tls_offset == tls_free_start) {
802                                                 /* Extend the contiguous chunk being reclaimed. */
803                                                 tls_free_start
804                                                         = tls_lmap->l_tls_offset -
805                                                           tls_lmap->l_tls_blocksize;
806
807                                                 if (tls_free_end == NO_TLS_OFFSET)
808                                                         tls_free_end = tls_lmap->l_tls_offset;
809                                         } else if (tls_lmap->l_tls_offset - tls_lmap->l_tls_blocksize
810                                                         == tls_free_end)
811                                                 /* Extend the chunk backwards.  */
812                                                 tls_free_end = tls_lmap->l_tls_offset;
813                                         else {
814                                                 /*
815                                                  * This isn't contiguous with the last chunk freed.
816                                                  * One of them will be leaked unless we can free
817                                                  * one block right away.
818                                                  */
819                                                 if (tls_free_end == _dl_tls_static_used) {
820                                                         _dl_tls_static_used = tls_free_start;
821                                                         tls_free_end = tls_lmap->l_tls_offset;
822                                                         tls_free_start
823                                                                 = tls_free_end - tls_lmap->l_tls_blocksize;
824                                                 } else if ((size_t) tls_lmap->l_tls_offset
825                                                                 == _dl_tls_static_used)
826                                                         _dl_tls_static_used = tls_lmap->l_tls_offset -
827                                                                 tls_lmap->l_tls_blocksize;
828                                                 else if (tls_free_end < (size_t) tls_lmap->l_tls_offset) {
829                                                         /*
830                                                          * We pick the later block. It has a chance
831                                                          * to be freed.
832                                                          */
833                                                         tls_free_end = tls_lmap->l_tls_offset;
834                                                         tls_free_start = tls_free_end -
835                                                                 tls_lmap->l_tls_blocksize;
836                                                 }
837                                         }
838 # elif defined(TLS_DTV_AT_TP)
839                                         if ((size_t) tls_lmap->l_tls_offset == tls_free_end)
840                                                 /* Extend the contiguous chunk being reclaimed. */
841                                                 tls_free_end -= tls_lmap->l_tls_blocksize;
842                                         else if (tls_lmap->l_tls_offset + tls_lmap->l_tls_blocksize
843                                                         == tls_free_start)
844                                                 /* Extend the chunk backwards. */
845                                                 tls_free_start = tls_lmap->l_tls_offset;
846                                         else {
847                                                 /*
848                                                  * This isn't contiguous with the last chunk
849                                                  * freed. One of them will be leaked.
850                                                  */
851                                                 if (tls_free_end == _dl_tls_static_used)
852                                                         _dl_tls_static_used = tls_free_start;
853                                                 tls_free_start = tls_lmap->l_tls_offset;
854                                                 tls_free_end = tls_free_start +
855                                                         tls_lmap->l_tls_blocksize;
856                                         }
857 # else
858 #  error Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined
859 # endif
860                                 } else {
861
862 #define TLS_DTV_UNALLOCATED     ((void *) -1l)
863
864                                         dtv_t *dtv = THREAD_DTV ();
865
866                                         _dl_assert(!(dtv[tls_lmap->l_tls_modid].pointer.is_static));
867                                         if (dtv[tls_lmap->l_tls_modid].pointer.val != TLS_DTV_UNALLOCATED) {
868                                                 /* Note that free is called for NULL is well.  We
869                                                 deallocate even if it is this dtv entry we are
870                                                 supposed to load.  The reason is that we call
871                                                 memalign and not malloc.  */
872                                                 _dl_free (dtv[tls_lmap->l_tls_modid].pointer.val);
873                                                 dtv[tls_lmap->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
874                                         }
875                                 }
876                         }
877 #endif
878
879                         DL_LIB_UNMAP (tpnt, end);
880                         /* Free elements in RTLD_LOCAL scope list */
881                         for (runp = tpnt->rtld_local; runp; runp = tmp) {
882                                 tmp = runp->next;
883                                 free(runp);
884                         }
885
886                         /* Next, remove tpnt from the loaded_module list */
887                         if (_dl_loaded_modules == tpnt) {
888                                 _dl_loaded_modules = tpnt->next;
889                                 if (_dl_loaded_modules)
890                                         _dl_loaded_modules->prev = 0;
891                         } else {
892                                 for (run_tpnt = _dl_loaded_modules; run_tpnt; run_tpnt = run_tpnt->next) {
893                                         if (run_tpnt->next == tpnt) {
894                                                 _dl_if_debug_print("removing loaded_modules: %s\n", tpnt->libname);
895                                                 run_tpnt->next = run_tpnt->next->next;
896                                                 if (run_tpnt->next)
897                                                         run_tpnt->next->prev = run_tpnt;
898                                                 break;
899                                         }
900                                 }
901                         }
902
903                         /* Next, remove tpnt from the global symbol table list */
904                         if (_dl_symbol_tables) {
905                                 if (_dl_symbol_tables->dyn == tpnt) {
906                                         _dl_symbol_tables = _dl_symbol_tables->next;
907                                         if (_dl_symbol_tables)
908                                                 _dl_symbol_tables->prev = 0;
909                                 } else {
910                                         for (rpnt1 = _dl_symbol_tables; rpnt1->next; rpnt1 = rpnt1->next) {
911                                                 if (rpnt1->next->dyn == tpnt) {
912                                                         _dl_if_debug_print("removing symbol_tables: %s\n", tpnt->libname);
913                                                         rpnt1_tmp = rpnt1->next->next;
914                                                         free(rpnt1->next);
915                                                         rpnt1->next = rpnt1_tmp;
916                                                         if (rpnt1->next)
917                                                                 rpnt1->next->prev = rpnt1;
918                                                         break;
919                                                 }
920                                         }
921                                 }
922                         }
923                         free(tpnt->libname);
924                         free(tpnt);
925                 }
926         }
927         free(handle->init_fini.init_fini);
928         free(handle);
929
930 #if defined(USE_TLS) && USE_TLS
931         /* If we removed any object which uses TLS bump the generation counter.  */
932         if (any_tls) {
933                 if (__builtin_expect(++_dl_tls_generation == 0, 0)) {
934                         _dl_debug_early("TLS generation counter wrapped!  Please report to the uClibc mailing list.\n");
935                         _dl_exit(30);
936                 }
937
938                 if (tls_free_end == _dl_tls_static_used)
939                         _dl_tls_static_used = tls_free_start;
940         }
941 #endif
942
943         if (_dl_debug_addr) {
944                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
945                 if (dl_brk != NULL) {
946                         _dl_debug_addr->r_state = RT_DELETE;
947                         (*dl_brk) ();
948
949                         _dl_debug_addr->r_state = RT_CONSISTENT;
950                         (*dl_brk) ();
951                 }
952         }
953
954         return 0;
955 }
956
957 /* l4: */ int dlclose(void *vhandle);
958 int dlclose(void *vhandle)
959 {
960         return do_dlclose(vhandle, 1);
961 }
962
963 /* l4: */ char *dlerror(void);
964 char *dlerror(void)
965 {
966         const char *retval;
967
968         if (!_dl_error_number)
969                 return NULL;
970         retval = dl_error_names[_dl_error_number];
971         _dl_error_number = 0;
972         return (char *)retval;
973 }
974
975 /*
976  * Dump information to stderr about the current loaded modules
977  */
978 #ifdef __USE_GNU
979 static const char type[][4] = { "Lib", "Exe", "Int", "Mod" };
980
981 /* l4: */int dlinfo(void);
982 int dlinfo(void)
983 {
984         struct elf_resolve *tpnt;
985         struct dyn_elf *rpnt, *hpnt;
986
987         fprintf(stderr, "List of loaded modules\n");
988         /* First start with a complete list of all of the loaded files. */
989         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
990                 fprintf(stderr, "\t%p %p %p %s %d %s\n",
991                         (void *)DL_LOADADDR_BASE(tpnt->loadaddr), tpnt, tpnt->symbol_scope,
992                         type[tpnt->libtype],
993                         tpnt->usage_count, tpnt->libname);
994         }
995
996         /* Next dump the module list for the application itself */
997         fprintf(stderr, "\nModules for application (%p):\n", _dl_symbol_tables);
998         for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
999                 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1000
1001         for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
1002                 fprintf(stderr, "Modules for handle %p\n", hpnt);
1003                 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
1004                         fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1005         }
1006         return 0;
1007 }
1008
1009 /* l4: */int dladdr(const void *__address, Dl_info * __info);
1010 int dladdr(const void *__address, Dl_info * __info)
1011 {
1012         struct elf_resolve *pelf;
1013         struct elf_resolve *rpnt;
1014
1015         _dl_map_cache();
1016
1017         /*
1018          * Try and locate the module address is in
1019          */
1020         pelf = NULL;
1021
1022         _dl_if_debug_print("__address: %p  __info: %p\n", __address, __info);
1023
1024         __address = DL_LOOKUP_ADDRESS (__address);
1025
1026         for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
1027                 struct elf_resolve *tpnt;
1028
1029                 tpnt = rpnt;
1030
1031                 _dl_if_debug_print("Module \"%s\" at %p\n",
1032                                    tpnt->libname, (void *)DL_LOADADDR_BASE(tpnt->loadaddr));
1033
1034                 if (DL_ADDR_IN_LOADADDR((ElfW(Addr)) __address, tpnt, pelf))
1035                         pelf = tpnt;
1036         }
1037
1038         if (!pelf) {
1039                 return 0;
1040         }
1041
1042         /*
1043          * Try and locate the symbol of address
1044          */
1045
1046         {
1047                 char *strtab;
1048                 ElfW(Sym) *symtab;
1049                 unsigned int hn, si, sn, sf;
1050                 ElfW(Addr) sa = 0;
1051
1052                 /* Set the info for the object the address lies in */
1053                 __info->dli_fname = pelf->libname;
1054                 __info->dli_fbase = (void *)pelf->mapaddr;
1055
1056                 symtab = (ElfW(Sym) *) (pelf->dynamic_info[DT_SYMTAB]);
1057                 strtab = (char *) (pelf->dynamic_info[DT_STRTAB]);
1058
1059                 sf = sn = 0;
1060
1061 #ifdef __LDSO_GNU_HASH_SUPPORT__
1062                 if (pelf->l_gnu_bitmask) {
1063                         for (hn = 0; hn < pelf->nbucket; hn++) {
1064                                 si = pelf->l_gnu_buckets[hn];
1065                                 if (!si)
1066                                         continue;
1067
1068                                 const Elf32_Word *hasharr = &pelf->l_gnu_chain_zero[si];
1069                                 do {
1070                                         ElfW(Addr) symbol_addr;
1071
1072                                         symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1073                                         if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
1074                                                 sa = symbol_addr;
1075                                                 sn = si;
1076                                                 sf = 1;
1077                                         }
1078                                         _dl_if_debug_print("Symbol \"%s\" at %p\n", strtab + symtab[si].st_name, (void *)symbol_addr);
1079                                         ++si;
1080                                 } while ((*hasharr++ & 1u) == 0);
1081                         }
1082                 } else
1083 #endif
1084                 for (hn = 0; hn < pelf->nbucket; hn++) {
1085                         for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
1086                                 ElfW(Addr) symbol_addr;
1087
1088                                 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1089                                 if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
1090                                         sa = symbol_addr;
1091                                         sn = si;
1092                                         sf = 1;
1093                                 }
1094
1095                                 _dl_if_debug_print("Symbol \"%s\" at %p\n",
1096                                                    strtab + symtab[si].st_name, (void *)symbol_addr);
1097                         }
1098                 }
1099
1100                 if (sf) {
1101                         /* A nearest symbol has been found; fill the entries */
1102                         __info->dli_sname = strtab + symtab[sn].st_name;
1103                         __info->dli_saddr = (void *)sa;
1104                 } else {
1105                         /* No symbol found, fill entries with NULL value,
1106                         only the containing object will be returned. */
1107                         __info->dli_sname = NULL;
1108                         __info->dli_saddr = NULL;
1109                 }
1110                 return 1;
1111         }
1112 }
1113 #endif