X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fldso%2Fdynlink.c;h=a171df977196c708c65819d5de885112d2f98644;hb=649cec5f9868070b4d350b861ee7f68b03a552a8;hp=49ea5e9cb2d0d36620e042a03e62c4cd50ce130a;hpb=f7d15dcc543c3b65c751064a5e51a0ec462f3cdb;p=musl diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 49ea5e9c..a171df97 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -20,7 +20,7 @@ static int errflag; static char errbuf[128]; -#ifdef __PIC__ +#ifdef SHARED #include "reloc.h" @@ -60,7 +60,7 @@ struct dso { size_t map_len; dev_t dev; ino_t ino; - char global; + signed char global; char relocated; char constructed; struct dso **deps; @@ -322,6 +322,7 @@ static void decode_dyn(struct dso *p) static struct dso *load_library(const char *name) { char buf[2*NAME_MAX+2]; + const char *pathname; unsigned char *base, *map; size_t dyno, map_len; struct dso *p; @@ -346,16 +347,17 @@ static struct dso *load_library(const char *name) } } } - /* Search for the name to see if it's already loaded */ - for (p=head->next; p; p=p->next) { - if (!strcmp(p->shortname, name)) { - p->refcnt++; - return p; - } - } if (strchr(name, '/')) { + pathname = name; fd = open(name, O_RDONLY); } else { + /* Search for the name to see if it's already loaded */ + for (p=head->next; p; p=p->next) { + if (p->shortname && !strcmp(p->shortname, name)) { + p->refcnt++; + return p; + } + } if (strlen(name) > NAME_MAX) return 0; fd = -1; if (r_path) fd = path_open(name, r_path, buf, sizeof buf); @@ -372,6 +374,7 @@ static struct dso *load_library(const char *name) if (sys_path) fd = path_open(name, sys_path, buf, sizeof buf); else fd = path_open(name, "/lib:/usr/local/lib:/usr/lib", buf, sizeof buf); } + pathname = buf; } if (fd < 0) return 0; if (fstat(fd, &st) < 0) { @@ -380,6 +383,10 @@ static struct dso *load_library(const char *name) } for (p=head->next; p; p=p->next) { if (p->dev == st.st_dev && p->ino == st.st_ino) { + /* If this library was previously loaded with a + * pathname but a search found the same inode, + * setup its shortname so it can be found by name. */ + if (!p->shortname) p->shortname = strrchr(p->name, '/')+1; close(fd); p->refcnt++; return p; @@ -388,7 +395,7 @@ static struct dso *load_library(const char *name) map = map_library(fd, &map_len, &base, &dyno); close(fd); if (!map) return 0; - p = calloc(1, sizeof *p + strlen(buf) + 1); + p = calloc(1, sizeof *p + strlen(pathname) + 1); if (!p) { munmap(map, map_len); return 0; @@ -404,15 +411,15 @@ static struct dso *load_library(const char *name) p->ino = st.st_ino; p->refcnt = 1; p->name = p->buf; - strcpy(p->name, buf); - if (!strchr(name, '/')) p->shortname = strrchr(p->name, '/'); - if (!p->shortname) p->shortname = p->name; + strcpy(p->name, pathname); + /* Add a shortname only if name arg was not an explicit pathname. */ + if (pathname != name) p->shortname = strrchr(p->name, '/')+1; tail->next = p; p->prev = tail; tail = p; - if (ldd_mode) dprintf(1, "\t%s => %s (%p)\n", name, buf, base); + if (ldd_mode) dprintf(1, "\t%s => %s (%p)\n", name, pathname, base); return p; } @@ -570,13 +577,17 @@ void *__dynlink(int argc, char **argv) decode_dyn(lib); if (aux[AT_PHDR]) { + size_t interp_off = 0; /* Find load address of the main program, via AT_PHDR vs PT_PHDR. */ phdr = (void *)aux[AT_PHDR]; for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) { if (phdr->p_type == PT_PHDR) app->base = (void *)(aux[AT_PHDR] - phdr->p_vaddr); + else if (phdr->p_type == PT_INTERP) + interp_off = (size_t)phdr->p_vaddr; } - app->name = app->shortname = argv[0]; + if (interp_off) lib->name = (char *)app->base + interp_off; + app->name = argv[0]; app->dynv = (void *)(app->base + find_dyn( (void *)aux[AT_PHDR], aux[AT_PHNUM], aux[AT_PHENT])); } else { @@ -605,7 +616,8 @@ void *__dynlink(int argc, char **argv) } runtime = 0; close(fd); - app->name = app->shortname = argv[0]; + lib->name = ldname; + app->name = argv[0]; app->dynv = (void *)(app->base + dyno); aux[AT_ENTRY] = ehdr->e_entry; } @@ -766,7 +778,9 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra) if (p == RTLD_NEXT) { for (p=head; p && (unsigned char *)ra-p->map>p->map_len; p=p->next); if (!p) p=head; - p=p->next; + void *res = find_sym(p->next, s, 0); + if (!res) goto failed; + return res; } if (p == head || p == RTLD_DEFAULT) { void *res = find_sym(head, s, 0);