4 * Functions required for dlopen et. al.
11 #include "ld_syscall.h"
13 #include "ld_string.h"
15 extern struct r_debug *_dl_debug_addr;
17 extern void *(*_dl_malloc_function) (size_t size);
19 static int do_fixup(struct elf_resolve *tpnt, int flag);
20 static int do_dlclose(void *, int need_fini);
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")));
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)
35 const char msg[]="libdl library not correctly linked\n";
36 _dl_write(2, msg, _dl_strlen(msg));
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")));
51 extern void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt)
52 __attribute__ ((__weak__, __alias__ ("foobar")));
55 int _dl_map_cache(void) __attribute__ ((__weak__, __alias__ ("foobar")));
56 int _dl_unmap_cache(void) __attribute__ ((__weak__, __alias__ ("foobar")));
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")));
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
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"
87 static const char *dl_error_names[] = {
90 "Unable to open /dev/zero",
92 #if defined (__i386__)
94 #elif defined (__sparc__)
96 #elif defined (__mc68000__)
99 "Unrecognized binary type",
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",
107 "Unable to process RELA relocs",
110 "Unable to resolve symbol"
113 static void __attribute__ ((destructor)) dl_cleanup(void)
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;
124 void *_dlopen(const char *libname, int flag)
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;
132 void (*dl_brk) (void);
134 int (*dl_elf_init) (void);
137 /* A bit of sanity checking... */
138 if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
139 _dl_error_number = LD_BAD_HANDLE;
143 from = __builtin_return_address(0);
145 /* Have the dynamic linker use the regular malloc function now */
148 _dl_malloc_function = malloc;
151 /* Cover the trivial case first */
153 return _dl_symbol_tables;
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
168 for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
170 if (tpnt->loadaddr < from
171 && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
175 if (!(tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname))) {
181 //tpnt->libtype = loaded_file;
183 dyn_chain = rpnt = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
184 _dl_memset(rpnt, 0, sizeof(struct dyn_elf));
187 if (!tpnt->symbol_scope)
188 tpnt->symbol_scope = dyn_chain;
190 rpnt->next_handle = _dl_handles;
194 * OK, we have the requested file in memory. Now check for
195 * any other requested files that may also be required.
198 struct elf_resolve *tcurr;
199 struct elf_resolve * tpnt1;
205 for(dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
208 if(dpnt->d_tag == DT_NEEDED)
210 lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
212 if(!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpnt)))
215 rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
216 _dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
218 if (!tpnt1->symbol_scope) tpnt1->symbol_scope = dyn_chain;
228 * OK, now attach the entire chain at the end
231 rpnt->next = _dl_symbol_tables;
234 * MIPS is special *sigh*
237 _dl_perform_mips_global_got_relocations(tpnt);
240 if (do_fixup(tpnt, flag)) {
241 _dl_error_number = LD_NO_SYMBOL;
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;
251 _dl_debug_addr->r_state = RT_CONSISTENT;
257 /* Find the last library */
258 for (tpnt = dyn_chain->dyn; tpnt->next!=NULL; tpnt = tpnt->next)
260 /* Run the ctors and set up the dtors */
261 for (; tpnt != dyn_chain->dyn->prev; tpnt=tpnt->prev)
263 /* Apparently crt1 for the application is responsible for handling this.
264 * We only need to run the init/fini for shared libraries
266 if (tpnt->libtype == program_interpreter)
268 if (tpnt->libtype == elf_executable)
270 if (tpnt->init_flag & INIT_FUNCS_CALLED)
272 tpnt->init_flag |= INIT_FUNCS_CALLED;
274 if (tpnt->dynamic_info[DT_INIT]) {
275 dl_elf_init = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
278 if (tpnt->dynamic_info[DT_FINI]) {
279 atexit((void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]));
288 return (void *) dyn_chain;
291 /* Something went wrong. Clean up and return NULL. */
295 do_dlclose(dyn_chain, 0);
299 static int do_fixup(struct elf_resolve *tpnt, int flag)
304 goof += do_fixup(tpnt->next, flag);
306 if (tpnt->dynamic_info[DT_REL]) {
307 #ifdef ELF_USES_RELOCA
310 if (tpnt->init_flag & RELOCS_DONE)
312 tpnt->init_flag |= RELOCS_DONE;
314 goof += _dl_parse_relocation_information(tpnt,
315 tpnt->dynamic_info[DT_REL], tpnt->dynamic_info[DT_RELSZ], 0);
318 if (tpnt->dynamic_info[DT_RELA]) {
319 #ifdef ELF_USES_RELOCA
320 if (tpnt->init_flag & RELOCS_DONE)
322 tpnt->init_flag |= RELOCS_DONE;
324 goof += _dl_parse_relocation_information(tpnt,
325 tpnt->dynamic_info[DT_RELA], tpnt->dynamic_info[DT_RELASZ], 0);
330 if (tpnt->dynamic_info[DT_JMPREL]) {
331 if (tpnt->init_flag & JMP_RELOCS_DONE)
333 tpnt->init_flag |= JMP_RELOCS_DONE;
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);
340 goof += _dl_parse_relocation_information(tpnt,
341 tpnt->dynamic_info[DT_JMPREL],
342 tpnt->dynamic_info[DT_PLTRELSZ], 0);
348 void *_dlsym(void *vhandle, const char *name)
350 struct elf_resolve *tpnt, *tfrom;
351 struct dyn_elf *handle;
353 struct dyn_elf *rpnt;
356 handle = (struct dyn_elf *) vhandle;
358 /* First of all verify that we have a real handle
359 of some kind. Return NULL if not a valid handle. */
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)
368 _dl_error_number = LD_BAD_HANDLE;
371 } else if (handle == RTLD_NEXT) {
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.
379 from = __builtin_return_address(0);
382 for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
384 if (tpnt->loadaddr < from
385 && (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr)) {
392 ret = _dl_find_hash((char*)name, handle, NULL, copyrel);
398 _dl_error_number = LD_NO_SYMBOL;
402 int _dlclose(void *vhandle)
404 return do_dlclose(vhandle, 1);
407 static int do_dlclose(void *vhandle, int need_fini)
409 struct dyn_elf *rpnt, *rpnt1;
410 struct dyn_elf *spnt, *spnt1;
412 struct elf_resolve *tpnt;
413 int (*dl_elf_fini) (void);
414 void (*dl_brk) (void);
415 struct dyn_elf *handle;
419 handle = (struct dyn_elf *) vhandle;
421 for (rpnt = _dl_handles; rpnt; rpnt = rpnt->next_handle) {
422 if (rpnt == handle) {
429 _dl_error_number = LD_BAD_HANDLE;
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) {
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)
443 if (spnt->dyn->usage_count == 1
444 && spnt->dyn->libtype == loaded_file) {
446 /* Apparently crt1 for the application is responsible for handling this.
447 * We only need to run the init/fini for shared libraries
450 if (tpnt->dynamic_info[DT_FINI]) {
451 dl_elf_fini = (int (*)(void)) (tpnt->loadaddr +
452 tpnt->dynamic_info[DT_FINI]);
458 rpnt1->next_handle = rpnt->next_handle;
460 _dl_handles = rpnt->next_handle;
462 /* OK, this is a valid handle - now close out the file */
463 for (rpnt = handle; rpnt; rpnt = rpnt1) {
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)
471 rpnt->dyn->usage_count--;
472 if (rpnt->dyn->usage_count == 0
473 && rpnt->dyn->libtype == loaded_file) {
475 /* Apparently crt1 for the application is responsible for handling this.
476 * We only need to run the init/fini for shared libraries
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]);
489 for (i = 0, ppnt = rpnt->dyn->ppnt;
490 i < rpnt->dyn->n_phent; ppnt++, i++) {
491 if (ppnt->p_type != PT_LOAD)
493 if (end < ppnt->p_vaddr + ppnt->p_memsz)
494 end = ppnt->p_vaddr + ppnt->p_memsz;
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;
503 for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next)
504 if (tpnt->next == rpnt->dyn) {
505 tpnt->next = tpnt->next->next;
507 tpnt->next->prev = tpnt;
510 free(rpnt->dyn->libname);
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;
523 _dl_debug_addr->r_state = RT_CONSISTENT;
531 const char *_dlerror(void)
535 if (!_dl_error_number)
537 retval = dl_error_names[_dl_error_number];
538 _dl_error_number = 0;
543 * Dump information to stderrr about the current loaded modules
545 static char *type[] = { "Lib", "Exe", "Int", "Mod" };
549 struct elf_resolve *tpnt;
550 struct dyn_elf *rpnt, *hpnt;
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,
559 tpnt->usage_count, tpnt->libname);
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);
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,
576 int _dladdr(void *__address, Dl_info * __dlip)
578 struct elf_resolve *pelf;
579 struct elf_resolve *rpnt;
586 * Try and locate the module address is in
591 _dl_dprintf(2, "dladdr( 0x%p, 0x%p )\n", __address, __dlip);
594 for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
595 struct elf_resolve *tpnt;
599 _dl_dprintf(2, "Module \"%s\" at 0x%p\n",
600 tpnt->libname, tpnt->loadaddr);
602 if (tpnt->loadaddr < (char *) __address
603 && (pelf == NULL || pelf->loadaddr < tpnt->loadaddr)) {
613 * Try and locate the symbol of address
624 symtab = (Elf32_Sym *) (pelf->dynamic_info[DT_SYMTAB] + pelf->loadaddr);
625 strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
628 for (hn = 0; hn < pelf->nbucket; hn++) {
629 for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
632 symbol_addr = pelf->loadaddr + symtab[si].st_value;
633 if (symbol_addr <= __address && (!sf || sa < symbol_addr)) {
639 _dl_dprintf(2, "Symbol \"%s\" at 0x%p\n",
640 strtab + symtab[si].st_name, symbol_addr);
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;