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