OSDN Git Service

mkostemp: fix implementation
[uclinux-h8/uClibc.git] / ldso / libdl / libdl.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Program to load an ELF binary on a linux system, and run it
4  * after resolving ELF shared library symbols
5  *
6  * Copyright (C) 2000-2006 by Erik Andersen <andersen@uclibc.org>
7  * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
8  *                              David Engel, Hongjiu Lu and Mitch D'Souza
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. The name of the above contributors may not be
16  *    used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32
33 #include <ldso.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdbool.h>
37 #include <bits/uClibc_mutex.h>
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 #include <dl-tls.h>
46 extern void _dl_add_to_slotinfo(struct link_map  *l);
47 #endif
48
49 /* TODO: get rid of global lock and use more finegrained locking, or
50  * perhaps RCU for the global structures */
51 __UCLIBC_MUTEX_STATIC(_dl_mutex, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
52
53 #ifdef SHARED
54 # if defined(USE_TLS) && USE_TLS
55 extern struct link_map *_dl_update_slotinfo(unsigned long int req_modid);
56 # endif
57
58 /* When libdl is loaded as a shared library, we need to load in
59  * and use a pile of symbols from ldso... */
60 #include <dl-elf.h>
61 #if 0
62 extern struct elf_resolve * _dl_load_shared_library(unsigned, struct dyn_elf **,
63         struct elf_resolve *, char *, int);
64 extern int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int lazy);
65 extern void _dl_protect_relro(struct elf_resolve * tpnt);
66 #endif
67 extern int _dl_errno;
68 extern struct dyn_elf *_dl_symbol_tables;
69 extern struct dyn_elf *_dl_handles;
70 extern struct elf_resolve *_dl_loaded_modules;
71 extern void _dl_free (void *__ptr);
72 extern struct r_debug *_dl_debug_addr;
73 extern unsigned long _dl_error_number;
74 extern void *(*_dl_malloc_function)(size_t);
75 extern void (*_dl_free_function) (void *p);
76 extern void _dl_run_init_array(struct elf_resolve *);
77 extern void _dl_run_fini_array(struct elf_resolve *);
78 #ifdef __LDSO_CACHE_SUPPORT__
79 int _dl_map_cache(void);
80 int _dl_unmap_cache(void);
81 #endif
82 #ifdef __mips__
83 extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy);
84 #endif
85 #ifdef __SUPPORT_LD_DEBUG__
86 extern char *_dl_debug;
87 #endif
88
89 #else /* !SHARED */
90
91 #define _dl_malloc malloc
92 #define _dl_free free
93
94 /* When libdl is linked as a static library, we need to replace all
95  * the symbols that otherwise would have been loaded in from ldso... */
96
97 #ifdef __SUPPORT_LD_DEBUG__
98 char *_dl_debug  = NULL;
99 char *_dl_debug_symbols   = NULL;
100 char *_dl_debug_move      = NULL;
101 char *_dl_debug_reloc     = NULL;
102 char *_dl_debug_detail    = NULL;
103 char *_dl_debug_nofixups  = NULL;
104 char *_dl_debug_bindings  = NULL;
105 int   _dl_debug_file      = 2;
106 #endif
107 const char *_dl_progname       = "";        /* Program name */
108 void *(*_dl_malloc_function)(size_t);
109 void (*_dl_free_function) (void *p);
110 #ifdef __LDSO_LD_LIBRARY_PATH__
111 char *_dl_library_path         = NULL;         /* Where we look for libraries */
112 #endif
113 int _dl_errno                  = 0;         /* We can't use the real errno in ldso */
114 size_t _dl_pagesize            = PAGE_SIZE; /* Store the page size for use later */
115 /* This global variable is also to communicate with debuggers such as gdb. */
116 struct r_debug *_dl_debug_addr = NULL;
117
118 #include "../ldso/dl-array.c"
119 #include "../ldso/dl-debug.c"
120
121
122 # if defined(USE_TLS) && USE_TLS
123 /*
124  * Giving this initialized value preallocates some surplus bytes in the
125  * static TLS area, see __libc_setup_tls (libc-tls.c).
126  */
127 size_t _dl_tls_static_size = 2048;
128 # endif
129 #include LDSO_ELFINTERP
130 #include "../ldso/dl-hash.c"
131 #define _dl_trace_loaded_objects    0
132 #include "../ldso/dl-elf.c"
133 #endif /* SHARED */
134
135 #ifdef __SUPPORT_LD_DEBUG__
136 # define _dl_if_debug_print(fmt, args...) \
137         do { \
138         if (_dl_debug) \
139                 fprintf(stderr, "%s():%i: " fmt, __func__, __LINE__, ## args); \
140         } while (0)
141 #else
142 # define _dl_if_debug_print(fmt, args...)
143 #endif
144
145 static int do_dlclose(void *, int need_fini);
146
147
148 static const char *const dl_error_names[] = {
149         "",
150         "File not found",
151         "Unable to open /dev/zero",
152         "Not an ELF file",
153 #if defined (__i386__)
154         "Not i386 binary",
155 #elif defined (__sparc__)
156         "Not sparc binary",
157 #elif defined (__mc68000__)
158         "Not m68k binary",
159 #else
160         "Unrecognized binary type",
161 #endif
162         "Not an ELF shared library",
163         "Unable to mmap file",
164         "No dynamic section",
165         "Library contains unsupported TLS",
166 #ifdef ELF_USES_RELOCA
167         "Unable to process REL relocs",
168 #else
169         "Unable to process RELA relocs",
170 #endif
171         "Bad handle",
172         "Unable to resolve symbol"
173 };
174
175
176 #if defined(USE_TLS) && USE_TLS
177 #ifdef SHARED
178 /*
179  * Systems which do not have tls_index also probably have to define
180  * DONT_USE_TLS_INDEX.
181  */
182
183 # ifndef __TLS_GET_ADDR
184 #  define __TLS_GET_ADDR __tls_get_addr
185 # endif
186
187 /*
188  * Return the symbol address given the map of the module it is in and
189  *  the symbol record.  This is used in dl-sym.c.
190  */
191 static void *
192 internal_function
193 _dl_tls_symaddr(struct link_map *map, const Elf32_Addr st_value)
194 {
195 # ifndef DONT_USE_TLS_INDEX
196         tls_index tmp =
197         {
198                 .ti_module = map->l_tls_modid,
199                 .ti_offset = st_value
200         };
201
202         return __TLS_GET_ADDR (&tmp);
203 # else
204         return __TLS_GET_ADDR (map->l_tls_modid, st_value);
205 # endif
206 }
207 #endif
208
209 /* Returns true when a non-empty entry was found.  */
210 static bool
211 remove_slotinfo(size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
212          bool should_be_there)
213 {
214         if (idx - disp >= listp->len) {
215                 if (listp->next == NULL) {
216                         /*
217                          * The index is not actually valid in the slotinfo list,
218                          * because this object was closed before it was fully set
219                          * up due to some error.
220                          */
221                         _dl_assert(!should_be_there);
222                 } else {
223                         if (remove_slotinfo(idx, listp->next, disp + listp->len,
224                                         should_be_there))
225                                 return true;
226
227                         /*
228                          * No non-empty entry. Search from the end of this element's
229                          * slotinfo array.
230                          */
231                         idx = disp + listp->len;
232                 }
233         } else {
234                 struct link_map *old_map = listp->slotinfo[idx - disp].map;
235
236                 /*
237                  * The entry might still be in its unused state if we are
238                  * closing an object that wasn't fully set up.
239                  */
240                 if (__builtin_expect(old_map != NULL, 1)) {
241                         _dl_assert(old_map->l_tls_modid == idx);
242
243                         /* Mark the entry as unused. */
244                         listp->slotinfo[idx - disp].gen = _dl_tls_generation + 1;
245                         listp->slotinfo[idx - disp].map = NULL;
246                 }
247
248                 /*
249                  * If this is not the last currently used entry no need to
250                  * look further.
251                  */
252                 if (idx != _dl_tls_max_dtv_idx)
253                         return true;
254         }
255
256         while (idx - disp > (disp == 0 ? 1 + _dl_tls_static_nelem : 0)) {
257                 --idx;
258
259                 if (listp->slotinfo[idx - disp].map != NULL) {
260                         /* Found a new last used index.  */
261                         _dl_tls_max_dtv_idx = idx;
262                         return true;
263                 }
264         }
265
266         /* No non-entry in this list element.  */
267         return false;
268 }
269 #endif
270
271 #ifndef __LDSO_NO_CLEANUP__
272 void dl_cleanup(void) attribute_hidden __attribute__ ((destructor));
273 void dl_cleanup(void)
274 {
275         struct dyn_elf *h, *n;
276
277         for (h = _dl_handles; h; h = n) {
278                 n = h->next_handle;
279                 do_dlclose(h, 1);
280         }
281 }
282 #endif
283
284 static ptrdiff_t _dl_build_local_scope (struct elf_resolve **list,
285         struct elf_resolve *map)
286 {
287         struct elf_resolve **p = list;
288         struct init_fini_list *q;
289
290         *p++ = map;
291         map->init_flag |= DL_RESERVED;
292         if (map->init_fini)
293                 for (q = map->init_fini; q; q = q->next)
294                         if (! (q->tpnt->init_flag & DL_RESERVED))
295                                 p += _dl_build_local_scope (p, q->tpnt);
296         return p - list;
297 }
298
299 static void *do_dlopen(const char *libname, int flag, ElfW(Addr) from)
300 {
301         struct elf_resolve *tpnt, *tfrom;
302         struct dyn_elf *dyn_chain, *rpnt = NULL, *dyn_ptr, *relro_ptr, *handle;
303         struct elf_resolve *tpnt1;
304         void (*dl_brk) (void);
305         int now_flag;
306         struct init_fini_list *tmp, *runp, *runp2, *dep_list;
307         unsigned int nlist, i;
308         struct elf_resolve **init_fini_list;
309         static bool _dl_init;
310         struct elf_resolve **local_scope;
311 #ifdef SHARED
312         struct r_scope_elem *ls;
313 #endif
314 #if defined(USE_TLS) && USE_TLS
315         bool any_tls = false;
316 #endif
317
318         /* A bit of sanity checking... */
319         if (!(flag & (RTLD_LAZY|RTLD_NOW|RTLD_NOLOAD))) {
320                 _dl_error_number = LD_BAD_HANDLE;
321                 return NULL;
322         }
323
324         if (!_dl_init) {
325                 _dl_init = true;
326                 _dl_malloc_function = malloc;
327                 _dl_free_function = free;
328         }
329         /* Cover the trivial case first */
330         if (!libname)
331                 return _dl_symbol_tables;
332
333 #ifndef SHARED
334 # ifdef __SUPPORT_LD_DEBUG__
335         _dl_debug = getenv("LD_DEBUG");
336         if (_dl_debug) {
337                 if (strstr(_dl_debug, "all")) {
338                         _dl_debug_detail = _dl_debug_move = _dl_debug_symbols
339                                 = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = (void*)1;
340                 } else {
341                         _dl_debug_detail   = strstr(_dl_debug, "detail");
342                         _dl_debug_move     = strstr(_dl_debug, "move");
343                         _dl_debug_symbols  = strstr(_dl_debug, "sym");
344                         _dl_debug_reloc    = strstr(_dl_debug, "reloc");
345                         _dl_debug_nofixups = strstr(_dl_debug, "nofix");
346                         _dl_debug_bindings = strstr(_dl_debug, "bind");
347                 }
348         }
349 # endif
350 #endif
351
352         _dl_map_cache();
353
354         /*
355          * Try and locate the module we were called from - we
356          * need this so that we get the correct RPATH/RUNPATH.  Note that
357          * this is the current behavior under Solaris, but the
358          * ABI+ specifies that we should only use the RPATH from
359          * the application.  Thus this may go away at some time
360          * in the future.
361          */
362         {
363                 struct dyn_elf *dpnt;
364                 tfrom = NULL;
365                 for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
366                         tpnt = dpnt->dyn;
367                         if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom))
368                                 tfrom = tpnt;
369                 }
370         }
371         for (rpnt = _dl_symbol_tables; rpnt && rpnt->next; rpnt = rpnt->next)
372                 continue;
373
374         relro_ptr = rpnt;
375         now_flag = (flag & RTLD_NOW) ? RTLD_NOW : 0;
376         if (getenv("LD_BIND_NOW"))
377                 now_flag = RTLD_NOW;
378
379 #if !defined SHARED && defined __LDSO_LD_LIBRARY_PATH__
380         /* When statically linked, the _dl_library_path is not yet initialized */
381         _dl_library_path = getenv("LD_LIBRARY_PATH");
382 #endif
383
384         /* Try to load the specified library */
385         _dl_if_debug_print("Trying to dlopen '%s', RTLD_GLOBAL:%d RTLD_NOW:%d\n",
386                         (char*)libname, (flag & RTLD_GLOBAL ? 1:0), (now_flag & RTLD_NOW ? 1:0));
387
388         tpnt = _dl_load_shared_library((flag & RTLD_NOLOAD) ? DL_RESOLVE_NOLOAD : 0,
389                                         &rpnt, tfrom, (char*)libname, 0);
390         if (tpnt == NULL) {
391                 _dl_unmap_cache();
392                 return NULL;
393         }
394         dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
395         memset(dyn_chain, 0, sizeof(struct dyn_elf));
396         dyn_chain->dyn = tpnt;
397         tpnt->rtld_flags |= (flag & RTLD_GLOBAL);
398
399         dyn_chain->next_handle = _dl_handles;
400         _dl_handles = dyn_ptr = dyn_chain;
401
402         if (tpnt->usage_count > 1) {
403                 _dl_if_debug_print("Lib: %s already opened\n", libname);
404                 /* see if there is a handle from a earlier dlopen */
405                 for (handle = _dl_handles->next_handle; handle; handle = handle->next_handle) {
406                         if (handle->dyn == tpnt) {
407                                 dyn_chain->init_fini.init_fini = handle->init_fini.init_fini;
408                                 dyn_chain->init_fini.nlist = handle->init_fini.nlist;
409                                 for (i = 0; i < dyn_chain->init_fini.nlist; i++)
410                                         dyn_chain->init_fini.init_fini[i]->rtld_flags |= (flag & RTLD_GLOBAL);
411                                 dyn_chain->next = handle->next;
412                                 break;
413                         }
414                 }
415                 return dyn_chain;
416         }
417
418         tpnt->init_flag |= DL_OPENED;
419
420         _dl_if_debug_print("Looking for needed libraries\n");
421         nlist = 0;
422         runp = alloca(sizeof(*runp));
423         runp->tpnt = tpnt;
424         runp->next = NULL;
425         dep_list = runp2 = runp;
426         for (; runp; runp = runp->next) {
427                 ElfW(Dyn) *dpnt;
428                 char *lpntstr;
429
430                 nlist++;
431                 runp->tpnt->init_fini = NULL; /* clear any previous dependcies */
432                 for (dpnt = (ElfW(Dyn) *) runp->tpnt->dynamic_addr; dpnt->d_tag; dpnt++) {
433                         if (dpnt->d_tag == DT_NEEDED) {
434                                 lpntstr = (char*) (runp->tpnt->dynamic_info[DT_STRTAB] +
435                                                 dpnt->d_un.d_val);
436                                 _dl_if_debug_print("Trying to load '%s', needed by '%s'\n",
437                                                 lpntstr, runp->tpnt->libname);
438                                 tpnt1 = _dl_load_shared_library(0, &rpnt, runp->tpnt, lpntstr, 0);
439                                 if (!tpnt1)
440                                         goto oops;
441
442                                 tpnt1->rtld_flags |= (flag & RTLD_GLOBAL);
443
444                                 /* This list is for dlsym() and relocation */
445                                 dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
446                                 memset (dyn_ptr->next, 0, sizeof (struct dyn_elf));
447                                 dyn_ptr = dyn_ptr->next;
448                                 dyn_ptr->dyn = tpnt1;
449                                 /* Used to record RTLD_LOCAL scope */
450                                 tmp = alloca(sizeof(struct init_fini_list));
451                                 tmp->tpnt = tpnt1;
452                                 tmp->next = runp->tpnt->init_fini;
453                                 runp->tpnt->init_fini = tmp;
454
455                                 for (tmp=dep_list; tmp; tmp = tmp->next) {
456                                         if (tpnt1 == tmp->tpnt) { /* if match => cirular dependency, drop it */
457                                                 _dl_if_debug_print("Circular dependency, skipping '%s',\n",
458                                                                    tmp->tpnt->libname);
459                                                 tpnt1->usage_count--;
460                                                 break;
461                                         }
462                                 }
463                                 if (!tmp) { /* Don't add if circular dependency detected */
464                                         runp2->next = alloca(sizeof(*runp));
465                                         runp2 = runp2->next;
466                                         runp2->tpnt = tpnt1;
467                                         runp2->next = NULL;
468                                 }
469                         }
470                 }
471         }
472         init_fini_list = malloc(nlist * sizeof(struct elf_resolve *));
473         dyn_chain->init_fini.init_fini = init_fini_list;
474         dyn_chain->init_fini.nlist = nlist;
475         i = 0;
476         for (runp2 = dep_list; runp2; runp2 = runp2->next) {
477                 init_fini_list[i++] = runp2->tpnt;
478                 for (runp = runp2->tpnt->init_fini; runp; runp = runp->next) {
479                         if (!(runp->tpnt->rtld_flags & RTLD_GLOBAL)) {
480                                 tmp = malloc(sizeof(struct init_fini_list));
481                                 tmp->tpnt = runp->tpnt;
482                                 tmp->next = runp2->tpnt->rtld_local;
483                                 runp2->tpnt->rtld_local = tmp;
484                         }
485                 }
486
487         }
488         /* Build the local scope for the dynamically loaded modules. */
489         local_scope = _dl_malloc(nlist * sizeof(struct elf_resolve *)); /* Could it allocated on stack? */
490         for (i = 0; i < nlist; i++)
491                 if (init_fini_list[i]->symbol_scope.r_nlist == 0) {
492                         int k, cnt;
493                         cnt = _dl_build_local_scope(local_scope, init_fini_list[i]);
494                         init_fini_list[i]->symbol_scope.r_list = _dl_malloc(cnt * sizeof(struct elf_resolve *));
495                         init_fini_list[i]->symbol_scope.r_nlist = cnt;
496                         _dl_memcpy (init_fini_list[i]->symbol_scope.r_list, local_scope,
497                                         cnt * sizeof (struct elf_resolve *));
498                         /* Restoring the init_flag.*/
499                         for (k = 0; k < nlist; k++)
500                                 init_fini_list[k]->init_flag &= ~DL_RESERVED;
501                 }
502
503         _dl_free(local_scope);
504
505         /* Sort the INIT/FINI list in dependency order. */
506         for (runp2 = dep_list; runp2; runp2 = runp2->next) {
507                 unsigned int j, k;
508                 for (j = 0; init_fini_list[j] != runp2->tpnt; ++j)
509                         /* Empty */;
510                 for (k = j + 1; k < nlist; ++k) {
511                         struct init_fini_list *ele = init_fini_list[k]->init_fini;
512
513                         for (; ele; ele = ele->next) {
514                                 if (ele->tpnt == runp2->tpnt) {
515                                         struct elf_resolve *here = init_fini_list[k];
516                                         _dl_if_debug_print("Move %s from pos %d to %d in INIT/FINI list.\n", here->libname, k, j);
517                                         for (i = (k - j); i; --i)
518                                                 init_fini_list[i+j] = init_fini_list[i+j-1];
519                                         init_fini_list[j] = here;
520                                         ++j;
521                                         break;
522                                 }
523                         }
524                 }
525         }
526 #ifdef __SUPPORT_LD_DEBUG__
527         if (_dl_debug) {
528                 fprintf(stderr, "\nINIT/FINI order and dependencies:\n");
529                 for (i = 0; i < nlist; i++) {
530                         fprintf(stderr, "lib: %s has deps:\n", init_fini_list[i]->libname);
531                         runp = init_fini_list[i]->init_fini;
532                         for (; runp; runp = runp->next)
533                                 fprintf(stderr, " %s ", runp->tpnt->libname);
534                         fprintf(stderr, "\n");
535                 }
536         }
537 #endif
538
539         _dl_if_debug_print("Beginning dlopen relocation fixups\n");
540         /*
541          * OK, now all of the kids are tucked into bed in their proper addresses.
542          * Now we go through and look for REL and RELA records that indicate fixups
543          * to the GOT tables.  We need to do this in reverse order so that COPY
544          * directives work correctly */
545
546 #ifdef SHARED
547         /*
548          * Get the tail of the list.
549          * In the static case doesn't need to extend the global scope, it is
550          * ready to be used as it is, because _dl_loaded_modules already points
551          * to the dlopened library.
552          */
553         for (ls = &_dl_loaded_modules->symbol_scope; ls && ls->next; ls = ls->next);
554
555         /* Extend the global scope by adding the local scope of the dlopened DSO. */
556         ls->next = &dyn_chain->dyn->symbol_scope;
557 #endif
558 #ifdef __mips__
559         /*
560          * Relocation of the GOT entries for MIPS have to be done
561          * after all the libraries have been loaded.
562          */
563         _dl_perform_mips_global_got_relocations(tpnt, !now_flag);
564 #endif
565
566         if (_dl_fixup(dyn_chain, &_dl_loaded_modules->symbol_scope, now_flag))
567                 goto oops;
568
569         if (relro_ptr) {
570                 for (rpnt = relro_ptr->next; rpnt; rpnt = rpnt->next) {
571                         if (rpnt->dyn->relro_size)
572                                 _dl_protect_relro(rpnt->dyn);
573                 }
574         }
575         /* TODO:  Should we set the protections of all pages back to R/O now ? */
576
577
578 #if defined(USE_TLS) && USE_TLS
579
580         for (i=0; i < nlist; i++) {
581                 struct elf_resolve *tmp_tpnt = init_fini_list[i];
582                 /* Only add TLS memory if this object is loaded now and
583                    therefore is not yet initialized.  */
584
585                 if (!(tmp_tpnt->init_flag & INIT_FUNCS_CALLED)
586                 /* Only if the module defines thread local data. */
587                         && __builtin_expect (tmp_tpnt->l_tls_blocksize > 0, 0)) {
588
589                         /* Now that we know the object is loaded successfully add
590                         modules containing TLS data to the slot info table.  We
591                         might have to increase its size.  */
592                         _dl_add_to_slotinfo ((struct link_map*)tmp_tpnt);
593
594                         /* It is the case in which we couldn't perform TLS static
595                            initialization at relocation time, and we delayed it until
596                            the relocation has been completed. */
597
598                         if (tmp_tpnt->l_need_tls_init) {
599                                 tmp_tpnt->l_need_tls_init = 0;
600 # ifdef SHARED
601                                 /* Update the slot information data for at least the
602                                 generation of the DSO we are allocating data for.  */
603                                 _dl_update_slotinfo (tmp_tpnt->l_tls_modid);
604 # endif
605
606                                 _dl_init_static_tls((struct link_map*)tmp_tpnt);
607                                 _dl_assert (tmp_tpnt->l_need_tls_init == 0);
608                 }
609
610                 /* We have to bump the generation counter. */
611                 any_tls = true;
612                 }
613         }
614
615         /* Bump the generation number if necessary.  */
616         if (any_tls && __builtin_expect (++_dl_tls_generation == 0, 0)) {
617                 _dl_debug_early("TLS generation counter wrapped! Please report this.");
618                 _dl_exit(30);
619         }
620
621 #endif
622
623         /* Notify the debugger we have added some objects. */
624         if (_dl_debug_addr) {
625                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
626                 if (dl_brk != NULL) {
627                         _dl_debug_addr->r_state = RT_ADD;
628                         (*dl_brk) ();
629
630                         _dl_debug_addr->r_state = RT_CONSISTENT;
631                         (*dl_brk) ();
632                 }
633         }
634
635         /* Run the ctors and setup the dtors */
636         for (i = nlist; i; --i) {
637                 tpnt = init_fini_list[i-1];
638                 if (tpnt->init_flag & INIT_FUNCS_CALLED)
639                         continue;
640                 tpnt->init_flag |= INIT_FUNCS_CALLED;
641
642                 if (tpnt->dynamic_info[DT_INIT]) {
643                         void (*dl_elf_func) (void);
644                         dl_elf_func = (void (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_INIT]);
645                         if (dl_elf_func) {
646                                 _dl_if_debug_print("running ctors for library %s at '%p'\n",
647                                                 tpnt->libname, dl_elf_func);
648                                 DL_CALL_FUNC_AT_ADDR (dl_elf_func, tpnt->loadaddr, (void(*)(void)));
649                         }
650                 }
651
652                 _dl_run_init_array(tpnt);
653         }
654
655         _dl_unmap_cache();
656         return (void *) dyn_chain;
657
658 oops:
659         /* Something went wrong.  Clean up and return NULL. */
660         _dl_unmap_cache();
661         do_dlclose(dyn_chain, 0);
662         return NULL;
663 }
664
665 void *dlopen(const char *libname, int flag)
666 {
667         void *ret;
668
669         __UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
670         ret = do_dlopen(libname, flag,
671                         (ElfW(Addr)) __builtin_return_address(0));
672         __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
673
674         return ret;
675 }
676
677 static void *do_dlsym(void *vhandle, const char *name, void *caller_address)
678 {
679         struct elf_resolve *tpnt, *tfrom;
680         struct dyn_elf *handle;
681         ElfW(Addr) from = 0;
682         struct dyn_elf *rpnt;
683         void *ret;
684         struct symbol_ref sym_ref = { NULL, NULL };
685         /* Nastiness to support underscore prefixes.  */
686 #ifdef __UCLIBC_UNDERSCORES__
687         char tmp_buf[80];
688         char *name2 = tmp_buf;
689         size_t nlen = strlen (name) + 1;
690         if (nlen + 1 > sizeof (tmp_buf))
691                 name2 = malloc (nlen + 1);
692         if (name2 == 0) {
693                 _dl_error_number = LD_ERROR_MMAP_FAILED;
694                 return 0;
695         }
696         name2[0] = '_';
697         memcpy (name2 + 1, name, nlen);
698 #else
699         const char *name2 = name;
700 #endif
701         handle = (struct dyn_elf *) vhandle;
702
703         /* First of all verify that we have a real handle
704            of some kind.  Return NULL if not a valid handle. */
705
706         if (handle == NULL)
707                 handle = _dl_symbol_tables;
708         else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
709                 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
710                         if (rpnt == handle)
711                                 break;
712                 if (!rpnt) {
713                         _dl_error_number = LD_BAD_HANDLE;
714                         ret = NULL;
715                         goto out;
716                 }
717         } else if (handle == RTLD_NEXT) {
718                 /*
719                  * Try and locate the module we were called from - we
720                  * need this so that we know where to start searching
721                  * from.  We never pass RTLD_NEXT down into the actual
722                  * dynamic loader itself, as it doesn't know
723                  * how to properly treat it.
724                  */
725                 from = (ElfW(Addr)) caller_address;
726
727                 tfrom = NULL;
728                 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
729                         tpnt = rpnt->dyn;
730                         if (DL_ADDR_IN_LOADADDR(from, tpnt, tfrom)) {
731                                 tfrom = tpnt;
732                                 handle = rpnt->next;
733                         }
734                 }
735         }
736         tpnt = NULL;
737         if (handle == _dl_symbol_tables)
738                 tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
739
740         do {
741                 ret = _dl_find_hash(name2, &handle->dyn->symbol_scope, tpnt, ELF_RTYPE_CLASS_DLSYM, &sym_ref);
742                 if (ret != NULL)
743                         break;
744                 handle = handle->next;
745         } while (from && handle);
746
747 #if defined(USE_TLS) && USE_TLS && defined SHARED
748         if (sym_ref.sym && (ELF_ST_TYPE(sym_ref.sym->st_info) == STT_TLS) && (sym_ref.tpnt)) {
749                 /* The found symbol is a thread-local storage variable.
750                 Return its address for the current thread.  */
751                 ret = _dl_tls_symaddr ((struct link_map *)sym_ref.tpnt, (Elf32_Addr)ret);
752         }
753 #endif
754
755         /*
756          * Nothing found.
757          */
758         if (!ret)
759                 _dl_error_number = LD_NO_SYMBOL;
760 out:
761 #ifdef __UCLIBC_UNDERSCORES__
762         if (name2 != tmp_buf)
763                 free (name2);
764 #endif
765         return ret;
766 }
767
768 void *dlsym(void *vhandle, const char *name)
769 {
770         void *ret;
771
772         __UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
773         ret = do_dlsym(vhandle, name, __builtin_return_address(0));
774         __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
775
776         return ret;
777 }
778
779 #if 0
780 void *dlvsym(void *vhandle, const char *name, const char *version)
781 {
782         return dlsym(vhandle, name);
783 }
784 #endif
785
786 static int do_dlclose(void *vhandle, int need_fini)
787 {
788         struct dyn_elf *rpnt, *rpnt1, *rpnt1_tmp;
789         struct init_fini_list *runp, *tmp;
790         ElfW(Phdr) *ppnt;
791         struct elf_resolve *tpnt, *run_tpnt;
792         int (*dl_elf_fini) (void);
793         void (*dl_brk) (void);
794         struct dyn_elf *handle;
795         unsigned int end = 0, start = 0xffffffff;
796         unsigned int i, j;
797         struct r_scope_elem *ls, *ls_next = NULL;
798         struct elf_resolve **handle_rlist;
799
800 #if defined(USE_TLS) && USE_TLS
801         bool any_tls = false;
802         size_t tls_free_start = NO_TLS_OFFSET;
803         size_t tls_free_end = NO_TLS_OFFSET;
804         struct link_map *tls_lmap;
805 #endif
806
807         handle = (struct dyn_elf *) vhandle;
808         if (handle == _dl_symbol_tables)
809                 return 0;
810         rpnt1 = NULL;
811         for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
812                 if (rpnt == handle)
813                         break;
814                 rpnt1 = rpnt;
815         }
816
817         if (!rpnt) {
818                 _dl_error_number = LD_BAD_HANDLE;
819                 return 1;
820         }
821         if (rpnt1)
822                 rpnt1->next_handle = rpnt->next_handle;
823         else
824                 _dl_handles = rpnt->next_handle;
825         _dl_if_debug_print("%s: usage count: %d\n",
826                         handle->dyn->libname, handle->dyn->usage_count);
827         if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & RTLD_NODELETE)) {
828                 handle->dyn->usage_count--;
829                 free(handle);
830                 return 0;
831         }
832
833         /* Store the handle's local scope array for later removal */
834         handle_rlist = handle->dyn->symbol_scope.r_list;
835
836         /* Store references to the local scope entries for later removal */
837         for (ls = &_dl_loaded_modules->symbol_scope; ls && ls->next; ls = ls->next)
838                 if (ls->next->r_list[0] == handle->dyn) {
839                         break;
840                 }
841         /* ls points to the previous local symbol scope */
842         if(ls && ls->next)
843                 ls_next = ls->next->next;
844
845         /* OK, this is a valid handle - now close out the file */
846         for (j = 0; j < handle->init_fini.nlist; ++j) {
847                 tpnt = handle->init_fini.init_fini[j];
848                 tpnt->usage_count--;
849                 if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) {
850                         if ((tpnt->dynamic_info[DT_FINI]
851                              || tpnt->dynamic_info[DT_FINI_ARRAY])
852                          && need_fini
853                          && !(tpnt->init_flag & FINI_FUNCS_CALLED)
854                         ) {
855                                 tpnt->init_flag |= FINI_FUNCS_CALLED;
856                                 _dl_run_fini_array(tpnt);
857
858                                 if (tpnt->dynamic_info[DT_FINI]) {
859                                         dl_elf_fini = (int (*)(void)) DL_RELOC_ADDR(tpnt->loadaddr, tpnt->dynamic_info[DT_FINI]);
860                                         _dl_if_debug_print("running dtors for library %s at '%p'\n",
861                                                         tpnt->libname, dl_elf_fini);
862                                         DL_CALL_FUNC_AT_ADDR (dl_elf_fini, tpnt->loadaddr, (int (*)(void)));
863                                 }
864                         }
865
866                         _dl_if_debug_print("unmapping: %s\n", tpnt->libname);
867                         end = 0;
868                         for (i = 0, ppnt = tpnt->ppnt;
869                                         i < tpnt->n_phent; ppnt++, i++) {
870                                 if (ppnt->p_type != PT_LOAD)
871                                         continue;
872                                 if (ppnt->p_vaddr < start)
873                                         start = ppnt->p_vaddr;
874                                 if (end < ppnt->p_vaddr + ppnt->p_memsz)
875                                         end = ppnt->p_vaddr + ppnt->p_memsz;
876                         }
877
878 #if defined(USE_TLS) && USE_TLS
879                         /* Do the cast to make things easy. */
880                         tls_lmap = (struct link_map *) tpnt;
881
882                         /* Remove the object from the dtv slotinfo array if it uses TLS. */
883                         if (__builtin_expect (tls_lmap->l_tls_blocksize > 0, 0)) {
884                                 any_tls = true;
885
886                                 if (_dl_tls_dtv_slotinfo_list != NULL
887                                                 && ! remove_slotinfo (tls_lmap->l_tls_modid,
888                                                 _dl_tls_dtv_slotinfo_list, 0,
889                                                 (tpnt->init_flag & INIT_FUNCS_CALLED)))
890                                         /* All dynamically loaded modules with TLS are unloaded. */
891                                         _dl_tls_max_dtv_idx = _dl_tls_static_nelem;
892
893                                 if (tls_lmap->l_tls_offset != NO_TLS_OFFSET) {
894                                         /*
895                                          * Collect a contiguous chunk built from the objects in
896                                          * this search list, going in either direction.  When the
897                                          * whole chunk is at the end of the used area then we can
898                                          * reclaim it.
899                                          */
900 # if defined(TLS_TCB_AT_TP)
901                                         if (tls_free_start == NO_TLS_OFFSET
902                                                 || (size_t) tls_lmap->l_tls_offset == tls_free_start) {
903                                                 /* Extend the contiguous chunk being reclaimed. */
904                                                 tls_free_start
905                                                         = tls_lmap->l_tls_offset -
906                                                           tls_lmap->l_tls_blocksize;
907
908                                                 if (tls_free_end == NO_TLS_OFFSET)
909                                                         tls_free_end = tls_lmap->l_tls_offset;
910                                         } else if (tls_lmap->l_tls_offset - tls_lmap->l_tls_blocksize
911                                                         == tls_free_end)
912                                                 /* Extend the chunk backwards.  */
913                                                 tls_free_end = tls_lmap->l_tls_offset;
914                                         else {
915                                                 /*
916                                                  * This isn't contiguous with the last chunk freed.
917                                                  * One of them will be leaked unless we can free
918                                                  * one block right away.
919                                                  */
920                                                 if (tls_free_end == _dl_tls_static_used) {
921                                                         _dl_tls_static_used = tls_free_start;
922                                                         tls_free_end = tls_lmap->l_tls_offset;
923                                                         tls_free_start
924                                                                 = tls_free_end - tls_lmap->l_tls_blocksize;
925                                                 } else if ((size_t) tls_lmap->l_tls_offset
926                                                                 == _dl_tls_static_used)
927                                                         _dl_tls_static_used = tls_lmap->l_tls_offset -
928                                                                 tls_lmap->l_tls_blocksize;
929                                                 else if (tls_free_end < (size_t) tls_lmap->l_tls_offset) {
930                                                         /*
931                                                          * We pick the later block. It has a chance
932                                                          * to be freed.
933                                                          */
934                                                         tls_free_end = tls_lmap->l_tls_offset;
935                                                         tls_free_start = tls_free_end -
936                                                                 tls_lmap->l_tls_blocksize;
937                                                 }
938                                         }
939 # elif defined(TLS_DTV_AT_TP)
940                                         if ((size_t) tls_lmap->l_tls_offset == tls_free_end)
941                                                 /* Extend the contiguous chunk being reclaimed. */
942                                                 tls_free_end -= tls_lmap->l_tls_blocksize;
943                                         else if (tls_lmap->l_tls_offset + tls_lmap->l_tls_blocksize
944                                                         == tls_free_start)
945                                                 /* Extend the chunk backwards. */
946                                                 tls_free_start = tls_lmap->l_tls_offset;
947                                         else {
948                                                 /*
949                                                  * This isn't contiguous with the last chunk
950                                                  * freed. One of them will be leaked.
951                                                  */
952                                                 if (tls_free_end == _dl_tls_static_used)
953                                                         _dl_tls_static_used = tls_free_start;
954                                                 tls_free_start = tls_lmap->l_tls_offset;
955                                                 tls_free_end = tls_free_start +
956                                                         tls_lmap->l_tls_blocksize;
957                                         }
958 # else
959 #  error Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined
960 # endif
961                                 } else {
962
963 #define TLS_DTV_UNALLOCATED     ((void *) -1l)
964
965                                         dtv_t *dtv = THREAD_DTV ();
966
967                                         _dl_assert(!(dtv[tls_lmap->l_tls_modid].pointer.is_static));
968                                         if (dtv[tls_lmap->l_tls_modid].pointer.val != TLS_DTV_UNALLOCATED) {
969                                                 /* Note that free is called for NULL is well.  We
970                                                 deallocate even if it is this dtv entry we are
971                                                 supposed to load.  The reason is that we call
972                                                 memalign and not malloc.  */
973                                                 _dl_free (dtv[tls_lmap->l_tls_modid].pointer.val);
974                                                 dtv[tls_lmap->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
975                                         }
976                                 }
977                         }
978 #endif
979
980                         end = (end + ADDR_ALIGN) & PAGE_ALIGN;
981                         start = start & ~ADDR_ALIGN;
982                         DL_LIB_UNMAP (tpnt, end - start);
983                         /* Free elements in RTLD_LOCAL scope list */
984                         for (runp = tpnt->rtld_local; runp; runp = tmp) {
985                                 tmp = runp->next;
986                                 free(runp);
987                         }
988
989                         /* Next, remove tpnt from the loaded_module list */
990                         if (_dl_loaded_modules == tpnt) {
991                                 _dl_loaded_modules = tpnt->next;
992                                 if (_dl_loaded_modules)
993                                         _dl_loaded_modules->prev = 0;
994                         } else {
995                                 for (run_tpnt = _dl_loaded_modules; run_tpnt; run_tpnt = run_tpnt->next) {
996                                         if (run_tpnt->next == tpnt) {
997                                                 _dl_if_debug_print("removing loaded_modules: %s\n", tpnt->libname);
998                                                 run_tpnt->next = run_tpnt->next->next;
999                                                 if (run_tpnt->next)
1000                                                         run_tpnt->next->prev = run_tpnt;
1001                                                 break;
1002                                         }
1003                                 }
1004                         }
1005
1006                         /* Next, remove tpnt from the global symbol table list */
1007                         if (_dl_symbol_tables) {
1008                                 if (_dl_symbol_tables->dyn == tpnt) {
1009                                         _dl_symbol_tables = _dl_symbol_tables->next;
1010                                         if (_dl_symbol_tables)
1011                                                 _dl_symbol_tables->prev = 0;
1012                                 } else {
1013                                         for (rpnt1 = _dl_symbol_tables; rpnt1->next; rpnt1 = rpnt1->next) {
1014                                                 if (rpnt1->next->dyn == tpnt) {
1015                                                         _dl_if_debug_print("removing symbol_tables: %s\n", tpnt->libname);
1016                                                         rpnt1_tmp = rpnt1->next->next;
1017                                                         free(rpnt1->next);
1018                                                         rpnt1->next = rpnt1_tmp;
1019                                                         if (rpnt1->next)
1020                                                                 rpnt1->next->prev = rpnt1;
1021                                                         break;
1022                                                 }
1023                                         }
1024                                 }
1025                         }
1026                         free(tpnt->libname);
1027                         if (handle->dyn != tpnt)
1028                                 free(tpnt->symbol_scope.r_list);
1029                         free(tpnt);
1030                 }
1031         }
1032         /* Unlink and release the handle's local scope from global one */
1033         if(ls)
1034                 ls->next = ls_next;
1035         free(handle_rlist);
1036
1037         for (rpnt1 = handle->next; rpnt1; rpnt1 = rpnt1_tmp) {
1038                 rpnt1_tmp = rpnt1->next;
1039                 free(rpnt1);
1040         }
1041         free(handle->init_fini.init_fini);
1042         free(handle);
1043
1044 #if defined(USE_TLS) && USE_TLS
1045         /* If we removed any object which uses TLS bump the generation counter.  */
1046         if (any_tls) {
1047                 if (__builtin_expect(++_dl_tls_generation == 0, 0)) {
1048                         _dl_debug_early("TLS generation counter wrapped!  Please report to the uClibc mailing list.\n");
1049                         _dl_exit(30);
1050                 }
1051
1052                 if (tls_free_end == _dl_tls_static_used)
1053                         _dl_tls_static_used = tls_free_start;
1054         }
1055 #endif
1056
1057         if (_dl_debug_addr) {
1058                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
1059                 if (dl_brk != NULL) {
1060                         _dl_debug_addr->r_state = RT_DELETE;
1061                         (*dl_brk) ();
1062
1063                         _dl_debug_addr->r_state = RT_CONSISTENT;
1064                         (*dl_brk) ();
1065                 }
1066         }
1067
1068         return 0;
1069 }
1070
1071 int dlclose(void *vhandle)
1072 {
1073         int ret;
1074
1075         __UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
1076         ret = do_dlclose(vhandle, 1);
1077         __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
1078
1079         return ret;
1080 }
1081
1082 char *dlerror(void)
1083 {
1084         const char *retval;
1085
1086         if (!_dl_error_number)
1087                 return NULL;
1088         retval = dl_error_names[_dl_error_number];
1089         _dl_error_number = 0;
1090         return (char *)retval;
1091 }
1092
1093 /*
1094  * Dump information to stderr about the current loaded modules
1095  */
1096 #ifdef __USE_GNU
1097 # if 0
1098 static const char type[][4] = { "Lib", "Exe", "Int", "Mod" };
1099
1100 /* reimplement this, being a GNU extension it should be the same as on glibc */
1101 int dlinfo(void)
1102 {
1103         struct elf_resolve *tpnt;
1104         struct dyn_elf *rpnt, *hpnt;
1105
1106         fprintf(stderr, "List of loaded modules\n");
1107         /* First start with a complete list of all of the loaded files. */
1108         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
1109                 fprintf(stderr, "\t%p %p %p %s %d %s\n",
1110                         DL_LOADADDR_BASE(tpnt->loadaddr), tpnt, tpnt->symbol_scope,
1111                         type[tpnt->libtype],
1112                         tpnt->usage_count, tpnt->libname);
1113         }
1114
1115         /* Next dump the module list for the application itself */
1116         fprintf(stderr, "\nModules for application (%p):\n", _dl_symbol_tables);
1117         for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
1118                 fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1119
1120         for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
1121                 fprintf(stderr, "Modules for handle %p\n", hpnt);
1122                 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
1123                         fprintf(stderr, "\t%p %s\n", rpnt->dyn, rpnt->dyn->libname);
1124         }
1125         return 0;
1126 }
1127 #endif
1128
1129 static int do_dladdr(const void *__address, Dl_info * __info)
1130 {
1131         struct elf_resolve *pelf;
1132         struct elf_resolve *rpnt;
1133
1134         _dl_map_cache();
1135
1136         /*
1137          * Try and locate the module address is in
1138          */
1139         pelf = NULL;
1140
1141         _dl_if_debug_print("__address: %p  __info: %p\n", __address, __info);
1142
1143         __address = DL_LOOKUP_ADDRESS (__address);
1144
1145         for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
1146                 struct elf_resolve *tpnt;
1147
1148                 tpnt = rpnt;
1149
1150                 _dl_if_debug_print("Module \"%s\" at %p\n",
1151                                    tpnt->libname, DL_LOADADDR_BASE(tpnt->loadaddr));
1152
1153                 if (DL_ADDR_IN_LOADADDR((ElfW(Addr)) __address, tpnt, pelf))
1154                         pelf = tpnt;
1155         }
1156
1157         if (!pelf) {
1158                 return 0;
1159         }
1160
1161         /*
1162          * Try and locate the symbol of address
1163          */
1164
1165         {
1166                 char *strtab;
1167                 ElfW(Sym) *symtab;
1168                 unsigned int hn, si, sn, sf;
1169                 ElfW(Addr) sa = 0;
1170
1171                 /* Set the info for the object the address lies in */
1172                 __info->dli_fname = pelf->libname;
1173                 __info->dli_fbase = (void *)pelf->mapaddr;
1174
1175                 symtab = (ElfW(Sym) *) (pelf->dynamic_info[DT_SYMTAB]);
1176                 strtab = (char *) (pelf->dynamic_info[DT_STRTAB]);
1177
1178                 sf = sn = 0;
1179
1180 #ifdef __LDSO_GNU_HASH_SUPPORT__
1181                 if (pelf->l_gnu_bitmask) {
1182                         for (hn = 0; hn < pelf->nbucket; hn++) {
1183                                 si = pelf->l_gnu_buckets[hn];
1184                                 if (!si)
1185                                         continue;
1186
1187                                 const Elf32_Word *hasharr = &pelf->l_gnu_chain_zero[si];
1188                                 do {
1189                                         ElfW(Addr) symbol_addr;
1190
1191                                         symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1192                                         if ((symtab[si].st_shndx != SHN_UNDEF
1193                                                  || symtab[si].st_value != 0)
1194                                                 && ELF_ST_TYPE(symtab[si].st_info) != STT_TLS
1195                                                 && DL_ADDR_SYM_MATCH(symbol_addr, &symtab[si], sa,
1196                                                                                          (ElfW(Addr)) __address)) {
1197                                                 sa = symbol_addr;
1198                                                 sn = si;
1199                                                 sf = 1;
1200                                         }
1201                                         _dl_if_debug_print("Symbol \"%s\" at %p\n", strtab + symtab[si].st_name, symbol_addr);
1202                                         ++si;
1203                                 } while ((*hasharr++ & 1u) == 0);
1204                         }
1205                 } else
1206 #endif
1207                 for (hn = 0; hn < pelf->nbucket; hn++) {
1208                         for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
1209                                 ElfW(Addr) symbol_addr;
1210
1211                                 symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
1212                                 if ((symtab[si].st_shndx != SHN_UNDEF
1213                                          || symtab[si].st_value != 0)
1214                                         && ELF_ST_TYPE(symtab[si].st_info) != STT_TLS
1215                                         && DL_ADDR_SYM_MATCH(symbol_addr, &symtab[si], sa,
1216                                                                                  (ElfW(Addr)) __address)) {
1217                                         sa = symbol_addr;
1218                                         sn = si;
1219                                         sf = 1;
1220                                 }
1221
1222                                 _dl_if_debug_print("Symbol \"%s\" at %p\n",
1223                                                    strtab + symtab[si].st_name, symbol_addr);
1224                         }
1225                 }
1226
1227                 if (sf) {
1228                         /* A nearest symbol has been found; fill the entries */
1229                         __info->dli_sname = strtab + symtab[sn].st_name;
1230                         __info->dli_saddr = (void *)sa;
1231                 } else {
1232                         /* No symbol found, fill entries with NULL value,
1233                         only the containing object will be returned. */
1234                         __info->dli_sname = NULL;
1235                         __info->dli_saddr = NULL;
1236                 }
1237                 return 1;
1238         }
1239 }
1240 #endif
1241
1242 int dladdr(const void *__address, Dl_info * __info)
1243 {
1244         int ret;
1245
1246         __UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
1247         ret = do_dladdr(__address, __info);
1248         __UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
1249
1250         return ret;
1251 }