clean up internal dynamic linker functions enumerating phdrs
authorTimo Teräs <timo.teras@iki.fi>
Tue, 25 Mar 2014 18:59:50 +0000 (20:59 +0200)
committerRich Felker <dalias@aerifal.cx>
Tue, 25 Mar 2014 20:03:53 +0000 (16:03 -0400)
record phentsize in struct dso, so the phdrs can be easily
enumerated via it. simplify all functions enumerating phdrs
to require only struct dso. also merge find_map_range and
find_dso to kernel_mapped_dso function that does both tasks
during single phdr enumeration.

src/ldso/dynlink.c

index de0f2ac..2f151c2 100644 (file)
@@ -56,6 +56,7 @@ struct dso {
 
        Phdr *phdr;
        int phnum;
+       size_t phentsize;
        int refcnt;
        Sym *syms;
        uint32_t *hashtab;
@@ -298,9 +299,12 @@ static void reclaim(struct dso *dso, size_t start, size_t end)
        free(a);
 }
 
-static void reclaim_gaps(struct dso *dso, Phdr *ph, size_t phent, size_t phcnt)
+static void reclaim_gaps(struct dso *dso)
 {
-       for (; phcnt--; ph=(void *)((char *)ph+phent)) {
+       Phdr *ph;
+       size_t phcnt;
+
+       for (phcnt = dso->phnum, ph = dso->phdr; phcnt--; ph=(void *)((char *)ph+dso->phentsize)) {
                if (ph->p_type!=PT_LOAD) continue;
                if ((ph->p_flags&(PF_R|PF_W))!=(PF_R|PF_W)) continue;
                reclaim(dso, ph->p_vaddr & -PAGE_SIZE, ph->p_vaddr);
@@ -400,6 +404,7 @@ static void *map_library(int fd, struct dso *dso)
                        dso->phdr = (void *)(base + ph->p_vaddr
                                + (eh->e_phoff-ph->p_offset));
                        dso->phnum = eh->e_phnum;
+                       dso->phentsize = eh->e_phentsize;
                }
                /* Reuse the existing mapping for the lowest-address LOAD */
                if ((ph->p_vaddr & -PAGE_SIZE) == addr_min) continue;
@@ -430,7 +435,7 @@ static void *map_library(int fd, struct dso *dso)
        dso->base = base;
        dso->dynv = (void *)(base+dyn);
        if (dso->tls_size) dso->tls_image = (void *)(base+tls_image);
-       if (!runtime) reclaim_gaps(dso, ph0, eh->e_phentsize, eh->e_phnum);
+       if (!runtime) reclaim_gaps(dso);
        free(allocated_buf);
        return map;
 noexec:
@@ -787,19 +792,14 @@ static void reloc_all(struct dso *p)
        }
 }
 
-static size_t find_dyn(Phdr *ph, size_t cnt, size_t stride)
-{
-       for (; cnt--; ph = (void *)((char *)ph + stride))
-               if (ph->p_type == PT_DYNAMIC)
-                       return ph->p_vaddr;
-       return 0;
-}
-
-static void find_map_range(Phdr *ph, size_t cnt, size_t stride, struct dso *p)
+static void kernel_mapped_dso(struct dso *p)
 {
-       size_t min_addr = -1, max_addr = 0;
-       for (; cnt--; ph = (void *)((char *)ph + stride)) {
-               if (ph->p_type == PT_GNU_RELRO) {
+       size_t min_addr = -1, max_addr = 0, cnt;
+       Phdr *ph = p->phdr;
+       for (cnt = p->phnum; cnt--; ph = (void *)((char *)ph + p->phentsize)) {
+               if (ph->p_type == PT_DYNAMIC) {
+                       p->dynv = (void *)(p->base + ph->p_vaddr);
+               } else if (ph->p_type == PT_GNU_RELRO) {
                        p->relro_start = ph->p_vaddr & -PAGE_SIZE;
                        p->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE;
                }
@@ -813,6 +813,7 @@ static void find_map_range(Phdr *ph, size_t cnt, size_t stride, struct dso *p)
        max_addr = (max_addr + PAGE_SIZE-1) & -PAGE_SIZE;
        p->map = p->base + min_addr;
        p->map_len = max_addr - min_addr;
+       p->kernel_mapped = 1;
 }
 
 static void do_fini()
@@ -1023,13 +1024,11 @@ void *__dynlink(int argc, char **argv)
        lib->base = (void *)aux[AT_BASE];
        lib->name = lib->shortname = "libc.so";
        lib->global = 1;
-       lib->kernel_mapped = 1;
        ehdr = (void *)lib->base;
        lib->phnum = ehdr->e_phnum;
        lib->phdr = (void *)(aux[AT_BASE]+ehdr->e_phoff);
-       find_map_range(lib->phdr, ehdr->e_phnum, ehdr->e_phentsize, lib);
-       lib->dynv = (void *)(lib->base + find_dyn(lib->phdr,
-               ehdr->e_phnum, ehdr->e_phentsize));
+       lib->phentsize = ehdr->e_phentsize;
+       kernel_mapped_dso(lib);
        decode_dyn(lib);
 
        if (aux[AT_PHDR]) {
@@ -1038,6 +1037,7 @@ void *__dynlink(int argc, char **argv)
                /* Find load address of the main program, via AT_PHDR vs PT_PHDR. */
                app->phdr = phdr = (void *)aux[AT_PHDR];
                app->phnum = aux[AT_PHNUM];
+               app->phentsize = aux[AT_PHENT];
                for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) {
                        if (phdr->p_type == PT_PHDR)
                                app->base = (void *)(aux[AT_PHDR] - phdr->p_vaddr);
@@ -1057,11 +1057,7 @@ void *__dynlink(int argc, char **argv)
                        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]));
-               find_map_range((void *)aux[AT_PHDR],
-                       aux[AT_PHNUM], aux[AT_PHENT], app);
+               kernel_mapped_dso(app);
        } else {
                int fd;
                char *ldname = argv[0];
@@ -1127,6 +1123,7 @@ void *__dynlink(int argc, char **argv)
                ehdr = (void *)vdso_base;
                vdso->phdr = phdr = (void *)(vdso_base + ehdr->e_phoff);
                vdso->phnum = ehdr->e_phnum;
+               vdso->phentsize = ehdr->e_phentsize;
                for (i=ehdr->e_phnum; i; i--, phdr=(void *)((char *)phdr + ehdr->e_phentsize)) {
                        if (phdr->p_type == PT_DYNAMIC)
                                vdso->dynv = (void *)(vdso_base + phdr->p_offset);
@@ -1154,10 +1151,8 @@ void *__dynlink(int argc, char **argv)
        /* PAST THIS POINT, ALL LIBC INTERFACES ARE FULLY USABLE. */
 
        /* Donate unused parts of app and library mapping to malloc */
-       reclaim_gaps(app, (void *)aux[AT_PHDR], aux[AT_PHENT], aux[AT_PHNUM]);
-       ehdr = (void *)lib->base;
-       reclaim_gaps(lib, (void *)(lib->base+ehdr->e_phoff),
-               ehdr->e_phentsize, ehdr->e_phnum);
+       reclaim_gaps(app);
+       reclaim_gaps(lib);
 
        /* Load preload/needed libraries, add their symbols to the global
         * namespace, and perform all remaining relocations. The main