OSDN Git Service

Hopefully fix Laszlo and Jacobs dlopen problem.
[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-2004 by Erik Andersen <andersen@codpoet.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
36
37 #if defined (__LIBDL_SHARED__)
38
39 /* When libdl is loaded as a shared library, we need to load in
40  * and use a pile of symbols from ldso... */
41
42 extern char *_dl_find_hash(const char *, struct dyn_elf *, int)
43         __attribute__ ((__weak__));
44 extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **,
45         struct elf_resolve *, char *, int) __attribute__ ((__weak__));
46 extern struct elf_resolve * _dl_check_if_named_library_is_loaded(const char *, int)
47         __attribute__ ((__weak__));
48 extern int _dl_fixup(struct dyn_elf *rpnt, int lazy)
49          __attribute__ ((__weak__));
50 extern int _dl_errno __attribute__ ((__weak__));
51 extern struct dyn_elf *_dl_symbol_tables __attribute__ ((__weak__));
52 extern struct dyn_elf *_dl_handles __attribute__ ((__weak__));
53 extern struct elf_resolve *_dl_loaded_modules __attribute__ ((__weak__));
54 extern struct r_debug *_dl_debug_addr __attribute__ ((__weak__));
55 extern unsigned long _dl_error_number __attribute__ ((__weak__));
56 extern void *(*_dl_malloc_function)(size_t) __attribute__ ((__weak__));
57 #ifdef USE_CACHE
58 int _dl_map_cache(void) __attribute__ ((__weak__));
59 int _dl_unmap_cache(void) __attribute__ ((__weak__));
60 #endif
61 #ifdef __mips__
62 extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt)
63         __attribute__ ((__weak__));
64 #endif
65 #ifdef __SUPPORT_LD_DEBUG__
66 extern char *_dl_debug __attribute__ ((__weak__));
67 #endif
68
69
70 #else /* __LIBDL_SHARED__ */
71
72 /* When libdl is linked as a static library, we need to replace all
73  * the symbols that otherwise would have been loaded in from ldso... */
74
75 #ifdef __SUPPORT_LD_DEBUG__
76 char *_dl_debug  = 0;
77 #endif
78 char *_dl_library_path         = 0;                 /* Where we look for libraries */
79 char *_dl_ldsopath             = 0;                 /* Location of the shared lib loader */
80 int _dl_errno                  = 0;         /* We can't use the real errno in ldso */
81 size_t _dl_pagesize            = PAGE_SIZE; /* Store the page size for use later */
82 /* This global variable is also to communicate with debuggers such as gdb. */
83 struct r_debug *_dl_debug_addr = NULL;
84 #define _dl_malloc malloc
85 #include "dl-progname.h"
86 #include "../ldso/dl-hash.c"
87 #define _dl_trace_loaded_objects    0
88 #include "../ldso/dl-elf.c"
89 #endif
90
91 static int do_dlclose(void *, int need_fini);
92
93
94 static const char *dl_error_names[] = {
95         "",
96         "File not found",
97         "Unable to open /dev/zero",
98         "Not an ELF file",
99 #if defined (__i386__)
100         "Not i386 binary",
101 #elif defined (__sparc__)
102         "Not sparc binary",
103 #elif defined (__mc68000__)
104         "Not m68k binary",
105 #else
106         "Unrecognized binary type",
107 #endif
108         "Not an ELF shared library",
109         "Unable to mmap file",
110         "No dynamic section",
111 #ifdef ELF_USES_RELOCA
112         "Unable to process REL relocs",
113 #else
114         "Unable to process RELA relocs",
115 #endif
116         "Bad handle",
117         "Unable to resolve symbol"
118 };
119
120 void __attribute__ ((destructor)) dl_cleanup(void)
121 {
122         struct dyn_elf *d;
123         for (d = _dl_handles; d; d = d->next_handle) {
124                 do_dlclose(d, 1);
125         }
126 }
127
128 void *dlopen(const char *libname, int flag)
129 {
130         struct elf_resolve *tpnt, *tfrom, *tcurr;
131         struct dyn_elf *dyn_chain, *rpnt = NULL, *dyn_ptr;
132         struct dyn_elf *dpnt;
133         static int dl_init = 0;
134         ElfW(Addr) from;
135         struct elf_resolve *tpnt1;
136         void (*dl_brk) (void);
137         int now_flag;
138
139         /* A bit of sanity checking... */
140         if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
141                 _dl_error_number = LD_BAD_HANDLE;
142                 return NULL;
143         }
144
145         from = (ElfW(Addr)) __builtin_return_address(0);
146
147         /* Have the dynamic linker use the regular malloc function now */
148         if (!dl_init) {
149                 dl_init++;
150 #if defined (__LIBDL_SHARED__)
151                 _dl_malloc_function = malloc;
152 #endif
153         }
154
155         /* Cover the trivial case first */
156         if (!libname)
157                 return _dl_symbol_tables;
158
159         _dl_map_cache();
160
161         /*
162          * Try and locate the module we were called from - we
163          * need this so that we get the correct RPATH.  Note that
164          * this is the current behavior under Solaris, but the
165          * ABI+ specifies that we should only use the RPATH from
166          * the application.  Thus this may go away at some time
167          * in the future.
168          */
169         tfrom = NULL;
170         for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
171                 tpnt = dpnt->dyn;
172                 if (tpnt->loadaddr < from
173                                 && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
174                         tfrom = tpnt;
175         }
176         for(rpnt = _dl_symbol_tables; rpnt->next; rpnt=rpnt->next);
177         /* Try to load the specified library */
178 #ifdef __SUPPORT_LD_DEBUG__
179         if(_dl_debug)
180                 fprintf(stderr, "Trying to dlopen '%s'\n", (char*)libname);
181 #endif
182         tpnt = _dl_check_if_named_library_is_loaded((char *)libname, 0);
183         if (!(tpnt))
184                 tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname, 0);
185         else
186                 tpnt->usage_count++;
187         if (tpnt == NULL) {
188                 _dl_unmap_cache();
189                 return NULL;
190         }
191
192         dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
193         _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
194         dyn_chain->dyn = tpnt;
195         tpnt->rtld_flags |= RTLD_GLOBAL;
196
197         dyn_chain->next_handle = _dl_handles;
198         _dl_handles = dyn_ptr = dyn_chain;
199
200 #ifdef __SUPPORT_LD_DEBUG__
201         if(_dl_debug)
202                 fprintf(stderr, "Looking for needed libraries\n");
203 #endif
204
205         for (tcurr = tpnt; tcurr; tcurr = tcurr->next)
206         {
207                 Elf32_Dyn *dpnt;
208                 char *lpntstr;
209                 for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++) {
210                         if (dpnt->d_tag == DT_NEEDED) {
211
212                                 char *name;
213                                 lpntstr = (char*) (tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
214                                                 dpnt->d_un.d_val);
215                                 name = _dl_get_last_path_component(lpntstr);
216                                 tpnt1 = _dl_check_if_named_library_is_loaded(name, 0);
217 #ifdef __SUPPORT_LD_DEBUG__
218                                 if(_dl_debug)
219                                         fprintf(stderr, "Trying to load '%s', needed by '%s'\n",
220                                                         lpntstr, tcurr->libname);
221 #endif
222                                 dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
223                                 _dl_memset (dyn_ptr->next, 0, sizeof (struct dyn_elf));
224                                 dyn_ptr = dyn_ptr->next;
225                                 dyn_ptr->dyn = tpnt1;
226                                 tpnt->rtld_flags |= RTLD_GLOBAL;
227                                 if (!tpnt1) {
228                                         tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr, 0);
229                                         if (!tpnt1)
230                                                 goto oops;
231                                         dyn_ptr->dyn = tpnt1;
232                                 } else {
233                                         tpnt1->usage_count++;
234                                 }
235                         }
236                 }
237         }
238
239         if (dyn_chain->dyn->init_flag & INIT_FUNCS_CALLED) {
240                 /* If the init and fini stuff has already been run, that means
241                  * the dlopen'd library has already been loaded, and nothing
242                  * further needs to be done. */
243                 return (void *) dyn_chain;
244         }
245 #ifdef __mips__
246         /*
247          * Relocation of the GOT entries for MIPS have to be done
248          * after all the libraries have been loaded.
249          */
250         _dl_perform_mips_global_got_relocations(tpnt);
251 #endif
252
253 #ifdef __SUPPORT_LD_DEBUG__
254         if(_dl_debug)
255                 fprintf(stderr, "Beginning dlopen relocation fixups\n");
256 #endif
257         /*
258          * OK, now all of the kids are tucked into bed in their proper addresses.
259          * Now we go through and look for REL and RELA records that indicate fixups
260          * to the GOT tables.  We need to do this in reverse order so that COPY
261          * directives work correctly */
262         now_flag = (flag & RTLD_NOW) ? RTLD_NOW : 0;
263         if (getenv("LD_BIND_NOW"))
264                 now_flag = RTLD_NOW;
265         if (_dl_fixup(dyn_chain, now_flag))
266                 goto oops;
267
268         /* TODO:  Should we set the protections of all pages back to R/O now ? */
269
270
271         /* Notify the debugger we have added some objects. */
272         if (_dl_debug_addr) {
273                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
274                 if (dl_brk != NULL) {
275                         _dl_debug_addr->r_state = RT_ADD;
276                         (*dl_brk) ();
277
278                         _dl_debug_addr->r_state = RT_CONSISTENT;
279                         (*dl_brk) ();
280                 }
281         }
282
283 #if defined (__LIBDL_SHARED__)
284         /* Find the last library so we can run things in the right order */
285         for (tpnt = dyn_chain->dyn; tpnt->next!=NULL; tpnt = tpnt->next)
286                 ;
287
288         /* Run the ctors and set up the dtors */
289         for (; tpnt != dyn_chain->dyn->prev; tpnt=tpnt->prev)
290         {
291                 /* Apparently crt1 for the application is responsible for handling this.
292                  * We only need to run the init/fini for shared libraries
293                  */
294                 if (tpnt->libtype == program_interpreter)
295                         continue;
296                 if (tpnt->libtype == elf_executable)
297                         continue;
298                 if (tpnt->init_flag & INIT_FUNCS_CALLED)
299                         continue;
300                 tpnt->init_flag |= INIT_FUNCS_CALLED;
301
302                 if (tpnt->dynamic_info[DT_INIT]) {
303                         void (*dl_elf_func) (void);
304                         dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
305                         if (dl_elf_func && *dl_elf_func != NULL) {
306 #ifdef __SUPPORT_LD_DEBUG__
307                                 if(_dl_debug)
308                                         fprintf(stderr, "running ctors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
309 #endif
310                                 (*dl_elf_func) ();
311                         }
312                 }
313         }
314 #endif
315         return (void *) dyn_chain;
316
317 oops:
318         /* Something went wrong.  Clean up and return NULL. */
319         _dl_unmap_cache();
320         do_dlclose(dyn_chain, 0);
321         return NULL;
322 }
323
324 void *dlsym(void *vhandle, const char *name)
325 {
326         struct elf_resolve *tpnt, *tfrom;
327         struct dyn_elf *handle;
328         ElfW(Addr) from;
329         struct dyn_elf *rpnt;
330         void *ret;
331
332         handle = (struct dyn_elf *) vhandle;
333
334         /* First of all verify that we have a real handle
335            of some kind.  Return NULL if not a valid handle. */
336
337         if (handle == NULL)
338                 handle = _dl_symbol_tables;
339         else if (handle != RTLD_NEXT && handle != _dl_symbol_tables) {
340                 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle)
341                         if (rpnt == handle)
342                                 break;
343                 if (!rpnt) {
344                         _dl_error_number = LD_BAD_HANDLE;
345                         return NULL;
346                 }
347         } else if (handle == RTLD_NEXT) {
348                 /*
349                  * Try and locate the module we were called from - we
350                  * need this so that we know where to start searching
351                  * from.  We never pass RTLD_NEXT down into the actual
352                  * dynamic loader itself, as it doesn't know
353                  * how to properly treat it.
354                  */
355                 from = (ElfW(Addr)) __builtin_return_address(0);
356
357                 tfrom = NULL;
358                 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
359                         tpnt = rpnt->dyn;
360                         if (tpnt->loadaddr < from
361                                         && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr)) {
362                                 tfrom = tpnt;
363                                 handle = rpnt->next;
364                         }
365                 }
366         }
367
368         ret = _dl_find_hash((char*)name, handle, 0);
369
370         /*
371          * Nothing found.
372          */
373         if (!ret)
374                 _dl_error_number = LD_NO_SYMBOL;
375         return ret;
376 }
377
378 static int do_dlclose(void *vhandle, int need_fini)
379 {
380         struct dyn_elf *rpnt, *rpnt1;
381         ElfW(Phdr) *ppnt;
382         struct elf_resolve *tpnt;
383         int (*dl_elf_fini) (void);
384         void (*dl_brk) (void);
385         struct dyn_elf *handle;
386         unsigned int end;
387         int i = 0;
388
389         handle = (struct dyn_elf *) vhandle;
390         rpnt1 = NULL;
391         for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
392                 if (rpnt == handle)
393                         break;
394                 rpnt1 = rpnt;
395         }
396
397         if (!rpnt) {
398                 _dl_error_number = LD_BAD_HANDLE;
399                 return 1;
400         }
401         if (rpnt1)
402                 rpnt1->next_handle = rpnt->next_handle;
403         else
404                 _dl_handles = rpnt->next_handle;
405         /* OK, this is a valid handle - now close out the file */
406         for (rpnt = handle; rpnt; rpnt = rpnt->next) {
407                 tpnt = rpnt->dyn;
408                 if (--tpnt->usage_count == 0) {
409                         if (need_fini && tpnt->dynamic_info[DT_FINI]) {
410                                 dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
411                                 (*dl_elf_fini) ();
412                         }
413
414                         end = 0;
415                         for (i = 0, ppnt = tpnt->ppnt;
416                                         i < tpnt->n_phent; ppnt++, i++) {
417                                 if (ppnt->p_type != PT_LOAD)
418                                         continue;
419                                 if (end < ppnt->p_vaddr + ppnt->p_memsz)
420                                         end = ppnt->p_vaddr + ppnt->p_memsz;
421                         }
422                         _dl_munmap((void*)tpnt->loadaddr, end);
423                         /* Next, remove tpnt from the loaded_module list */
424                         if (_dl_loaded_modules == tpnt) {
425                                 _dl_loaded_modules = tpnt->next;
426                                 if (_dl_loaded_modules)
427                                         _dl_loaded_modules->prev = 0;
428                         } else
429                                 for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
430                                         if (tpnt->next == rpnt->dyn) {
431                                                 tpnt->next = tpnt->next->next;
432                                                 if (tpnt->next)
433                                                         tpnt->next->prev = tpnt;
434                                                 break;
435                                         }
436
437                         /* Next, remove tpnt from the global symbol table list */
438                         if (_dl_symbol_tables->dyn == rpnt->dyn) {
439                                 _dl_symbol_tables = rpnt->next;
440                                 if (_dl_symbol_tables)
441                                         _dl_symbol_tables->prev = 0;
442                         } else
443                                 for (rpnt1 = _dl_symbol_tables; rpnt1->next; rpnt1 = rpnt1->next) {
444                                         if (rpnt1->next->dyn == rpnt->dyn) {
445                                                 free(rpnt1->next);
446                                                 rpnt1->next = rpnt1->next->next;
447                                                 if (rpnt1->next)
448                                                         rpnt1->next->prev = rpnt1;
449                                                 break;
450                                         }
451                                 }
452                         free(rpnt->dyn->libname);
453                         free(rpnt->dyn);
454                 }
455                 free(rpnt);
456         }
457
458
459         if (_dl_debug_addr) {
460                 dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
461                 if (dl_brk != NULL) {
462                         _dl_debug_addr->r_state = RT_DELETE;
463                         (*dl_brk) ();
464
465                         _dl_debug_addr->r_state = RT_CONSISTENT;
466                         (*dl_brk) ();
467                 }
468         }
469
470         return 0;
471 }
472
473 int dlclose(void *vhandle)
474 {
475         return do_dlclose(vhandle, 1);
476 }
477
478 const char *dlerror(void)
479 {
480         const char *retval;
481
482         if (!_dl_error_number)
483                 return NULL;
484         retval = dl_error_names[_dl_error_number];
485         _dl_error_number = 0;
486         return retval;
487 }
488
489 /*
490  * Dump information to stderrr about the current loaded modules
491  */
492 static char *type[] = { "Lib", "Exe", "Int", "Mod" };
493
494 void dlinfo(void)
495 {
496         struct elf_resolve *tpnt;
497         struct dyn_elf *rpnt, *hpnt;
498
499         fprintf(stderr, "List of loaded modules\n");
500         /* First start with a complete list of all of the loaded files. */
501         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
502                 fprintf(stderr, "\t%x %x %x %s %d %s\n",
503                                 (unsigned) tpnt->loadaddr, (unsigned) tpnt,
504                                 (unsigned) tpnt->symbol_scope,
505                                 type[tpnt->libtype],
506                                 tpnt->usage_count, tpnt->libname);
507         }
508
509         /* Next dump the module list for the application itself */
510         fprintf(stderr, "\nModules for application (%x):\n",
511                         (unsigned) _dl_symbol_tables);
512         for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next)
513                 fprintf(stderr, "\t%x %s\n", (unsigned) rpnt->dyn, rpnt->dyn->libname);
514
515         for (hpnt = _dl_handles; hpnt; hpnt = hpnt->next_handle) {
516                 fprintf(stderr, "Modules for handle %x\n", (unsigned) hpnt);
517                 for (rpnt = hpnt; rpnt; rpnt = rpnt->next)
518                         fprintf(stderr, "\t%x %s\n", (unsigned) rpnt->dyn,
519                                         rpnt->dyn->libname);
520         }
521 }
522
523 int dladdr(void *__address, Dl_info * __dlip)
524 {
525         struct elf_resolve *pelf;
526         struct elf_resolve *rpnt;
527
528         _dl_map_cache();
529
530         /*
531          * Try and locate the module address is in
532          */
533         pelf = NULL;
534
535 #if 0
536         fprintf(stderr, "dladdr( %x, %x )\n", __address, __dlip);
537 #endif
538
539         for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
540                 struct elf_resolve *tpnt;
541
542                 tpnt = rpnt;
543 #if 0
544                 fprintf(stderr, "Module \"%s\" at %x\n",
545                                 tpnt->libname, tpnt->loadaddr);
546 #endif
547                 if (tpnt->loadaddr < (ElfW(Addr)) __address
548                                 && (pelf == NULL || pelf->loadaddr < tpnt->loadaddr)) {
549                         pelf = tpnt;
550                 }
551         }
552
553         if (!pelf) {
554                 return 0;
555         }
556
557         /*
558          * Try and locate the symbol of address
559          */
560
561         {
562                 char *strtab;
563                 Elf32_Sym *symtab;
564                 int hn, si;
565                 int sf;
566                 int sn = 0;
567                 ElfW(Addr) sa;
568
569                 sa = 0;
570                 symtab = (Elf32_Sym *) (pelf->dynamic_info[DT_SYMTAB] + pelf->loadaddr);
571                 strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
572
573                 sf = 0;
574                 for (hn = 0; hn < pelf->nbucket; hn++) {
575                         for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
576                                 ElfW(Addr) symbol_addr;
577
578                                 symbol_addr = pelf->loadaddr + symtab[si].st_value;
579                                 if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
580                                         sa = symbol_addr;
581                                         sn = si;
582                                         sf = 1;
583                                 }
584 #if 0
585                                 fprintf(stderr, "Symbol \"%s\" at %x\n",
586                                                 strtab + symtab[si].st_name, symbol_addr);
587 #endif
588                         }
589                 }
590
591                 if (sf) {
592                         __dlip->dli_fname = pelf->libname;
593                         __dlip->dli_fbase = (void *)pelf->loadaddr;
594                         __dlip->dli_sname = strtab + symtab[sn].st_name;
595                         __dlip->dli_saddr = (void *)sa;
596                 }
597                 return 1;
598         }
599 }