OSDN Git Service

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