X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=inline;f=ldso%2Fdynlink.c;h=178fe27eb2f657b4c9b92f4bb9002f90621622d6;hb=cb525397bb053ea49cf160965477a17b17286eb3;hp=0bd9d50ce36031ba836d7a1fb7cb168289957e00;hpb=4823b13a75b40c4408c1101b363ab00fd118fb27;p=musl diff --git a/ldso/dynlink.c b/ldso/dynlink.c index 0bd9d50c..178fe27e 100644 --- a/ldso/dynlink.c +++ b/ldso/dynlink.c @@ -52,13 +52,13 @@ struct dso { Phdr *phdr; int phnum; size_t phentsize; - int refcnt; Sym *syms; Elf_Symndx *hashtab; uint32_t *ghashtab; int16_t *versym; char *strings; - struct dso *syms_next; + struct dso *syms_next, *lazy_next; + size_t *lazy, lazy_cnt; unsigned char *map; size_t map_len; dev_t dev; @@ -113,7 +113,7 @@ static struct builtin_tls { static size_t *saved_addends, *apply_addends_to; static struct dso ldso; -static struct dso *head, *tail, *fini_head, *syms_tail; +static struct dso *head, *tail, *fini_head, *syms_tail, *lazy_head; static char *env_path, *sys_path; static unsigned long long gencnt; static int runtime; @@ -350,6 +350,13 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri : find_sym(ctx, name, type==REL_PLT); if (!def.sym && (sym->st_shndx != SHN_UNDEF || sym->st_info>>4 != STB_WEAK)) { + if (dso->lazy && (type==REL_PLT || type==REL_GOT)) { + dso->lazy[3*dso->lazy_cnt+0] = rel[0]; + dso->lazy[3*dso->lazy_cnt+1] = rel[1]; + dso->lazy[3*dso->lazy_cnt+2] = addend; + dso->lazy_cnt++; + continue; + } error("Error relocating %s: %s: symbol not found", dso->name, name); if (runtime) longjmp(*rtld_fail, 1); @@ -451,6 +458,26 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri } } +static void redo_lazy_relocs() +{ + struct dso *p = lazy_head, *next; + lazy_head = 0; + for (; p; p=next) { + next = p->lazy_next; + size_t size = p->lazy_cnt*3*sizeof(size_t); + p->lazy_cnt = 0; + do_relocs(p, p->lazy, size, 3); + if (p->lazy_cnt) { + p->lazy_next = lazy_head; + lazy_head = p; + } else { + free(p->lazy); + p->lazy = 0; + p->lazy_next = 0; + } + } +} + /* A huge hack: to make up for the wastefulness of shared libraries * needing at least a page of dirty memory even if they have no global * data, we reclaim the gaps at the beginning and end of writable maps @@ -943,7 +970,6 @@ static struct dso *load_library(const char *name, struct dso *needed_by) /* 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; } } @@ -1006,7 +1032,6 @@ static struct dso *load_library(const char *name, struct dso *needed_by) if (!p->shortname && pathname != name) p->shortname = strrchr(p->name, '/')+1; close(fd); - p->refcnt++; return p; } } @@ -1014,6 +1039,17 @@ static struct dso *load_library(const char *name, struct dso *needed_by) close(fd); if (!map) return 0; + /* Avoid the danger of getting two versions of libc mapped into the + * same process when an absolute pathname was used. The symbols + * checked are chosen to catch both musl and glibc, and to avoid + * false positives from interposition-hack libraries. */ + decode_dyn(&temp_dso); + if (find_sym(&temp_dso, "__libc_start_main", 1).sym && + find_sym(&temp_dso, "stdin", 1).sym) { + unmap_library(&temp_dso); + return load_library("libc.so", needed_by); + } + /* Allocate storage for the new DSO. When there is TLS, this * storage must include a reservation for all pre-existing * threads to obtain copies of both the new TLS, and an @@ -1033,10 +1069,8 @@ static struct dso *load_library(const char *name, struct dso *needed_by) return 0; } memcpy(p, &temp_dso, sizeof temp_dso); - decode_dyn(p); p->dev = st.st_dev; p->ino = st.st_ino; - p->refcnt = 1; p->needed_by = needed_by; p->name = p->buf; strcpy(p->name, pathname); @@ -1653,9 +1687,31 @@ _Noreturn void __dls3(size_t *sp) for(;;); } +static void prepare_lazy(struct dso *p) +{ + size_t dyn[DYN_CNT], n, flags1=0; + decode_vec(p->dynv, dyn, DYN_CNT); + search_vec(p->dynv, &flags1, DT_FLAGS_1); + if (dyn[DT_BIND_NOW] || (dyn[DT_FLAGS] & DF_BIND_NOW) || (flags1 & DF_1_NOW)) + return; + n = dyn[DT_RELSZ]/2 + dyn[DT_RELASZ]/3 + dyn[DT_PLTRELSZ]/2 + 1; + if (NEED_MIPS_GOT_RELOCS) { + size_t j=0; search_vec(p->dynv, &j, DT_MIPS_GOTSYM); + size_t i=0; search_vec(p->dynv, &i, DT_MIPS_SYMTABNO); + n += i-j; + } + p->lazy = calloc(n, 3*sizeof(size_t)); + if (!p->lazy) { + error("Error preparing lazy relocation for %s: %m", p->name); + longjmp(*rtld_fail, 1); + } + p->lazy_next = lazy_head; + lazy_head = p; +} + void *dlopen(const char *file, int mode) { - struct dso *volatile p, *orig_tail, *orig_syms_tail, *next; + struct dso *volatile p, *orig_tail, *orig_syms_tail, *orig_lazy_head, *next; struct tls_module *orig_tls_tail; size_t orig_tls_cnt, orig_tls_offset, orig_tls_align; size_t i; @@ -1673,6 +1729,7 @@ void *dlopen(const char *file, int mode) orig_tls_cnt = tls_cnt; orig_tls_offset = tls_offset; orig_tls_align = tls_align; + orig_lazy_head = lazy_head; orig_syms_tail = syms_tail; orig_tail = tail; noload = mode & RTLD_NOLOAD; @@ -1701,6 +1758,7 @@ void *dlopen(const char *file, int mode) tls_cnt = orig_tls_cnt; tls_offset = orig_tls_offset; tls_align = orig_tls_align; + lazy_head = orig_lazy_head; tail = orig_tail; tail->next = 0; p = 0; @@ -1718,6 +1776,12 @@ void *dlopen(const char *file, int mode) /* First load handling */ if (!p->relocated) { load_deps(p); + if ((mode & RTLD_LAZY)) { + prepare_lazy(p); + if (p->deps) for (i=0; p->deps[i]; i++) + if (!p->deps[i]->relocated) + prepare_lazy(p->deps[i]); + } /* Make new symbols global, at least temporarily, so we can do * relocations. If not RTLD_GLOBAL, this is reverted below. */ add_syms(p); @@ -1732,6 +1796,11 @@ void *dlopen(const char *file, int mode) if (!(mode & RTLD_GLOBAL)) revert_syms(orig_syms_tail); + /* Processing of deferred lazy relocations must not happen until + * the new libraries are committed; otherwise we could end up with + * relocations resolved to symbol definitions that get removed. */ + redo_lazy_relocs(); + update_tls_size(); _dl_debug_state(); orig_tail = tail;