fix fesetenv(FE_DFL_ENV) on x86_64 (see previous commit)
[musl] / src / ldso / dynlink.c
index 6f23fa5..a1bdf0f 100644 (file)
@@ -7,12 +7,9 @@
 #include <elf.h>
 #include <sys/mman.h>
 #include <limits.h>
-#include <stdint.h>
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <errno.h>
-#include <limits.h>
-#include <elf.h>
 #include <link.h>
 #include <setjmp.h>
 #include <pthread.h>
@@ -96,6 +93,8 @@ void __init_ssp(size_t *);
 void *__install_initial_tls(void *);
 void __init_libc(char **, char *);
 
+const char *__libc_get_version(void);
+
 static struct dso *head, *tail, *ldso, *fini_head;
 static char *env_path, *sys_path;
 static unsigned long long gencnt;
@@ -254,7 +253,8 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri
                        name = strings + sym->st_name;
                        ctx = IS_COPY(type) ? head->next : head;
                        def = find_sym(ctx, name, IS_PLT(type));
-                       if (!def.sym && sym->st_info>>4 != STB_WEAK) {
+                       if (!def.sym && (sym->st_shndx != SHN_UNDEF
+                           || sym->st_info>>4 != STB_WEAK)) {
                                snprintf(errbuf, sizeof errbuf,
                                        "Error relocating %s: %s: symbol not found",
                                        dso->name, name);
@@ -462,7 +462,9 @@ static int fixup_rpath(struct dso *p, char *buf, size_t buf_size)
        }
        n = 0;
        s = p->rpath_orig;
-       while ((t=strstr(s, "$ORIGIN")) || (t=strstr(s, "${ORIGIN}"))) {
+       while ((t=strchr(s, '$'))) {
+               if (strncmp(t, "$ORIGIN", 7) && strncmp(t, "${ORIGIN}", 9))
+                       return -1;
                s = t+1;
                n++;
        }
@@ -477,8 +479,10 @@ static int fixup_rpath(struct dso *p, char *buf, size_t buf_size)
                 * (either system paths or a call to dlopen). */
                if (libc.secure)
                        return -1;
-               if (readlink("/proc/self/exe", buf, buf_size) >= buf_size)
+               l = readlink("/proc/self/exe", buf, buf_size);
+               if (l >= buf_size)
                        return -1;
+               buf[l] = 0;
                origin = buf;
        } else {
                origin = p->name;
@@ -490,11 +494,13 @@ static int fixup_rpath(struct dso *p, char *buf, size_t buf_size)
 
        d = p->rpath;
        s = p->rpath_orig;
-       while ((t=strstr(s, "$ORIGIN")) || (t=strstr(s, "${ORIGIN}"))) {
+       while ((t=strchr(s, '$'))) {
                memcpy(d, s, t-s);
                d += t-s;
                memcpy(d, origin, l);
                d += l;
+               /* It was determined previously that the '$' is followed
+                * either by "ORIGIN" or "{ORIGIN}". */
                s = t + 7 + 2*(t[1]=='{');
        }
        strcpy(d, s);
@@ -608,6 +614,8 @@ static struct dso *load_library(const char *name, struct dso *needed_by)
                                                sys_path = "";
                                        }
                                        fclose(f);
+                               } else if (errno != ENOENT) {
+                                       sys_path = "";
                                }
                        }
                        if (!sys_path) sys_path = "/lib:/usr/local/lib:/usr/lib";
@@ -972,6 +980,7 @@ void *__dynlink(int argc, char **argv)
                env_preload = 0;
                libc.secure = 1;
        }
+       libc.page_size = aux[AT_PAGESZ];
 
        /* 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
@@ -1016,7 +1025,11 @@ void *__dynlink(int argc, char **argv)
                }
                if (app->tls_size) app->tls_image = (char *)app->base + tls_image;
                if (interp_off) lib->name = (char *)app->base + interp_off;
-               app->name = argv[0];
+               if ((aux[0] & (1UL<<AT_EXECFN))
+                   && strncmp((char *)aux[AT_EXECFN], "/proc/", 6))
+                       app->name = (char *)aux[AT_EXECFN];
+               else
+                       app->name = argv[0];
                app->kernel_mapped = 1;
                app->dynv = (void *)(app->base + find_dyn(
                        (void *)aux[AT_PHDR], aux[AT_PHNUM], aux[AT_PHENT]));
@@ -1030,8 +1043,11 @@ void *__dynlink(int argc, char **argv)
                *argv++ = (void *)-1;
                if (argv[0] && !strcmp(argv[0], "--")) *argv++ = (void *)-1;
                if (!argv[0]) {
-                       dprintf(2, "musl libc/dynamic program loader\n");
-                       dprintf(2, "usage: %s pathname%s\n", ldname,
+                       dprintf(2, "musl libc\n"
+                               "Version %s\n"
+                               "Dynamic Program Loader\n"
+                               "Usage: %s [--] pathname%s\n",
+                               __libc_get_version(), ldname,
                                ldd_mode ? "" : " [args]");
                        _exit(1);
                }
@@ -1210,7 +1226,7 @@ void *dlopen(const char *file, int mode)
                p = 0;
                errflag = 1;
                goto end;
-       } else p = load_library(file, 0);
+       } else p = load_library(file, head);
 
        if (!p) {
                snprintf(errbuf, sizeof errbuf, noload ?
@@ -1316,7 +1332,7 @@ failed:
        return 0;
 }
 
-int __dladdr(void *addr, Dl_info *info)
+int __dladdr(const void *addr, Dl_info *info)
 {
        struct dso *p;
        Sym *sym;
@@ -1341,7 +1357,7 @@ int __dladdr(void *addr, Dl_info *info)
                uint32_t *hashval;
                buckets = p->ghashtab + 4 + (p->ghashtab[2]*sizeof(size_t)/4);
                sym += p->ghashtab[1];
-               for (i = 0; i < p->ghashtab[0]; i++) {
+               for (i = nsym = 0; i < p->ghashtab[0]; i++) {
                        if (buckets[i] > nsym)
                                nsym = buckets[i];
                }
@@ -1426,7 +1442,7 @@ void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra)
 {
        return 0;
 }
-int __dladdr (void *addr, Dl_info *info)
+int __dladdr (const void *addr, Dl_info *info)
 {
        return 0;
 }