fix stderr locking and ferror semantics in getopt message printing
[musl] / src / ldso / dynlink.c
index 66bca50..00af886 100644 (file)
@@ -233,6 +233,10 @@ static Sym *gnu_lookup(const char *s, uint32_t h1, struct dso *dso)
 #define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON | 1<<STT_TLS)
 #define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK | 1<<STB_GNU_UNIQUE)
 
+#ifndef ARCH_SYM_REJECT_UND
+#define ARCH_SYM_REJECT_UND(s) 0
+#endif
+
 static struct symdef find_sym(struct dso *dso, const char *s, int need_def)
 {
        uint32_t h = 0, gh = 0;
@@ -249,7 +253,8 @@ static struct symdef find_sym(struct dso *dso, const char *s, int need_def)
                }
                if (!sym) continue;
                if (!sym->st_shndx)
-                       if (need_def || (sym->st_info&0xf) == STT_TLS)
+                       if (need_def || (sym->st_info&0xf) == STT_TLS
+                           || ARCH_SYM_REJECT_UND(sym))
                                continue;
                if (!sym->st_value)
                        if ((sym->st_info&0xf) != STT_TLS)
@@ -290,8 +295,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
                if (!astype) continue;
                type = remap_rel(astype);
                if (!type) {
-                       error(errbuf, sizeof errbuf,
-                               "Error relocating %s: unsupported relocation type %d",
+                       error("Error relocating %s: unsupported relocation type %d",
                                dso->name, astype);
                        continue;
                }
@@ -304,8 +308,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
                        def = find_sym(ctx, name, type==REL_PLT);
                        if (!def.sym && (sym->st_shndx != SHN_UNDEF
                            || sym->st_info>>4 != STB_WEAK)) {
-                               error(errbuf, sizeof errbuf,
-                                       "Error relocating %s: %s: symbol not found",
+                               error("Error relocating %s: %s: symbol not found",
                                        dso->name, name);
                                continue;
                        }
@@ -366,7 +369,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
                        if (stride<3) addend = reloc_addr[1];
                        if (runtime && def.dso->tls_id >= static_tls_cnt) {
                                struct td_index *new = malloc(sizeof *new);
-                               if (!new) error(errbuf, sizeof errbuf,
+                               if (!new) error(
                                        "Error relocating %s: cannot allocate TLSDESC for %s",
                                        dso->name, sym ? name : "(local)" );
                                new->next = dso->td_index;
@@ -642,6 +645,8 @@ static void decode_dyn(struct dso *p)
                p->hashtab = (void *)(p->base + dyn[DT_HASH]);
        if (dyn[0]&(1<<DT_RPATH))
                p->rpath_orig = (void *)(p->strings + dyn[DT_RPATH]);
+       if (dyn[0]&(1<<DT_RUNPATH))
+               p->rpath_orig = (void *)(p->strings + dyn[DT_RUNPATH]);
        if (search_vec(p->dynv, dyn, DT_GNU_HASH))
                p->ghashtab = (void *)(p->base + *dyn);
        if (search_vec(p->dynv, dyn, DT_VERSYM))
@@ -660,6 +665,11 @@ static struct dso *load_library(const char *name, struct dso *needed_by)
        int n_th = 0;
        int is_self = 0;
 
+       if (!*name) {
+               errno = EINVAL;
+               return 0;
+       }
+
        /* Catch and block attempts to reload the implementation itself */
        if (name[0]=='l' && name[1]=='i' && name[2]=='b') {
                static const char *rp, reserved[] =
@@ -839,8 +849,7 @@ static void load_deps(struct dso *p)
                        if (p->dynv[i] != DT_NEEDED) continue;
                        dep = load_library(p->strings + p->dynv[i+1], p);
                        if (!dep) {
-                               error(errbuf, sizeof errbuf,
-                                       "Error loading shared library %s: %m (needed by %s)",
+                               error("Error loading shared library %s: %m (needed by %s)",
                                        p->strings + p->dynv[i+1], p->name);
                                continue;
                        }
@@ -860,8 +869,8 @@ static void load_preload(char *s)
        int tmp;
        char *z;
        for (z=s; *z; s=z) {
-               for (   ; *s && isspace(*s); s++);
-               for (z=s; *z && !isspace(*z); z++);
+               for (   ; *s && (isspace(*s) || *s==':'); s++);
+               for (z=s; *z && !isspace(*z) && *z!=':'; z++);
                tmp = *z;
                *z = 0;
                load_library(s, 0);
@@ -890,8 +899,7 @@ static void reloc_all(struct dso *p)
 
                if (p->relro_start != p->relro_end &&
                    mprotect(p->base+p->relro_start, p->relro_end-p->relro_start, PROT_READ) < 0) {
-                       error(errbuf, sizeof errbuf,
-                               "Error relocating %s: RELRO protection failed: %m",
+                       error("Error relocating %s: RELRO protection failed: %m",
                                p->name);
                }
 
@@ -1031,17 +1039,15 @@ void *__copy_tls(unsigned char *mem)
        return td;
 }
 
-void *__tls_get_addr(size_t *v)
+void *__tls_get_new(size_t *v)
 {
        pthread_t self = __pthread_self();
-       if (v[0]<=(size_t)self->dtv[0] && self->dtv[v[0]])
-               return (char *)self->dtv[v[0]]+v[1];
 
        /* Block signals to make accessing new TLS async-signal-safe */
        sigset_t set;
-       pthread_sigmask(SIG_BLOCK, SIGALL_SET, &set);
-       if (v[0]<=(size_t)self->dtv[0] && self->dtv[v[0]]) {
-               pthread_sigmask(SIG_SETMASK, &set, 0);
+       __block_all_sigs(&set);
+       if (v[0]<=(size_t)self->dtv[0]) {
+               __restore_sigs(&set);
                return (char *)self->dtv[v[0]]+v[1];
        }
 
@@ -1062,13 +1068,19 @@ void *__tls_get_addr(size_t *v)
                self->dtv = newdtv;
        }
 
-       /* Get new TLS memory from new DSO */
-       unsigned char *mem = p->new_tls +
-               (p->tls_size + p->tls_align) * a_fetch_add(&p->new_tls_idx,1);
-       mem += ((uintptr_t)p->tls_image - (uintptr_t)mem) & (p->tls_align-1);
-       self->dtv[v[0]] = mem;
-       memcpy(mem, p->tls_image, p->tls_len);
-       pthread_sigmask(SIG_SETMASK, &set, 0);
+       /* Get new TLS memory from all new DSOs up to the requested one */
+       unsigned char *mem;
+       for (p=head; ; p=p->next) {
+               if (!p->tls_id || self->dtv[p->tls_id]) continue;
+               mem = p->new_tls + (p->tls_size + p->tls_align)
+                       * a_fetch_add(&p->new_tls_idx,1);
+               mem += ((uintptr_t)p->tls_image - (uintptr_t)mem)
+                       & (p->tls_align-1);
+               self->dtv[p->tls_id] = mem;
+               memcpy(mem, p->tls_image, p->tls_len);
+               if (p->tls_id == v[0]) break;
+       }
+       __restore_sigs(&set);
        return mem + v[1];
 }
 
@@ -1116,6 +1128,7 @@ void *__dynlink(int argc, char **argv)
                libc.secure = 1;
        }
        libc.page_size = aux[AT_PAGESZ];
+       libc.auxv = auxv;
 
        /* If the dynamic linker was invoked as a program itself, AT_BASE
         * will not be set. In that case, we assume the base address is
@@ -1436,6 +1449,8 @@ static int invalid_dso_handle(void *h)
        return 1;
 }
 
+void *__tls_get_addr(size_t *);
+
 static void *do_dlsym(struct dso *p, const char *s, void *ra)
 {
        size_t i;
@@ -1591,10 +1606,14 @@ static int invalid_dso_handle(void *h)
 }
 void *dlopen(const char *file, int mode)
 {
+       strcpy(errbuf, "Dynamic loading not supported");
+       errflag = 1;
        return 0;
 }
 void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra)
 {
+       errflag = 1;
+       snprintf(errbuf, sizeof errbuf, "Symbol not found: %s", s);
        return 0;
 }
 int __dladdr (const void *addr, Dl_info *info)