OSDN Git Service

c2949c981460568978db0fa8ee6b1532bae1a6a6
[uclinux-h8/uClibc.git] / ldso / libdl / libdl.c
1 /*
2  * libdl.c
3  * 
4  * Functions required for dlopen et. al.
5  */
6
7 #include <stdlib.h>
8 #include <features.h>
9 #include "dlfcn.h"
10 #include "linuxelf.h"
11 #include "ld_syscall.h"
12 #include "ld_hash.h"
13 #include "ld_string.h"
14
15 extern struct r_debug *_dl_debug_addr;
16
17 extern void *(*_dl_malloc_function) (size_t size);
18
19 static int do_fixup(struct elf_resolve *tpnt, int flag);
20 static int do_dlclose(void *, int need_fini);
21
22 void *dlopen(const char *, int) __attribute__ ((__weak__, __alias__ ("_dlopen")));
23 const char *dlerror(void) __attribute__ ((__weak__, __alias__ ("_dlerror")));
24 void *dlsym(void *, const char *) __attribute__ ((__weak__, __alias__ ("_dlsym")));
25 int dlclose(void *) __attribute__ ((__weak__, __alias__ ("_dlclose")));
26 int dladdr(void *, Dl_info *) __attribute__ ((__weak__, __alias__ ("_dladdr")));
27
28 #ifdef __PIC__
29 /* This is a real hack.  We need access to the dynamic linker, but we
30 also need to make it possible to link against this library without any
31 unresolved externals.  We provide these weak symbols to make the link
32 possible, but at run time the normal symbols are accessed. */
33 static void __attribute__ ((unused)) foobar(void)
34 {
35         const char msg[]="libdl library not correctly linked\n";
36         _dl_write(2, msg, _dl_strlen(msg));
37         _dl_exit(1);
38 }
39
40 static int __attribute__ ((unused)) foobar1 = (int) foobar;     /* Use as pointer */
41 extern void _dl_dprintf(int, const char *, ...) __attribute__ ((__weak__, __alias__ ("foobar")));
42 extern char *_dl_find_hash(const char *, struct dyn_elf *, struct elf_resolve *, enum caller_type)
43         __attribute__ ((__weak__, __alias__ ("foobar")));
44 extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **, struct elf_resolve *, char *)
45         __attribute__ ((__weak__, __alias__ ("foobar")));
46 extern int _dl_parse_relocation_information(struct elf_resolve *, unsigned long, unsigned long, int)
47         __attribute__ ((__weak__, __alias__ ("foobar")));
48 extern void _dl_parse_lazy_relocation_information(struct elf_resolve *, unsigned long, unsigned long, int)
49         __attribute__ ((__weak__, __alias__ ("foobar")));
50 #ifdef __mips__
51 extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt)
52         __attribute__ ((__weak__, __alias__ ("foobar")));
53 #endif
54 #ifdef USE_CACHE
55 int _dl_map_cache(void) __attribute__ ((__weak__, __alias__ ("foobar")));
56 int _dl_unmap_cache(void) __attribute__ ((__weak__, __alias__ ("foobar")));
57 #endif  
58
59 extern struct dyn_elf *_dl_symbol_tables __attribute__ ((__weak__, __alias__ ("foobar1")));
60 extern struct dyn_elf *_dl_handles __attribute__ ((__weak__, __alias__ ("foobar1")));
61 extern struct elf_resolve *_dl_loaded_modules __attribute__ ((__weak__, __alias__ ("foobar1")));
62 extern struct r_debug *_dl_debug_addr __attribute__ ((__weak__, __alias__ ("foobar1")));
63 extern unsigned long _dl_error_number __attribute__ ((__weak__, __alias__ ("foobar1")));
64 extern void *(*_dl_malloc_function)(size_t) __attribute__ ((__weak__, __alias__ ("foobar1")));
65 #else
66 #ifdef __SUPPORT_LD_DEBUG__
67 static char *_dl_debug  = 0;
68 static char *_dl_debug_symbols = 0;
69 static char *_dl_debug_move    = 0;
70 static char *_dl_debug_reloc   = 0;
71 static char *_dl_debug_detail  = 0;
72 static char *_dl_debug_nofixups  = 0;
73 static char *_dl_debug_bindings  = 0;
74 static int   _dl_debug_file = 2;
75 #elif defined __SUPPORT_LD_DEBUG_EARLY__
76 #define _dl_debug_file 2
77 #endif
78 char *_dl_library_path = 0;
79 char *_dl_ldsopath = 0;
80 struct r_debug *_dl_debug_addr = NULL;
81 static char *_dl_malloc_addr, *_dl_mmap_zero;
82 #include "../ldso/ldso.h"               /* Pull in the name of ld.so */
83 #include "../ldso/hash.c"
84 #include "../ldso/readelflib1.c"
85 #endif
86
87 static const char *dl_error_names[] = {
88         "",
89         "File not found",
90         "Unable to open /dev/zero",
91         "Not an ELF file",
92 #if defined (__i386__)
93         "Not i386 binary",
94 #elif defined (__sparc__)
95         "Not sparc binary",
96 #elif defined (__mc68000__)
97         "Not m68k binary",
98 #else
99         "Unrecognized binary type",
100 #endif
101         "Not an ELF shared library",
102         "Unable to mmap file",
103         "No dynamic section",
104 #ifdef ELF_USES_RELOCA
105         "Unable to process REL relocs",
106 #else
107         "Unable to process RELA relocs",
108 #endif
109         "Bad handle",
110         "Unable to resolve symbol"
111 };
112
113 static void __attribute__ ((destructor)) dl_cleanup(void)
114 {
115         struct dyn_elf *d;
116
117         for (d = _dl_handles; d; d = d->next_handle)
118                 if (d->dyn->libtype == loaded_file && d->dyn->dynamic_info[DT_FINI]) {
119                         (* ((int (*)(void)) (d->dyn->loadaddr + d->dyn->dynamic_info[DT_FINI]))) ();
120                         d->dyn->dynamic_info[DT_FINI] = 0;
121                 }
122 }
123
124 void *_dlopen(const char *libname, int flag)
125 {
126         struct elf_resolve *tpnt, *tfrom;
127         struct dyn_elf *rpnt = NULL;
128         struct dyn_elf *dyn_chain;
129         struct dyn_elf *dpnt;
130         static int dl_init = 0;
131         char *from;
132         void (*dl_brk) (void);
133 #ifdef __PIC__
134         int (*dl_elf_init) (void);
135 #endif
136
137         /* A bit of sanity checking... */
138         if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
139                 _dl_error_number = LD_BAD_HANDLE;
140                 return NULL;
141         }
142
143         from = __builtin_return_address(0);
144
145         /* Have the dynamic linker use the regular malloc function now */
146         if (!dl_init) {
147                 dl_init++;
148                 _dl_malloc_function = malloc;
149         }
150
151         /* Cover the trivial case first */
152         if (!libname)
153                 return _dl_symbol_tables;
154
155 #ifdef USE_CACHE
156         _dl_map_cache();
157 #endif
158
159         /*
160          * Try and locate the module we were called from - we
161          * need this so that we get the correct RPATH.  Note that
162          * this is the current behavior under Solaris, but the
163          * ABI+ specifies that we should only use the RPATH from
164          * the application.  Thus this may go away at some time
165          * in the future.
166          */
167         tfrom = NULL;
168         for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
169                 tpnt = dpnt->dyn;
170                 if (tpnt->loadaddr < from
171                         && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
172                         tfrom = tpnt;
173         }
174
175         if (!(tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname))) {
176 #ifdef USE_CACHE
177                 _dl_unmap_cache();
178 #endif
179                 return NULL;
180         }
181         //tpnt->libtype = loaded_file;
182
183         dyn_chain = rpnt = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
184         _dl_memset(rpnt, 0, sizeof(struct dyn_elf));
185         rpnt->dyn = tpnt;
186         rpnt->flags = flag;
187         if (!tpnt->symbol_scope)
188                 tpnt->symbol_scope = dyn_chain;
189
190         rpnt->next_handle = _dl_handles;
191         _dl_handles = rpnt;
192
193         /*
194          * OK, we have the requested file in memory.  Now check for
195          * any other requested files that may also be required.
196          */
197           {
198             struct elf_resolve *tcurr;
199             struct elf_resolve * tpnt1;
200             Elf32_Dyn * dpnt;
201             char * lpnt;
202
203             tcurr = tpnt;
204             do{
205               for(dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
206                 {
207           
208                   if(dpnt->d_tag == DT_NEEDED)
209                     {
210                       lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + 
211                         dpnt->d_un.d_val;
212                       if(!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpnt)))
213                         goto oops;
214
215                       rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
216                       _dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
217                       rpnt = rpnt->next;
218                       if (!tpnt1->symbol_scope) tpnt1->symbol_scope = dyn_chain;
219                       rpnt->dyn = tpnt1;
220                     };
221                 }
222               
223               tcurr = tcurr->next;
224             } while(tcurr);
225           }
226          
227         /*
228          * OK, now attach the entire chain at the end
229          */
230
231         rpnt->next = _dl_symbol_tables;
232
233         /*
234          * MIPS is special *sigh*
235          */
236 #ifdef __mips__
237         _dl_perform_mips_global_got_relocations(tpnt);
238 #endif
239
240         if (do_fixup(tpnt, flag)) {
241                 _dl_error_number = LD_NO_SYMBOL;
242                 goto oops;
243         }
244
245         if (_dl_debug_addr) {
246             dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
247             if (dl_brk != NULL) {
248                 _dl_debug_addr->r_state = RT_ADD;
249                 (*dl_brk) ();
250
251                 _dl_debug_addr->r_state = RT_CONSISTENT;
252                 (*dl_brk) ();
253             }
254         }
255
256 #ifdef __PIC__
257         /* Find the last library */
258         for (tpnt = dyn_chain->dyn; tpnt->next!=NULL; tpnt = tpnt->next)
259                 ;
260         /* Run the ctors and set up the dtors */
261         for (; tpnt != dyn_chain->dyn->prev; tpnt=tpnt->prev)
262         {
263                 /* Apparently crt1 for the application is responsible for handling this.
264                  * We only need to run the init/fini for shared libraries
265                  */
266                 if (tpnt->libtype == program_interpreter)
267                         continue;
268                 if (tpnt->libtype == elf_executable)
269                         continue;
270                 if (tpnt->init_flag & INIT_FUNCS_CALLED)
271                         continue;
272                 tpnt->init_flag |= INIT_FUNCS_CALLED;
273
274                 if (tpnt->dynamic_info[DT_INIT]) {
275                         dl_elf_init = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
276                         (*dl_elf_init) ();
277                 }
278                 if (tpnt->dynamic_info[DT_FINI]) {
279                         atexit((void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]));
280                 }
281
282         }
283 #endif
284
285 #ifdef USE_CACHE
286         _dl_unmap_cache();
287 #endif
288         return (void *) dyn_chain;
289
290   oops:
291         /* Something went wrong.  Clean up and return NULL. */
292 #ifdef USE_CACHE
293         _dl_unmap_cache();
294 #endif
295         do_dlclose(dyn_chain, 0);
296         return NULL;
297 }
298
299 static int do_fixup(struct elf_resolve *tpnt, int flag)
300 {
301         int goof = 0;
302
303         if (tpnt->next)
304                 goof += do_fixup(tpnt->next, flag);
305
306         if (tpnt->dynamic_info[DT_REL]) {
307 #ifdef ELF_USES_RELOCA
308                 goof++;
309 #else
310                 if (tpnt->init_flag & RELOCS_DONE)
311                         return goof;
312                 tpnt->init_flag |= RELOCS_DONE;
313
314                 goof += _dl_parse_relocation_information(tpnt, 
315                         tpnt->dynamic_info[DT_REL], tpnt->dynamic_info[DT_RELSZ], 0);
316 #endif
317         }
318         if (tpnt->dynamic_info[DT_RELA]) {
319 #ifdef ELF_USES_RELOCA
320                 if (tpnt->init_flag & RELOCS_DONE)
321                         return goof;
322                 tpnt->init_flag |= RELOCS_DONE;
323
324                 goof += _dl_parse_relocation_information(tpnt, 
325                         tpnt->dynamic_info[DT_RELA], tpnt->dynamic_info[DT_RELASZ], 0);
326 #else
327                 goof++;
328 #endif
329         }
330         if (tpnt->dynamic_info[DT_JMPREL]) {
331                 if (tpnt->init_flag & JMP_RELOCS_DONE)
332                         return goof;
333                 tpnt->init_flag |= JMP_RELOCS_DONE;
334
335                 if (flag == RTLD_LAZY) {
336                         _dl_parse_lazy_relocation_information(tpnt, 
337                                 tpnt->dynamic_info[DT_JMPREL], 
338                                 tpnt->dynamic_info[DT_PLTRELSZ], 0);
339                 } else {
340                         goof += _dl_parse_relocation_information(tpnt, 
341                                 tpnt->dynamic_info[DT_JMPREL], 
342                                 tpnt->dynamic_info[DT_PLTRELSZ], 0);
343                 }
344         };
345         return goof;
346 }
347
348 void *_dlsym(void *vhandle, const char *name)
349 {
350         struct elf_resolve *tpnt, *tfrom;
351         struct dyn_elf *handle;
352         char *from;
353         struct dyn_elf *rpnt;
354         void *ret;
355
356         handle = (struct dyn_elf *) vhandle;
357
358         /* First of all verify that we have a real handle
359            of some kind.  Return NULL if not a valid handle. */
360
361         if (handle == NULL)
362                 handle = _dl_symbol_tables;
363         else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
364                 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
365                         if (rpnt == handle)
366                                 break;
367                 if (!rpnt) {
368                         _dl_error_number = LD_BAD_HANDLE;
369                         return NULL;
370                 }
371         } else if (handle == RTLD_NEXT) {
372                 /*
373                  * Try and locate the module we were called from - we
374                  * need this so that we know where to start searching
375                  * from.  We never pass RTLD_NEXT down into the actual
376                  * dynamic loader itself, as it doesn't know
377                  * how to properly treat it.
378                  */
379                 from = __builtin_return_address(0);
380
381                 tfrom = NULL;
382                 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
383                         tpnt = rpnt->dyn;
384                         if (tpnt->loadaddr < from
385                                 && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr)) {
386                                 tfrom = tpnt;
387                                 handle = rpnt->next;
388                         }
389                 }
390         }
391
392         ret = _dl_find_hash((char*)name, handle, NULL, copyrel);
393
394         /*
395          * Nothing found.
396          */
397         if (!ret)
398                 _dl_error_number = LD_NO_SYMBOL;
399         return ret;
400 }
401
402 int _dlclose(void *vhandle)
403 {
404         return do_dlclose(vhandle, 1);
405 }
406
407 static int do_dlclose(void *vhandle, int need_fini)
408 {
409         struct dyn_elf *rpnt, *rpnt1;
410         struct dyn_elf *spnt, *spnt1;
411         elf_phdr *ppnt;
412         struct elf_resolve *tpnt;
413         int (*dl_elf_fini) (void);
414         void (*dl_brk) (void);
415         struct dyn_elf *handle;
416         unsigned int end;
417         int i = 0;
418
419         handle = (struct dyn_elf *) vhandle;
420         rpnt1 = NULL;
421         for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
422                 if (rpnt == handle) {
423                         break;
424                 }
425                 rpnt1 = rpnt;
426         }
427
428         if (!rpnt) {
429                 _dl_error_number = LD_BAD_HANDLE;
430                 return 1;
431         }
432
433         /* OK, this is a valid handle - now close out the file.
434          * We check if we need to call fini () on the handle. */
435         spnt = need_fini ? handle : handle->next;
436         for (; spnt; spnt = spnt1) {
437                 spnt1 = spnt->next;
438
439                 /* We appended the module list to the end - when we get back here, 
440                    quit. The access counts were not adjusted to account for being here. */
441                 if (spnt == _dl_symbol_tables)
442                         break;
443                 if (spnt->dyn->usage_count == 1
444                         && spnt->dyn->libtype == loaded_file) {
445                         tpnt = spnt->dyn;
446                         /* Apparently crt1 for the application is responsible for handling this.
447                          * We only need to run the init/fini for shared libraries
448                          */
449
450                         if (tpnt->dynamic_info[DT_FINI]) {
451                                 dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + 
452                                         tpnt->dynamic_info[DT_FINI]);
453                                 (*dl_elf_fini) ();
454                         }
455                 }
456         }
457         if (rpnt1)
458                 rpnt1->next_handle = rpnt->next_handle;
459         else
460                 _dl_handles = rpnt->next_handle;
461
462         /* OK, this is a valid handle - now close out the file */
463         for (rpnt = handle; rpnt; rpnt = rpnt1) {
464                 rpnt1 = rpnt->next;
465
466                 /* We appended the module list to the end - when we get back here, 
467                    quit. The access counts were not adjusted to account for being here. */
468                 if (rpnt == _dl_symbol_tables)
469                         break;
470
471                 rpnt->dyn->usage_count--;
472                 if (rpnt->dyn->usage_count == 0
473                         && rpnt->dyn->libtype == loaded_file) {
474                         tpnt = rpnt->dyn;
475                         /* Apparently crt1 for the application is responsible for handling this.
476                          * We only need to run the init/fini for shared libraries
477                          */
478 #if 0
479
480                         /* We have to do this above, before we start closing objects.  
481                          * Otherwise when the needed symbols for _fini handling are 
482                          * resolved a coredump would occur. Rob Ryan (robr@cmu.edu)*/ 
483                         if (tpnt->dynamic_info[DT_FINI]) { 
484                             dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
485                                 (*dl_elf_fini) ();
486                         }
487 #endif
488                         end = 0;
489                         for (i = 0, ppnt = rpnt->dyn->ppnt;
490                                  i < rpnt->dyn->n_phent; ppnt++, i++) {
491                                 if (ppnt->p_type != PT_LOAD)
492                                         continue;
493                                 if (end < ppnt->p_vaddr + ppnt->p_memsz)
494                                         end = ppnt->p_vaddr + ppnt->p_memsz;
495                         }
496                         _dl_munmap(rpnt->dyn->loadaddr, end);
497                         /* Next, remove rpnt->dyn from the loaded_module list */
498                         if (_dl_loaded_modules == rpnt->dyn) {
499                                 _dl_loaded_modules = rpnt->dyn->next;
500                                 if (_dl_loaded_modules)
501                                         _dl_loaded_modules->prev = 0;
502                         } else
503                                 for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
504                                         if (tpnt->next == rpnt->dyn) {
505                                                 tpnt->next = tpnt->next->next;
506                                                 if (tpnt->next)
507                                                         tpnt->next->prev = tpnt;
508                                                 break;
509                                         }
510                         free(rpnt->dyn->libname);
511                         free(rpnt->dyn);
512                 }
513                 free(rpnt);
514         }
515
516
517         if (_dl_debug_addr) {
518             dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
519             if (dl_brk != NULL) {
520                 _dl_debug_addr->r_state = RT_DELETE;
521                 (*dl_brk) ();
522
523                 _dl_debug_addr->r_state = RT_CONSISTENT;
524                 (*dl_brk) ();
525             }
526         }
527
528         return 0;
529 }
530
531 const char *_dlerror(void)
532 {
533         const char *retval;
534
535         if (!_dl_error_number)
536                 return NULL;
537         retval = dl_error_names[_dl_error_number];
538         _dl_error_number = 0;
539         return retval;
540 }
541
542 /*
543  * Dump information to stderrr about the current loaded modules
544  */
545 static char *type[] = { "Lib", "Exe", "Int", "Mod" };
546
547 void _dlinfo(void)
548 {
549         struct elf_resolve *tpnt;
550         struct dyn_elf *rpnt, *hpnt;
551
552         _dl_dprintf(2, "List of loaded modules\n");
553         /* First start with a complete list of all of the loaded files. */
554         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) { 
555                 _dl_dprintf(2, "\t%x %x %x %s %d %s\n", 
556                         (unsigned) tpnt->loadaddr, (unsigned) tpnt,
557                         (unsigned) tpnt->symbol_scope,
558                         type[tpnt->libtype],
559                         tpnt->usage_count, tpnt->libname);
560         }
561
562         /* Next dump the module list for the application itself */
563         _dl_dprintf(2, "\nModules for application (%x):\n",
564                                  (unsigned) _dl_symbol_tables);
565         for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
566                 _dl_dprintf(2, "\t%x %s\n", (unsigned) rpnt->dyn, rpnt->dyn->libname);
567
568         for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
569                 _dl_dprintf(2, "Modules for handle %x\n", (unsigned) hpnt);
570                 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
571                         _dl_dprintf(2, "\t%x %s\n", (unsigned) rpnt->dyn, 
572                                 rpnt->dyn->libname);
573         }
574 }
575
576 int _dladdr(void *__address, Dl_info * __dlip)
577 {
578         struct elf_resolve *pelf;
579         struct elf_resolve *rpnt;
580
581 #ifdef USE_CACHE
582         _dl_map_cache();
583 #endif
584
585         /*
586          * Try and locate the module address is in
587          */
588         pelf = NULL;
589
590 #if 0
591         _dl_dprintf(2, "dladdr( 0x%p, 0x%p )\n", __address, __dlip);
592 #endif
593
594         for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
595                 struct elf_resolve *tpnt;
596
597                 tpnt = rpnt;
598 #if 0
599                 _dl_dprintf(2, "Module \"%s\" at 0x%p\n", 
600                         tpnt->libname, tpnt->loadaddr);
601 #endif
602                 if (tpnt->loadaddr < (char *) __address
603                         && (pelf == NULL || pelf->loadaddr < tpnt->loadaddr)) {
604                     pelf = tpnt;
605                 }
606         }
607
608         if (!pelf) {
609                 return 0;
610         }
611
612         /*
613          * Try and locate the symbol of address
614          */
615
616         {
617                 char *strtab;
618                 Elf32_Sym *symtab;
619                 int hn, si;
620                 int sf;
621                 int sn = 0;
622                 void *sa = 0;
623
624                 symtab = (Elf32_Sym *) (pelf->dynamic_info[DT_SYMTAB] + pelf->loadaddr);
625                 strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
626
627                 sf = 0;
628                 for (hn = 0; hn < pelf->nbucket; hn++) {
629                         for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
630                                 void *symbol_addr;
631
632                                 symbol_addr = pelf->loadaddr + symtab[si].st_value;
633                                 if (symbol_addr <= __address && (!sf || sa < symbol_addr)) {
634                                         sa = symbol_addr;
635                                         sn = si;
636                                         sf = 1;
637                                 }
638 #if 0
639                                 _dl_dprintf(2, "Symbol \"%s\" at 0x%p\n", 
640                                         strtab + symtab[si].st_name, symbol_addr);
641 #endif
642                         }
643                 }
644
645                 if (sf) {
646                         __dlip->dli_fname = pelf->libname;
647                         __dlip->dli_fbase = pelf->loadaddr;
648                         __dlip->dli_sname = strtab + symtab[sn].st_name;
649                         __dlip->dli_saddr = sa;
650                 }
651                 return 1;
652         }
653 }