X-Git-Url: http://nsz.repo.hu/git/?p=musl;a=blobdiff_plain;f=src%2Fldso%2Fdynlink.c;h=305d70e010bcdcfff655351b59c92f90ea545fdb;hp=472e389d6ccc89bd16a5c774abb03f4ae5e0ca57;hb=92ab5d8d156545ab0daff6062d7a519861684fb6;hpb=49388f3b7b72a1695bef05f64439b602b2e77a53 diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 472e389d..305d70e0 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include #include "reloc.h" @@ -44,11 +47,17 @@ struct dso ino_t ino; int global; int relocated; - char name[]; + struct dso **deps; + char *name; + char buf[]; }; static struct dso *head, *tail, *libc; static char *env_path, *sys_path; +static int rtld_used; +static int runtime; +static jmp_buf rtld_fail; +static pthread_rwlock_t lock; #define AUX_CNT 15 #define DYN_CNT 34 @@ -87,8 +96,12 @@ static Sym *lookup(const char *s, uint32_t h, Sym *syms, uint32_t *hashtab, char static void *find_sym(struct dso *dso, const char *s, int need_def) { uint32_t h = hash(s); + if (h==0x6b366be && !strcmp(s, "dlopen")) rtld_used = 1; + if (h==0x6b3afd && !strcmp(s, "dlsym")) rtld_used = 1; for (; dso; dso=dso->next) { - Sym *sym = lookup(s, h, dso->syms, dso->hashtab, dso->strings); + Sym *sym; + if (!dso->global) continue; + sym = lookup(s, h, dso->syms, dso->hashtab, dso->strings); if (sym && (!need_def || sym->st_shndx) && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) return dso->base + sym->st_value; @@ -114,7 +127,12 @@ static void do_relocs(unsigned char *base, size_t *rel, size_t rel_size, size_t sym = syms + sym_index; name = strings + sym->st_name; ctx = IS_COPY(type) ? dso->next : dso; - sym_val = (size_t)find_sym(ctx, name, 1); + sym_val = (size_t)find_sym(ctx, name, IS_PLT(type)); + if (!sym_val && sym->st_info>>4 != STB_WEAK) { + if (runtime) longjmp(rtld_fail, 1); + dprintf(2, "%s: symbol not found\n", name); + _exit(127); + } sym_size = sym->st_size; } do_single_reloc(reloc_addr, type, sym_val, sym_size, base, rel[2]); @@ -255,10 +273,10 @@ static struct dso *load_library(const char *name) return p; } } - if (name[0] == '/') { + if (strchr(name, '/')) { fd = open(name, O_RDONLY); } else { - if (strlen(name) > NAME_MAX || strchr(name, '/')) return 0; + if (strlen(name) > NAME_MAX) return 0; fd = -1; if (env_path) fd = path_open(name, env_path); if (fd < 0) { @@ -306,8 +324,8 @@ static struct dso *load_library(const char *name) p->strings = (void *)(base + dyn[DT_STRTAB]); p->dev = st.st_dev; p->ino = st.st_ino; - p->global = 1; p->refcnt = 1; + p->name = p->buf; strcpy(p->name, name); tail->next = p; @@ -319,15 +337,34 @@ static struct dso *load_library(const char *name) static void load_deps(struct dso *p) { - size_t i; + size_t i, ndeps=0; + struct dso ***deps = &p->deps, **tmp, *dep; for (; p; p=p->next) { for (i=0; p->dynv[i]; i+=2) { if (p->dynv[i] != DT_NEEDED) continue; - load_library(p->strings + p->dynv[i+1]); + dep = load_library(p->strings + p->dynv[i+1]); + if (!dep) { + if (runtime) longjmp(rtld_fail, 1); + dprintf(2, "%s: %m (needed by %s)\n", + p->strings + p->dynv[i+1], p->name); + _exit(127); + } + if (runtime) { + tmp = realloc(*deps, sizeof(*tmp)*(ndeps+2)); + if (!tmp) longjmp(rtld_fail, 1); + tmp[ndeps++] = dep; + tmp[ndeps] = 0; + *deps = tmp; + } } } } +static void make_global(struct dso *p) +{ + for (; p; p=p->next) p->global = 1; +} + static void reloc_all(struct dso *p) { size_t dyn[DYN_CNT] = {0}; @@ -335,11 +372,11 @@ static void reloc_all(struct dso *p) if (p->relocated) continue; decode_vec(p->dynv, dyn, DYN_CNT); do_relocs(p->base, (void *)(p->base+dyn[DT_JMPREL]), dyn[DT_PLTRELSZ], - 2+(dyn[DT_PLTREL]==DT_RELA), p->syms, p->strings, p); + 2+(dyn[DT_PLTREL]==DT_RELA), p->syms, p->strings, head); do_relocs(p->base, (void *)(p->base+dyn[DT_REL]), dyn[DT_RELSZ], - 2, p->syms, p->strings, p); + 2, p->syms, p->strings, head); do_relocs(p->base, (void *)(p->base+dyn[DT_RELA]), dyn[DT_RELASZ], - 3, p->syms, p->strings, p); + 3, p->syms, p->strings, head); p->relocated = 1; } } @@ -395,6 +432,8 @@ void *__dynlink(int argc, char **argv, size_t *got) .hashtab = (void *)(app_dyn[DT_HASH]), .syms = (void *)(app_dyn[DT_SYMTAB]), .dynv = (void *)(phdr->p_vaddr), + .name = argv[0], + .global = 1, .next = &lib }; @@ -404,6 +443,8 @@ void *__dynlink(int argc, char **argv, size_t *got) .hashtab = (void *)(aux[AT_BASE]+lib_dyn[DT_HASH]), .syms = (void *)(aux[AT_BASE]+lib_dyn[DT_SYMTAB]), .dynv = (void *)(got[0]), + .name = "libc.so", + .global = 1, .relocated = 1 }; @@ -420,11 +461,115 @@ void *__dynlink(int argc, char **argv, size_t *got) app.next = 0; load_deps(head); + make_global(head); reloc_all(head); - free_all(head); - free(sys_path); + if (rtld_used) { + runtime = 1; + head->next->prev = malloc(sizeof *head); + *head->next->prev = *head; + head = head->next->prev; + libc->prev->next = malloc(sizeof *libc); + *libc->prev->next = *libc; + libc = libc->prev->next; + if (libc->next) libc->next->prev = libc; + } else { + free_all(head); + free(sys_path); + } errno = 0; return (void *)aux[AT_ENTRY]; } + +void *dlopen(const char *file, int mode) +{ + struct dso *p, *orig_tail = tail, *next; + size_t i; + + if (!file) return head; + + pthread_rwlock_wrlock(&lock); + + if (setjmp(rtld_fail)) { + /* Clean up anything new that was (partially) loaded */ + if (p->deps) for (i=0; p->deps[i]; i++) + if (p->deps[i]->global < 0) + p->deps[i]->global = 0; + for (p=orig_tail->next; p; p=next) { + next = p->next; + munmap(p->map, p->map_len); + free(p->deps); + free(p); + } + tail = orig_tail; + tail->next = 0; + pthread_rwlock_unlock(&lock); + return 0; + } + + p = load_library(file); + if (!p) return 0; + + /* First load handling */ + if (!p->deps) { + load_deps(p); + for (i=0; p->deps[i]; i++) + if (!p->deps[i]->global) + p->deps[i]->global = -1; + if (!p->global) p->global = -1; + reloc_all(p); + for (i=0; p->deps[i]; i++) + if (p->deps[i]->global < 0) + p->deps[i]->global = 0; + if (p->global < 0) p->global = 0; + } + + if (mode & RTLD_GLOBAL) { + for (i=0; p->deps[i]; i++) + p->deps[i]->global = 1; + p->global = 1; + } + + pthread_rwlock_unlock(&lock); + + return p; +} + +static void *do_dlsym(struct dso *p, const char *s) +{ + size_t i; + uint32_t h; + Sym *sym; + if (p == head) return find_sym(head, s, 0); + h = hash(s); + sym = lookup(s, h, p->syms, p->hashtab, p->strings); + if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) + return p->base + sym->st_value; + if (p->deps) for (i=0; p->deps[i]; i++) { + sym = lookup(s, h, p->deps[i]->syms, + p->deps[i]->hashtab, p->deps[i]->strings); + if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) + return p->deps[i]->base + sym->st_value; + } + return 0; +} + +void *dlsym(void *p, const char *s) +{ + void *res; + pthread_rwlock_rdlock(&lock); + res = do_dlsym(p, s); + pthread_rwlock_unlock(&lock); + return res; +} + +char *dlerror() +{ + return "unknown error"; +} + +int dlclose(void *p) +{ + return 0; +}