diff options
Diffstat (limited to 'gnu/usr.bin')
-rw-r--r-- | gnu/usr.bin/ld/rtld/rtld.c | 173 |
1 files changed, 170 insertions, 3 deletions
diff --git a/gnu/usr.bin/ld/rtld/rtld.c b/gnu/usr.bin/ld/rtld/rtld.c index 3f6f7aa..02e6dcc 100644 --- a/gnu/usr.bin/ld/rtld/rtld.c +++ b/gnu/usr.bin/ld/rtld/rtld.c @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: rtld.c,v 1.28 1995/10/21 14:52:48 ache Exp $ + * $Id: rtld.c,v 1.29 1995/10/24 06:48:16 ache Exp $ */ #include <sys/param.h> @@ -93,6 +93,30 @@ struct somap_private { #endif }; +/* + * Memorizing structure for reducing the number of calls to lookup() + * during relocation. + * + * While relocating a given shared object, the dynamic linker maintains + * a memorizing vector that is directly indexed by the symbol number + * in the relocation entry. The first time a given symbol is looked + * up, the memorizing vector is filled in with a pointer to the symbol + * table entry, and a pointer to the so_map of the shared object in + * which the symbol was defined. On subsequent uses of the same + * symbol, that information is retrieved directly from the memorizing + * vector, without calling lookup() again. + * + * A symbol that is referenced in a relocation entry is typically + * referenced in many relocation entries, so this memorizing reduces + * the number of calls to lookup() dramatically. The overall improvement + * in the speed of dynamic linking is also dramatic -- as much as a + * factor of three for programs that use many shared libaries. + */ +struct memoent { + struct nzlist *np; /* Pointer to symbol entry */ + struct so_map *src_map; /* Shared object that defined the symbol */ +}; + #define LM_PRIVATE(smp) ((struct somap_private *)(smp)->som_spd) #ifdef SUN_COMPAT @@ -156,6 +180,9 @@ struct so_map *link_map_head, *main_map; struct so_map **link_map_tail = &link_map_head; struct rt_symbol *rt_symbol_head; +static struct memoent *symmemo; /* Nemorizing vector for symbols */ +static long symmemosyms; /* Number of symbols in memo vector */ + static void *__dlopen __P((char *, int)); static int __dlclose __P((void *)); static void *__dlsym __P((void *, char *)); @@ -191,6 +218,8 @@ static struct nzlist *lookup __P((char *, struct so_map **, int)); static inline struct rt_symbol *lookup_rts __P((char *)); static struct rt_symbol *enter_rts __P((char *, long, int, caddr_t, long, struct so_map *)); +static void *getMemory __P((size_t)); +static void freeMemory __P((void *, size_t)); static void generror __P((char *, ...)); static void maphints __P((void)); static void unmaphints __P((void)); @@ -279,6 +308,38 @@ struct _dynamic *dp; crtp->crt_dp->d_entry = &ld_entry; crtp->crt_dp->d_un.d_sdt->sdt_loaded = link_map_head->som_next; + /* + * Determine the maximum number of run-time symbols in any of + * the shared objects. + */ + symmemosyms = 0; + + for (smp = link_map_head; smp; smp = smp->som_next) { + struct _dynamic *dp; + size_t symsize; + long numsyms; + + if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) + continue; + + dp = smp->som_dynamic; + symsize = LD_VERSION_NZLIST_P(dp->d_version) ? + sizeof(struct nzlist) : sizeof(struct nlist); + numsyms = (LD_STRINGS(dp) - LD_SYMBOL(dp)) / symsize; + if(symmemosyms < numsyms) + symmemosyms = numsyms; + } + + /* + * Allocate a memorizing vector large enough to hold the maximum + * number of run-time symbols. We use mmap to get the memory, so + * that we can give it back to the system when we are finished + * with it. + */ + symmemo = getMemory(symmemosyms * sizeof(struct memoent)); + if(symmemo == NULL) /* Couldn't get the memory */ + symmemosyms = 0; + /* Relocate all loaded objects according to their RRS segments */ for (smp = link_map_head; smp; smp = smp->som_next) { if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) @@ -287,6 +348,12 @@ struct _dynamic *dp; return -1; } + if(symmemosyms != 0) { /* Free the memorizing vector */ + freeMemory(symmemo, symmemosyms * sizeof(struct memoent)); + symmemo = NULL; + symmemosyms = 0; + } + /* Copy any relocated initialized data. */ for (smp = link_map_head; smp; smp = smp->som_next) { if (LM_PRIVATE(smp)->spd_flags & RTLD_RTLD) @@ -328,6 +395,7 @@ struct _dynamic *dp; /* Close our file descriptor */ (void)close(crtp->crt_ldfd); anon_close(); + return LDSO_VERSION_HAS_DLEXIT; } @@ -704,6 +772,26 @@ reloc_map(smp) sizeof(struct nzlist) : sizeof(struct nlist); + if(symmemosyms != 0) { + /* + * We have allocated space for a memorizing vector large + * enough to hold "symmemosyms" symbols. Currently, the + * code is written in such a way that the vector will + * always be large enough, if it is present at all. But + * this routine will still handle the case where there + * is a memorizing vector, but it is smaller than what + * is needed for the current shared object. + */ + long numsyms; + size_t symmemobytes; + + numsyms = (LD_STRINGS(dp) - LD_SYMBOL(dp)) / symsize; + if(numsyms > symmemosyms) /* Currently, this won't happen */ + numsyms = symmemosyms; + symmemobytes = numsyms * sizeof(struct memoent); + bzero(symmemo, symmemobytes); + } + if (LD_PLTSZ(dp)) md_fix_jmpslot(LM_PLT(smp), (long)LM_PLT(smp), (long)binder_entry); @@ -718,7 +806,7 @@ reloc_map(smp) if (RELOC_EXTERN_P(r)) { struct so_map *src_map = NULL; struct nzlist *p, *np; - long relocation = md_get_addend(r, addr); + long relocation; if (RELOC_LAZY_P(r)) continue; @@ -731,7 +819,28 @@ reloc_map(smp) sym = stringbase + p->nz_strx; - np = lookup(sym, &src_map, 0/*XXX-jumpslots!*/); + if(RELOC_SYMBOL(r) < symmemosyms) { + /* Check the memorizing vector */ + np = symmemo[RELOC_SYMBOL(r)].np; + if(np != NULL) { /* We found it */ + src_map = + symmemo[RELOC_SYMBOL(r)].src_map; + } else { /* Symbol not memorized yet */ + np = lookup(sym, &src_map, + 0/*XXX-jumpslots!*/); + /* + * Record the needed information about + * the symbol in the memorizing vector, + * so that we won't have to call + * lookup the next time we encounter + * the symbol. + */ + symmemo[RELOC_SYMBOL(r)].np = np; + symmemo[RELOC_SYMBOL(r)].src_map = + src_map; + } + } else + np = lookup(sym, &src_map, 0/*XXX-jumpslots!*/); if (np == NULL) { generror ("Undefined symbol \"%s\" in %s:%s", sym, main_progname, smp->som_path); @@ -744,6 +853,7 @@ reloc_map(smp) * Otherwise it's a run-time allocated common * whose value is already up-to-date. */ + relocation = md_get_addend(r, addr); relocation += np->nz_value; if (src_map) relocation += (long)src_map->som_addr; @@ -1181,6 +1291,63 @@ restart: return rtsp->rt_sp; } +/* + * getMemory and freeMemory are special memory allocation routines + * that use mmap rather than malloc. They are used for allocating + * and freeing the symbol memorizing vector. This vector is somewhat + * large (8 to 12 Kbytes, typically), and it is used only temporarily. + * By using mmap to allocate it, we can then use munmap to free it. + * That reduces the runtime size of every dynamically linked program. + * + * Don't use getMemory and freeMemory casually for frequent allocations + * or for small allocations. + */ + +static size_t pagesize; /* Avoids multiple calls to getpagesize() */ + +/* + * Allocate a block of memory using mmap. + */ + static void * +getMemory(size_t size) +{ + caddr_t ptr; + + if(size == 0) /* That was easy */ + return NULL; + if(pagesize == 0) /* First call */ + pagesize = getpagesize(); + + /* Round up the request to an even multiple of the page size */ + size = (size + pagesize - 1) & ~(pagesize - 1); + + ptr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_COPY, + anon_fd, 0); + if(ptr == (caddr_t) -1) { + xprintf("Cannot map anonymous memory"); + return NULL; + } + + return (void *) ptr; +} + +/* + * Free a block of memory, using munmap to return the memory to the system. + */ + static void +freeMemory(void *ptr, size_t size) +{ + if(ptr == NULL || size == 0) + return; + if(pagesize == 0) /* Really, should never happen */ + pagesize = getpagesize(); + + /* Round up the size to an even multiple of the page size */ + size = (size + pagesize - 1) & ~(pagesize - 1); + + if(munmap((caddr_t) ptr, size) == -1) + xprintf("Cannot unmap anonymous memory"); +} /* * This routine is called from the jumptable to resolve |