support STB_GNU_UNIQUE symbol bindings in dynamic linker
[musl] / src / ldso / dynlink.c
index 829696f..f4c32ff 100644 (file)
@@ -91,6 +91,7 @@ struct symdef {
 
 void __init_ssp(size_t *);
 void *__install_initial_tls(void *);
+void __init_libc(char **, char *);
 
 static struct dso *head, *tail, *ldso, *fini_head;
 static char *env_path, *sys_path, *r_path;
@@ -100,7 +101,7 @@ static int runtime;
 static int ldd_mode;
 static int ldso_fail;
 static int noload;
-static jmp_buf rtld_fail;
+static jmp_buf *rtld_fail;
 static pthread_rwlock_t lock;
 static struct debug debug;
 static size_t tls_cnt, tls_offset, tls_align = 4*sizeof(size_t);
@@ -189,7 +190,7 @@ 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)
+#define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK | 1<<STB_GNU_UNIQUE)
 
 static struct symdef find_sym(struct dso *dso, const char *s, int need_def)
 {
@@ -254,7 +255,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
                                snprintf(errbuf, sizeof errbuf,
                                        "Error relocating %s: %s: symbol not found",
                                        dso->name, name);
-                               if (runtime) longjmp(rtld_fail, 1);
+                               if (runtime) longjmp(*rtld_fail, 1);
                                dprintf(2, "%s\n", errbuf);
                                ldso_fail = 1;
                                continue;
@@ -612,14 +613,14 @@ static void load_deps(struct dso *p)
                                snprintf(errbuf, sizeof errbuf,
                                        "Error loading shared library %s: %m (needed by %s)",
                                        p->strings + p->dynv[i+1], p->name);
-                               if (runtime) longjmp(rtld_fail, 1);
+                               if (runtime) longjmp(*rtld_fail, 1);
                                dprintf(2, "%s\n", errbuf);
                                ldso_fail = 1;
                                continue;
                        }
                        if (runtime) {
                                tmp = realloc(*deps, sizeof(*tmp)*(ndeps+2));
-                               if (!tmp) longjmp(rtld_fail, 1);
+                               if (!tmp) longjmp(*rtld_fail, 1);
                                tmp[ndeps++] = dep;
                                tmp[ndeps] = 0;
                                *deps = tmp;
@@ -701,8 +702,10 @@ static void do_fini()
                        size_t *fn = (size_t *)(p->base + dyn[DT_FINI_ARRAY])+n;
                        while (n--) ((void (*)(void))*--fn)();
                }
+#ifndef NO_LEGACY_INITFINI
                if (dyn[0] & (1<<DT_FINI))
                        ((void (*)(void))(p->base + dyn[DT_FINI]))();
+#endif
        }
 }
 
@@ -722,8 +725,10 @@ static void do_init_fini(struct dso *p)
                        p->fini_next = fini_head;
                        fini_head = p;
                }
+#ifndef NO_LEGACY_INITFINI
                if (dyn[0] & (1<<DT_INIT))
                        ((void (*)(void))(p->base + dyn[DT_INIT]))();
+#endif
                if (dyn[0] & (1<<DT_INIT_ARRAY)) {
                        size_t n = dyn[DT_INIT_ARRAYSZ]/sizeof(size_t);
                        size_t *fn = (void *)(p->base + dyn[DT_INIT_ARRAY]);
@@ -841,6 +846,7 @@ void *__dynlink(int argc, char **argv)
        char *env_preload=0;
        size_t vdso_base;
        size_t *auxv;
+       char **envp = argv+argc+1;
 
        /* Find aux vector just past environ[] */
        for (i=argc+1; argv[i]; i++)
@@ -953,7 +959,6 @@ void *__dynlink(int argc, char **argv)
                tls_align = MAXP2(tls_align, app->tls_align);
        }
        app->global = 1;
-       app->constructed = 1;
        decode_dyn(app);
 
        /* Attach to vdso, if provided by the kernel */
@@ -1038,15 +1043,12 @@ void *__dynlink(int argc, char **argv)
        _dl_debug_state();
 
        if (ssp_used) __init_ssp((void *)aux[AT_RANDOM]);
-
-       errno = 0;
-       return (void *)aux[AT_ENTRY];
-}
-
-void __init_ldso_ctors(void)
-{
+       __init_libc(envp, argv[0]);
        atexit(do_fini);
+       errno = 0;
        do_init_fini(tail);
+
+       return (void *)aux[AT_ENTRY];
 }
 
 void *dlopen(const char *file, int mode)
@@ -1055,6 +1057,7 @@ void *dlopen(const char *file, int mode)
        size_t orig_tls_cnt, orig_tls_offset, orig_tls_align;
        size_t i;
        int cs;
+       jmp_buf jb;
 
        if (!file) return head;
 
@@ -1069,7 +1072,8 @@ void *dlopen(const char *file, int mode)
        orig_tail = tail;
        noload = mode & RTLD_NOLOAD;
 
-       if (setjmp(rtld_fail)) {
+       rtld_fail = &jb;
+       if (setjmp(*rtld_fail)) {
                /* Clean up anything new that was (partially) loaded */
                if (p && p->deps) for (i=0; p->deps[i]; i++)
                        if (p->deps[i]->global < 0)