21 static char errbuf[128];
25 #if ULONG_MAX == 0xffffffff
26 typedef Elf32_Ehdr Ehdr;
27 typedef Elf32_Phdr Phdr;
28 typedef Elf32_Sym Sym;
29 #define R_TYPE(x) ((x)&255)
30 #define R_SYM(x) ((x)>>8)
32 typedef Elf64_Ehdr Ehdr;
33 typedef Elf64_Phdr Phdr;
34 typedef Elf64_Sym Sym;
35 #define R_TYPE(x) ((x)&0xffffffff)
36 #define R_SYM(x) ((x)>>32)
51 struct dso *next, *prev;
72 void __init_ssp(size_t *);
74 static struct dso *head, *tail, *libc;
75 static char *env_path, *sys_path, *r_path;
81 static jmp_buf rtld_fail;
82 static pthread_rwlock_t lock;
83 static struct debug debug;
86 struct debug *_dl_debug_addr = &debug;
91 static void decode_vec(size_t *v, size_t *a, size_t cnt)
93 memset(a, 0, cnt*sizeof(size_t));
94 for (; v[0]; v+=2) if (v[0]<cnt) {
100 static int search_vec(size_t *v, size_t *r, size_t key)
102 for (; v[0]!=key; v+=2)
108 static uint32_t sysv_hash(const char *s0)
110 const unsigned char *s = (void *)s0;
116 return h & 0xfffffff;
119 static uint32_t gnu_hash(const char *s0)
121 const unsigned char *s = (void *)s0;
122 uint_fast32_t h = 5381;
128 static Sym *sysv_lookup(const char *s, uint32_t h, struct dso *dso)
131 Sym *syms = dso->syms;
132 uint32_t *hashtab = dso->hashtab;
133 char *strings = dso->strings;
134 for (i=hashtab[2+h%hashtab[0]]; i; i=hashtab[2+hashtab[0]+i]) {
135 if (!strcmp(s, strings+syms[i].st_name))
141 static Sym *gnu_lookup(const char *s, uint32_t h1, struct dso *dso)
145 uint32_t *hashtab = dso->ghashtab;
146 uint32_t nbuckets = hashtab[0];
147 uint32_t *buckets = hashtab + 4 + hashtab[2]*(sizeof(size_t)/4);
150 uint32_t n = buckets[h1 % nbuckets];
154 strings = dso->strings;
156 hashval = buckets + nbuckets + (n - hashtab[1]);
158 for (h1 |= 1; ; sym++) {
160 if ((h1 == (h2|1)) && !strcmp(s, strings + sym->st_name))
168 #define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON)
169 #define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK)
171 static void *find_sym(struct dso *dso, const char *s, int need_def)
173 uint32_t h = 0, gh = 0;
177 if (gh == 0xf9040207 && !strcmp(s, "dlopen")) rtld_used = 1;
178 if (gh == 0xf4dc4ae && !strcmp(s, "dlsym")) rtld_used = 1;
179 if (gh == 0x1f4039c9 && !strcmp(s, "__stack_chk_fail")) ssp_used = 1;
182 if (h == 0x6b366be && !strcmp(s, "dlopen")) rtld_used = 1;
183 if (h == 0x6b3afd && !strcmp(s, "dlsym")) rtld_used = 1;
184 if (h == 0x595a4cc && !strcmp(s, "__stack_chk_fail")) ssp_used = 1;
186 for (; dso; dso=dso->next) {
188 if (!dso->global) continue;
190 if (!gh) gh = gnu_hash(s);
191 sym = gnu_lookup(s, gh, dso);
193 if (!h) h = sysv_hash(s);
194 sym = sysv_lookup(s, h, dso);
196 if (sym && (!need_def || sym->st_shndx) && sym->st_value
197 && (1<<(sym->st_info&0xf) & OK_TYPES)
198 && (1<<(sym->st_info>>4) & OK_BINDS)) {
199 if (def && sym->st_info>>4 == STB_WEAK) continue;
200 def = dso->base + sym->st_value;
201 if (sym->st_info>>4 == STB_GLOBAL) break;
207 static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride)
209 unsigned char *base = dso->base;
210 Sym *syms = dso->syms;
211 char *strings = dso->strings;
214 size_t sym_val, sym_size;
220 for (; rel_size; rel+=stride, rel_size-=stride*sizeof(size_t)) {
221 reloc_addr = (void *)(base + rel[0]);
222 type = R_TYPE(rel[1]);
223 sym_index = R_SYM(rel[1]);
225 sym = syms + sym_index;
226 name = strings + sym->st_name;
227 ctx = IS_COPY(type) ? head->next : head;
228 sym_val = (size_t)find_sym(ctx, name, IS_PLT(type));
229 if (!sym_val && sym->st_info>>4 != STB_WEAK) {
230 snprintf(errbuf, sizeof errbuf,
231 "Error relocating %s: %s: symbol not found",
233 if (runtime) longjmp(rtld_fail, 1);
234 dprintf(2, "%s\n", errbuf);
238 sym_size = sym->st_size;
240 sym_val = sym_size = 0;
242 do_single_reloc(reloc_addr, type, sym_val, sym_size, base, rel[2]);
246 /* A huge hack: to make up for the wastefulness of shared libraries
247 * needing at least a page of dirty memory even if they have no global
248 * data, we reclaim the gaps at the beginning and end of writable maps
249 * and "donate" them to the heap by setting up minimal malloc
250 * structures and then freeing them. */
252 static void reclaim(unsigned char *base, size_t start, size_t end)
255 start = start + 6*sizeof(size_t)-1 & -4*sizeof(size_t);
256 end = (end & -4*sizeof(size_t)) - 2*sizeof(size_t);
257 if (start>end || end-start < 4*sizeof(size_t)) return;
258 a = (size_t *)(base + start);
259 z = (size_t *)(base + end);
261 a[-1] = z[0] = end-start + 2*sizeof(size_t) | 1;
266 static void reclaim_gaps(unsigned char *base, Phdr *ph, size_t phent, size_t phcnt)
268 for (; phcnt--; ph=(void *)((char *)ph+phent)) {
269 if (ph->p_type!=PT_LOAD) continue;
270 if ((ph->p_flags&(PF_R|PF_W))!=(PF_R|PF_W)) continue;
271 reclaim(base, ph->p_vaddr & -PAGE_SIZE, ph->p_vaddr);
272 reclaim(base, ph->p_vaddr+ph->p_memsz,
273 ph->p_vaddr+ph->p_memsz+PAGE_SIZE-1 & -PAGE_SIZE);
277 static void *map_library(int fd, size_t *lenp, unsigned char **basep, size_t *dynp)
279 Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)];
281 size_t addr_min=SIZE_MAX, addr_max=0, map_len;
282 size_t this_min, this_max;
287 unsigned char *map, *base;
291 ssize_t l = read(fd, buf, sizeof buf);
292 if (l<sizeof *eh) return 0;
294 phsize = eh->e_phentsize * eh->e_phnum;
295 if (phsize + sizeof *eh > l) return 0;
296 if (eh->e_phoff + phsize > l) {
297 l = pread(fd, buf+1, phsize, eh->e_phoff);
298 if (l != phsize) return 0;
299 eh->e_phoff = sizeof *eh;
301 ph = (void *)((char *)buf + eh->e_phoff);
302 for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) {
303 if (ph->p_type == PT_DYNAMIC)
305 if (ph->p_type != PT_LOAD) continue;
306 if (ph->p_vaddr < addr_min) {
307 addr_min = ph->p_vaddr;
308 off_start = ph->p_offset;
309 prot = (((ph->p_flags&PF_R) ? PROT_READ : 0) |
310 ((ph->p_flags&PF_W) ? PROT_WRITE: 0) |
311 ((ph->p_flags&PF_X) ? PROT_EXEC : 0));
313 if (ph->p_vaddr+ph->p_memsz > addr_max) {
314 addr_max = ph->p_vaddr+ph->p_memsz;
318 addr_max += PAGE_SIZE-1;
319 addr_max &= -PAGE_SIZE;
320 addr_min &= -PAGE_SIZE;
321 off_start &= -PAGE_SIZE;
322 map_len = addr_max - addr_min + off_start;
323 /* The first time, we map too much, possibly even more than
324 * the length of the file. This is okay because we will not
325 * use the invalid part; we just need to reserve the right
326 * amount of virtual address space to map over later. */
327 map = mmap((void *)addr_min, map_len, prot, MAP_PRIVATE, fd, off_start);
328 if (map==MAP_FAILED) return 0;
329 base = map - addr_min;
330 ph = (void *)((char *)buf + eh->e_phoff);
331 for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) {
332 if (ph->p_type != PT_LOAD) continue;
333 /* Reuse the existing mapping for the lowest-address LOAD */
334 if ((ph->p_vaddr & -PAGE_SIZE) == addr_min) continue;
335 this_min = ph->p_vaddr & -PAGE_SIZE;
336 this_max = ph->p_vaddr+ph->p_memsz+PAGE_SIZE-1 & -PAGE_SIZE;
337 off_start = ph->p_offset & -PAGE_SIZE;
338 prot = (((ph->p_flags&PF_R) ? PROT_READ : 0) |
339 ((ph->p_flags&PF_W) ? PROT_WRITE: 0) |
340 ((ph->p_flags&PF_X) ? PROT_EXEC : 0));
341 if (mmap(base+this_min, this_max-this_min, prot, MAP_PRIVATE|MAP_FIXED, fd, off_start) == MAP_FAILED)
343 if (ph->p_memsz > ph->p_filesz) {
344 size_t brk = (size_t)base+ph->p_vaddr+ph->p_filesz;
345 size_t pgbrk = brk+PAGE_SIZE-1 & -PAGE_SIZE;
346 memset((void *)brk, 0, pgbrk-brk & PAGE_SIZE-1);
347 if (pgbrk-(size_t)base < this_max && mmap((void *)pgbrk, (size_t)base+this_max-pgbrk, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED)
351 for (i=0; ((size_t *)(base+dyn))[i]; i+=2)
352 if (((size_t *)(base+dyn))[i]==DT_TEXTREL) {
353 if (mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC) < 0)
357 if (!runtime) reclaim_gaps(base, (void *)((char *)buf + eh->e_phoff),
358 eh->e_phentsize, eh->e_phnum);
364 munmap(map, map_len);
368 static int path_open(const char *name, const char *search, char *buf, size_t buf_size)
370 const char *s=search, *z;
376 l = z ? z-s : strlen(s);
377 snprintf(buf, buf_size, "%.*s/%s", l, s, name);
378 if ((fd = open(buf, O_RDONLY))>=0) return fd;
383 static void decode_dyn(struct dso *p)
385 size_t dyn[DYN_CNT] = {0};
386 decode_vec(p->dynv, dyn, DYN_CNT);
387 p->syms = (void *)(p->base + dyn[DT_SYMTAB]);
388 p->strings = (void *)(p->base + dyn[DT_STRTAB]);
389 if (dyn[0]&(1<<DT_HASH))
390 p->hashtab = (void *)(p->base + dyn[DT_HASH]);
391 if (search_vec(p->dynv, dyn, DT_GNU_HASH))
392 p->ghashtab = (void *)(p->base + *dyn);
395 static struct dso *load_library(const char *name)
397 char buf[2*NAME_MAX+2];
398 const char *pathname;
399 unsigned char *base, *map;
400 size_t dyno, map_len;
405 /* Catch and block attempts to reload the implementation itself */
406 if (name[0]=='l' && name[1]=='i' && name[2]=='b') {
407 static const char *rp, reserved[] =
408 "c\0pthread\0rt\0m\0dl\0util\0xnet\0";
409 char *z = strchr(name, '.');
412 for (rp=reserved; *rp && memcmp(name+3, rp, l-3); rp+=strlen(rp)+1);
417 tail = libc->next ? libc->next : libc;
423 if (strchr(name, '/')) {
425 fd = open(name, O_RDONLY);
427 /* Search for the name to see if it's already loaded */
428 for (p=head->next; p; p=p->next) {
429 if (p->shortname && !strcmp(p->shortname, name)) {
434 if (strlen(name) > NAME_MAX) return 0;
436 if (r_path) fd = path_open(name, r_path, buf, sizeof buf);
437 if (fd < 0 && env_path) fd = path_open(name, env_path, buf, sizeof buf);
440 FILE *f = fopen(ETC_LDSO_PATH, "r");
442 if (getline(&sys_path, (size_t[1]){0}, f) > 0)
443 sys_path[strlen(sys_path)-1]=0;
447 if (sys_path) fd = path_open(name, sys_path, buf, sizeof buf);
448 else fd = path_open(name, "/lib:/usr/local/lib:/usr/lib", buf, sizeof buf);
452 if (fd < 0) return 0;
453 if (fstat(fd, &st) < 0) {
457 for (p=head->next; p; p=p->next) {
458 if (p->dev == st.st_dev && p->ino == st.st_ino) {
459 /* If this library was previously loaded with a
460 * pathname but a search found the same inode,
461 * setup its shortname so it can be found by name. */
462 if (!p->shortname) p->shortname = strrchr(p->name, '/')+1;
468 map = map_library(fd, &map_len, &base, &dyno);
471 p = calloc(1, sizeof *p + strlen(pathname) + 1);
473 munmap(map, map_len);
478 p->map_len = map_len;
480 p->dynv = (void *)(base + dyno);
487 strcpy(p->name, pathname);
488 /* Add a shortname only if name arg was not an explicit pathname. */
489 if (pathname != name) p->shortname = strrchr(p->name, '/')+1;
495 if (ldd_mode) dprintf(1, "\t%s => %s (%p)\n", name, pathname, base);
500 static void load_deps(struct dso *p)
503 struct dso ***deps = &p->deps, **tmp, *dep;
504 for (; p; p=p->next) {
505 for (i=0; p->dynv[i]; i+=2) {
506 if (p->dynv[i] != DT_RPATH) continue;
507 r_path = (void *)(p->strings + p->dynv[i+1]);
509 for (i=0; p->dynv[i]; i+=2) {
510 if (p->dynv[i] != DT_NEEDED) continue;
511 dep = load_library(p->strings + p->dynv[i+1]);
513 snprintf(errbuf, sizeof errbuf,
514 "Error loading shared library %s: %m (needed by %s)",
515 p->strings + p->dynv[i+1], p->name);
516 if (runtime) longjmp(rtld_fail, 1);
517 dprintf(2, "%s\n", errbuf);
522 tmp = realloc(*deps, sizeof(*tmp)*(ndeps+2));
523 if (!tmp) longjmp(rtld_fail, 1);
533 static void load_preload(char *s)
538 for ( ; *s && isspace(*s); s++);
539 for (z=s; *z && !isspace(*z); z++);
547 static void make_global(struct dso *p)
549 for (; p; p=p->next) p->global = 1;
552 static void reloc_all(struct dso *p)
554 size_t dyn[DYN_CNT] = {0};
555 for (; p; p=p->next) {
556 if (p->relocated) continue;
557 decode_vec(p->dynv, dyn, DYN_CNT);
558 #ifdef NEED_ARCH_RELOCS
559 do_arch_relocs(p, head);
561 do_relocs(p, (void *)(p->base+dyn[DT_JMPREL]), dyn[DT_PLTRELSZ],
562 2+(dyn[DT_PLTREL]==DT_RELA));
563 do_relocs(p, (void *)(p->base+dyn[DT_REL]), dyn[DT_RELSZ], 2);
564 do_relocs(p, (void *)(p->base+dyn[DT_RELA]), dyn[DT_RELASZ], 3);
569 static void free_all(struct dso *p)
579 static size_t find_dyn(Phdr *ph, size_t cnt, size_t stride)
581 for (; cnt--; ph = (void *)((char *)ph + stride))
582 if (ph->p_type == PT_DYNAMIC)
587 static void do_init_fini(struct dso *p)
589 size_t dyn[DYN_CNT] = {0};
590 for (; p; p=p->prev) {
591 if (p->constructed) return;
592 decode_vec(p->dynv, dyn, DYN_CNT);
593 if (dyn[0] & (1<<DT_FINI))
594 atexit((void (*)(void))(p->base + dyn[DT_FINI]));
595 if (dyn[0] & (1<<DT_INIT))
596 ((void (*)(void))(p->base + dyn[DT_INIT]))();
601 void _dl_debug_state(void)
605 void *__dynlink(int argc, char **argv)
607 size_t aux[AUX_CNT] = {0};
611 static struct dso builtin_dsos[3];
612 struct dso *const app = builtin_dsos+0;
613 struct dso *const lib = builtin_dsos+1;
614 struct dso *const vdso = builtin_dsos+2;
617 /* Find aux vector just past environ[] */
618 for (i=argc+1; argv[i]; i++)
619 if (!memcmp(argv[i], "LD_LIBRARY_PATH=", 16))
620 env_path = argv[i]+16;
621 else if (!memcmp(argv[i], "LD_PRELOAD=", 11))
622 env_preload = argv[i]+11;
623 auxv = (void *)(argv+i+1);
625 decode_vec(auxv, aux, AUX_CNT);
627 /* Only trust user/env if kernel says we're not suid/sgid */
628 if ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID]
629 || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]) {
634 /* If the dynamic linker was invoked as a program itself, AT_BASE
635 * will not be set. In that case, we assume the base address is
636 * the start of the page containing the PHDRs; I don't know any
637 * better approach... */
639 aux[AT_BASE] = aux[AT_PHDR] & -PAGE_SIZE;
640 aux[AT_PHDR] = aux[AT_PHENT] = aux[AT_PHNUM] = 0;
643 /* The dynamic linker load address is passed by the kernel
644 * in the AUX vector, so this is easy. */
645 lib->base = (void *)aux[AT_BASE];
646 lib->name = lib->shortname = "libc.so";
648 ehdr = (void *)lib->base;
649 lib->dynv = (void *)(lib->base + find_dyn(
650 (void *)(aux[AT_BASE]+ehdr->e_phoff),
651 ehdr->e_phnum, ehdr->e_phentsize));
655 size_t interp_off = 0;
656 /* Find load address of the main program, via AT_PHDR vs PT_PHDR. */
657 phdr = (void *)aux[AT_PHDR];
658 for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) {
659 if (phdr->p_type == PT_PHDR)
660 app->base = (void *)(aux[AT_PHDR] - phdr->p_vaddr);
661 else if (phdr->p_type == PT_INTERP)
662 interp_off = (size_t)phdr->p_vaddr;
664 if (interp_off) lib->name = (char *)app->base + interp_off;
666 app->dynv = (void *)(app->base + find_dyn(
667 (void *)aux[AT_PHDR], aux[AT_PHNUM], aux[AT_PHENT]));
670 char *ldname = argv[0];
671 size_t dyno, l = strlen(ldname);
672 if (l >= 3 && !strcmp(ldname+l-3, "ldd")) ldd_mode = 1;
673 *argv++ = (void *)-1;
674 if (argv[0] && !strcmp(argv[0], "--")) *argv++ = (void *)-1;
676 dprintf(2, "musl libc/dynamic program loader\n");
677 dprintf(2, "usage: %s pathname%s\n", ldname,
678 ldd_mode ? "" : " [args]");
681 fd = open(argv[0], O_RDONLY);
683 dprintf(2, "%s: cannot load %s: %s\n", ldname, argv[0], strerror(errno));
687 ehdr = (void *)map_library(fd, &app->map_len, &app->base, &dyno);
689 dprintf(2, "%s: %s: Not a valid dynamic program\n", ldname, argv[0]);
696 app->dynv = (void *)(app->base + dyno);
697 aux[AT_ENTRY] = ehdr->e_entry;
700 app->constructed = 1;
703 /* Attach to vdso, if provided by the kernel */
704 if (search_vec(auxv, aux, AT_SYSINFO_EHDR)) {
705 size_t vdso_base = *aux;
706 ehdr = (void *)vdso_base;
707 phdr = (void *)(vdso_base + ehdr->e_phoff);
708 for (i=ehdr->e_phnum; i; i--, phdr=(void *)((char *)phdr + ehdr->e_phentsize)) {
709 if (phdr->p_type == PT_DYNAMIC)
710 vdso->dynv = (void *)(vdso_base + phdr->p_offset);
711 if (phdr->p_type == PT_LOAD)
712 vdso->base = (void *)(vdso_base - phdr->p_vaddr + phdr->p_offset);
714 vdso->name = vdso->shortname = "linux-gate.so.1";
721 /* Initial dso chain consists only of the app. We temporarily
722 * append the dynamic linker/libc so we can relocate it, then
723 * restore the initial chain in preparation for loading third
724 * party libraries (preload/needed). */
731 /* PAST THIS POINT, ALL LIBC INTERFACES ARE FULLY USABLE. */
733 /* Donate unused parts of app and library mapping to malloc */
734 reclaim_gaps(app->base, (void *)aux[AT_PHDR], aux[AT_PHENT], aux[AT_PHNUM]);
735 ehdr = (void *)lib->base;
736 reclaim_gaps(lib->base, (void *)(lib->base+ehdr->e_phoff),
737 ehdr->e_phentsize, ehdr->e_phnum);
739 /* Load preload/needed libraries, add their symbols to the global
740 * namespace, and perform all remaining relocations. The main
741 * program must be relocated LAST since it may contain copy
742 * relocations which depend on libraries' relocations. */
743 if (env_preload) load_preload(env_preload);
746 reloc_all(app->next);
749 if (ldso_fail) _exit(127);
750 if (ldd_mode) _exit(0);
752 /* Switch to runtime mode: any further failures in the dynamic
753 * linker are a reportable failure rather than a fatal startup
754 * error. If the dynamic loader (dlopen) will not be used, free
755 * all memory used by the dynamic linker. */
758 #ifndef DYNAMIC_IS_RO
759 for (i=0; app->dynv[i]; i+=2)
760 if (app->dynv[i]==DT_DEBUG)
761 app->dynv[i+1] = (size_t)&debug;
764 debug.bp = _dl_debug_state;
766 debug.base = lib->base;
770 if (ssp_used) __init_ssp(auxv);
777 reclaim((void *)builtin_dsos, 0, sizeof builtin_dsos);
781 return (void *)aux[AT_ENTRY];
784 void *dlopen(const char *file, int mode)
786 struct dso *volatile p, *orig_tail = tail, *next;
790 if (!file) return head;
792 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
793 pthread_rwlock_wrlock(&lock);
795 if (setjmp(rtld_fail)) {
796 /* Clean up anything new that was (partially) loaded */
797 if (p->deps) for (i=0; p->deps[i]; i++)
798 if (p->deps[i]->global < 0)
799 p->deps[i]->global = 0;
800 for (p=orig_tail->next; p; p=next) {
802 munmap(p->map, p->map_len);
811 } else p = load_library(file);
814 snprintf(errbuf, sizeof errbuf,
815 "Error loading shared library %s: %m", file);
820 /* First load handling */
823 if (p->deps) for (i=0; p->deps[i]; i++)
824 if (!p->deps[i]->global)
825 p->deps[i]->global = -1;
826 if (!p->global) p->global = -1;
828 if (p->deps) for (i=0; p->deps[i]; i++)
829 if (p->deps[i]->global < 0)
830 p->deps[i]->global = 0;
831 if (p->global < 0) p->global = 0;
834 if (mode & RTLD_GLOBAL) {
835 if (p->deps) for (i=0; p->deps[i]; i++)
836 p->deps[i]->global = 1;
840 if (ssp_used) __init_ssp(auxv);
846 pthread_rwlock_unlock(&lock);
847 pthread_setcancelstate(cs, 0);
851 static void *do_dlsym(struct dso *p, const char *s, void *ra)
854 uint32_t h = 0, gh = 0;
856 if (p == RTLD_NEXT) {
857 for (p=head; p && (unsigned char *)ra-p->map>p->map_len; p=p->next);
859 void *res = find_sym(p->next, s, 0);
860 if (!res) goto failed;
863 if (p == head || p == RTLD_DEFAULT) {
864 void *res = find_sym(head, s, 0);
865 if (!res) goto failed;
870 sym = gnu_lookup(s, gh, p);
873 sym = sysv_lookup(s, h, p);
875 if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
876 return p->base + sym->st_value;
877 if (p->deps) for (i=0; p->deps[i]; i++) {
878 if (p->deps[i]->ghashtab) {
879 if (!gh) gh = gnu_hash(s);
880 sym = gnu_lookup(s, h, p->deps[i]);
882 if (!h) h = sysv_hash(s);
883 sym = sysv_lookup(s, h, p->deps[i]);
885 if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
886 return p->deps[i]->base + sym->st_value;
890 snprintf(errbuf, sizeof errbuf, "Symbol not found: %s", s);
894 void *__dlsym(void *p, const char *s, void *ra)
897 pthread_rwlock_rdlock(&lock);
898 res = do_dlsym(p, s, ra);
899 pthread_rwlock_unlock(&lock);
903 void *dlopen(const char *file, int mode)
907 void *__dlsym(void *p, const char *s, void *ra)
915 if (!errflag) return 0;