diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2006-05-12 15:12:43 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2006-05-12 15:12:43 +0000 |
commit | e5679510c68791a09c529315e7b7a7f68cf5ade9 (patch) | |
tree | 3e911ef42ceb21ef8f31a9bcecff1aa0814fba18 /libexec/ld.so | |
parent | 3fac9ac1ce0040147a49708033a5ab74aa65fd08 (diff) |
Major code rewrite, now uses about 1/6th of the memory it used before.
produces logically the same output (just a few fields reordered).
Diffstat (limited to 'libexec/ld.so')
-rw-r--r-- | libexec/ld.so/prebind/objarray.c | 1285 | ||||
-rw-r--r-- | libexec/ld.so/prebind/prebind.c | 1961 | ||||
-rw-r--r-- | libexec/ld.so/prebind/prebind_struct.h | 9 |
3 files changed, 1803 insertions, 1452 deletions
diff --git a/libexec/ld.so/prebind/objarray.c b/libexec/ld.so/prebind/objarray.c index cf772a48ccc..5aed79d7cf4 100644 --- a/libexec/ld.so/prebind/objarray.c +++ b/libexec/ld.so/prebind/objarray.c @@ -1,4 +1,4 @@ -/* $OpenBSD: objarray.c,v 1.7 2006/05/10 23:03:53 drahn Exp $ */ +/* $OpenBSD: objarray.c,v 1.8 2006/05/12 15:12:42 drahn Exp $ */ /* * Copyright (c) 2006 Dale Rahn <drahn@dalerahn.com> * @@ -20,7 +20,6 @@ #include <sys/syslimits.h> #include <sys/param.h> #include <sys/mman.h> -#include <errno.h> #include <fcntl.h> #include <nlist.h> #include <elf_abi.h> @@ -29,1069 +28,315 @@ #include <stdlib.h> #include <unistd.h> #include <dirent.h> -#include "resolve.h" #include "link.h" #include "sod.h" -#include "machine/reloc.h" +#include "resolve.h" #include "prebind.h" #include "prebind_struct.h" -struct objarray_list { - struct elf_object *obj; - struct symcache_noflag *symcache; - struct symcache_noflag *pltsymcache; - u_int32_t id0; - u_int32_t id1; - u_int32_t *idxtolib; - void *oprebind_data; - int numlibs; - - TAILQ_HEAD(, objlist) inst_list; -} *objarray; - -int objarray_cnt; -int objarray_sz; - -int write_txtbusy_file(char *name); -void copy_oldsymcache(int objidx); -void elf_load_existing_prebind(struct elf_object *object, int fd); - -void -elf_add_object_curbin_list(struct elf_object *object) -{ - struct objlist *ol; - ol = xmalloc(sizeof (struct objlist)); - ol->object = object; - TAILQ_INSERT_TAIL(&(curbin->curbin_list), ol, list); - if ( load_object == NULL) - load_object = object; - ol->load_prog = load_object; - -#if 0 - printf("adding object %s %d with prog %s\n", object->load_name, - object->dyn.null, load_object->load_name); -#endif - TAILQ_INSERT_TAIL(&(objarray[object->dyn.null].inst_list), ol, inst_list); -} -void -elf_init_objarray(void) -{ - objarray_sz = 512; - objarray = xmalloc(sizeof (objarray[0]) * objarray_sz); -} - -void -elf_sum_reloc() -{ - int i, numobjs; - int err = 0; - struct objlist *ol; - struct proglist *pl; +/* TODO - library path from ldconfig */ +#define DEFAULT_PATH "/usr/lib:/usr/X11R6/lib:/usr/local/qte/lib" - for (i = 0; i < objarray_cnt; i++) { -#if 0 - printf("%3d: %d obj %s\n", i, objarray[i].obj->dyn.null, - objarray[i].obj->load_name); -#endif - if (TAILQ_EMPTY(&objarray[i].inst_list)) { - printf("skipping %s\n", objarray[i].obj->load_name); - continue; - } - if (objarray[i].oprebind_data != NULL) { - copy_oldsymcache(i); - continue; - } - objarray[i].symcache = xcalloc(sizeof(struct symcache_noflag), - objarray[i].obj->nchains); - objarray[i].pltsymcache = xcalloc(sizeof( - struct symcache_noflag), objarray[i].obj->nchains); - - TAILQ_FOREACH(ol, &(objarray[i].inst_list), - inst_list) { - -#if 0 - printf("\tprog %d %s\n", ol->load_prog->dyn.null, - ol->load_prog->load_name); - printf("cache: %p %p %s\n", - objarray[i].symcache, ol->cache, - ol->object->load_name ); -#endif - - elf_copy_syms(objarray[i].symcache, - ol->cache, - ol->object, - ol->load_prog, - ol->object->nchains); - - elf_copy_syms(objarray[i].pltsymcache, - ol->pltcache, - ol->object, - ol->load_prog, - ol->object->nchains); - } - } - TAILQ_FOREACH(ol, &library_list, list) { -#if 0 - printf("processing lib %s\n", ol->object->load_name); -#endif - err += elf_prep_lib_prebind(ol->object); - } - TAILQ_FOREACH(pl, &prog_list, list) { - numobjs = 0; - TAILQ_FOREACH(ol, &(pl->curbin_list), list) { - numobjs++; - } - pl->nobj = numobjs; - pl->libmap = xcalloc(numobjs, sizeof (u_int32_t *)); - pl->fixup = xcalloc(2 * numobjs, sizeof (struct fixup *)); - pl->fixupcnt = xcalloc(2 * numobjs, sizeof (int)); - - numobjs = 0; - TAILQ_FOREACH(ol, &(pl->curbin_list), list) { - elf_calc_fixups(pl, ol, numobjs); - numobjs++; - } - } - TAILQ_FOREACH(pl, &prog_list, list) { - err += elf_prep_bin_prebind(pl); -#if 0 - printf("processing binary %s\n", - TAILQ_FIRST(&pl->curbin_list)->object->load_name); -#endif - } - if (err != 0) - printf("failures %d\n", err); -} - -int -elf_prep_lib_prebind(struct elf_object *object) -{ - int numlibs = 0; - int ret = 0; - int i; - int ref_obj; - int *libmap; - int *idxtolib; - struct nameidx *nameidx; - char *nametab; - int nametablen; - struct symcache_noflag *symcache; - struct symcache_noflag *pltsymcache; - struct symcachetab *symcachetab; - int symcache_cnt = 0; - struct symcachetab *pltsymcachetab; - int pltsymcache_cnt = 0; - - symcache = objarray[object->dyn.null].symcache; - pltsymcache = objarray[object->dyn.null].pltsymcache; - libmap = xcalloc(objarray_cnt, sizeof (int)); - idxtolib = xcalloc(objarray_cnt, sizeof (int)); - objarray[object->dyn.null].idxtolib = idxtolib; - - for (i = 0; i < objarray_cnt; i++) - libmap[i] = -1; - - nametablen = 0; - for (i = 0; i < object->nchains; i++) { - if (symcache[i].sym == NULL) - continue; - ref_obj = symcache[i].obj->dyn.null; - symcache_cnt++; - if (libmap[ref_obj] != -1) - continue; - libmap[ref_obj] = numlibs; - idxtolib[numlibs] = ref_obj; - nametablen += strlen(symcache[i].obj->load_name) + 1; - numlibs++; - } - symcachetab = xcalloc(symcache_cnt , sizeof(struct symcachetab)); - - symcache_cnt = 0; - for (i = 0; i < object->nchains; i++) { - if (symcache[i].sym == NULL) - continue; - symcachetab[symcache_cnt].idx = i; - symcachetab[symcache_cnt].obj_idx = - libmap[symcache[i].obj->dyn.null]; - symcachetab[symcache_cnt].sym_idx = - symcache[i].sym - symcache[i].obj->dyn.symtab; - symcache_cnt++; - } - for (i = 0; i < object->nchains; i++) { - if (pltsymcache[i].sym == NULL) - continue; - ref_obj = pltsymcache[i].obj->dyn.null; - pltsymcache_cnt++; - if (libmap[ref_obj] != -1) - continue; - libmap[ref_obj] = numlibs; - idxtolib[numlibs] = ref_obj; - nametablen += strlen(pltsymcache[i].obj->load_name) + 1; - numlibs++; - } - pltsymcachetab = xcalloc(pltsymcache_cnt , sizeof(struct symcachetab)); - - pltsymcache_cnt = 0; - for (i = 0; i < object->nchains; i++) { - if (pltsymcache[i].sym == NULL) - continue; - pltsymcachetab[pltsymcache_cnt].idx = i; - pltsymcachetab[pltsymcache_cnt].obj_idx = - libmap[pltsymcache[i].obj->dyn.null]; - pltsymcachetab[pltsymcache_cnt].sym_idx = - pltsymcache[i].sym - pltsymcache[i].obj->dyn.symtab; - pltsymcache_cnt++; - } - - objarray[object->dyn.null].numlibs = numlibs; - - nameidx = xcalloc(numlibs, sizeof (struct nameidx)); - nametab = xmalloc(nametablen); - - nametablen = 0; - for (i = 0; i < numlibs; i++) { - nameidx[i].name = nametablen; - nameidx[i].id0 = objarray[idxtolib[i]].id0; - nameidx[i].id1 = objarray[idxtolib[i]].id1; - nametablen += strlen(objarray[idxtolib[i]].obj->load_name) + 1; - strlcpy (&nametab[nameidx[i].name], - objarray[idxtolib[i]].obj->load_name, - nametablen - nameidx[i].name); - } -#if 0 - for (i = 0; i < numlibs; i++) { - printf("\tlib %s\n", &nametab[nameidx[i].name]); - } -#endif - - /* skip writing lib if using old prebind data */ - if (objarray[object->dyn.null].oprebind_data == NULL) - ret = elf_write_lib(object, nameidx, nametab, nametablen, - numlibs, 0, NULL, NULL, NULL, NULL, symcachetab, - symcache_cnt, pltsymcachetab, pltsymcache_cnt); - - free (nameidx); - free (nametab); - free (libmap); - free(pltsymcachetab); - free(symcachetab); - - return ret; -} +elf_object_t * elf_load_shlib_hint(struct sod *sod, struct sod *req_sod, + int ignore_hints, const char *libpath); +char * elf_find_shlib(struct sod *sodp, const char *searchpath, int nohints); +elf_object_t * elf_tryload_shlib(const char *libname); +int elf_match_file(struct sod *sodp, char *name, int namelen); int -elf_prep_bin_prebind(struct proglist *pl) +load_lib(const char *name, struct elf_object *parent) { - int ret; - int numlibs = 0; - int i, j; - int ref_obj; - int *libmap; - int *idxtolib; - struct nameidx *nameidx; - char *nametab; - int nametablen; - struct symcache_noflag *symcache; - struct symcache_noflag *pltsymcache; - struct symcachetab *symcachetab; - int symcache_cnt; - struct symcachetab *pltsymcachetab; - int pltsymcache_cnt; - struct elf_object *object; - struct objlist *ol; - - object = TAILQ_FIRST(&(pl->curbin_list))->object; - symcache = objarray[object->dyn.null].symcache; - pltsymcache = objarray[object->dyn.null].pltsymcache; - libmap = xcalloc(objarray_cnt, sizeof (int)); - idxtolib = xcalloc(pl->nobj, sizeof (int)); - - for (i = 0; i < objarray_cnt; i++) - libmap[i] = -1; - - for (i = 0; i < pl->nobj; i++) - idxtolib[i] = -1; - - nametablen = 0; - TAILQ_FOREACH(ol, &(pl->curbin_list), list) { - ref_obj = ol->object->dyn.null; - nametablen += strlen(ol->object->load_name) + 1; - libmap[ref_obj] = numlibs; - idxtolib[numlibs] = ref_obj; -#if 1 - printf("obj :%d, idx %d %s\n", numlibs, ref_obj, ol->object->load_name); -#endif - numlibs++; - } - - /* do got */ - symcache_cnt = 0; - for (i = 0; i < object->nchains; i++) { - if (symcache[i].sym != NULL) - symcache_cnt++; - } - - symcachetab = xcalloc(symcache_cnt , sizeof(struct symcachetab)); - - symcache_cnt = 0; - for (i = 0; i < object->nchains; i++) { - if (symcache[i].sym == NULL) - continue; - symcachetab[symcache_cnt].idx = i; - symcachetab[symcache_cnt].obj_idx = - libmap[symcache[i].obj->dyn.null]; - symcachetab[symcache_cnt].sym_idx = - symcache[i].sym - symcache[i].obj->dyn.symtab; - symcache_cnt++; - } - - /* now do plt */ - pltsymcache_cnt = 0; - for (i = 0; i < object->nchains; i++) { - if (pltsymcache[i].sym != NULL) - pltsymcache_cnt++; - } - pltsymcachetab = xcalloc(pltsymcache_cnt , sizeof(struct symcachetab)); - - pltsymcache_cnt = 0; - for (i = 0; i < object->nchains; i++) { - if (pltsymcache[i].sym == NULL) - continue; - pltsymcachetab[pltsymcache_cnt].idx = i; - pltsymcachetab[pltsymcache_cnt].obj_idx = - libmap[pltsymcache[i].obj->dyn.null]; - pltsymcachetab[pltsymcache_cnt].sym_idx = - pltsymcache[i].sym - pltsymcache[i].obj->dyn.symtab; - pltsymcache_cnt++; - } + struct sod sod, req_sod; + int ignore_hints; + int try_any_minor = 0; + struct elf_object *object = NULL; - objarray[object->dyn.null].numlibs = numlibs; - - nameidx = xcalloc(numlibs, sizeof (struct nameidx)); - nametab = xmalloc(nametablen); - - nametablen = 0; - for (i = 0; i < numlibs; i++) { - nameidx[i].name = nametablen; - nameidx[i].id0 = objarray[idxtolib[i]].id0; - nameidx[i].id1 = objarray[idxtolib[i]].id1; - nametablen += strlen(objarray[idxtolib[i]].obj->load_name) + 1; - - strlcpy (&nametab[nameidx[i].name], - objarray[idxtolib[i]].obj->load_name, - nametablen - nameidx[i].name); - } #if 0 - for (i = 0; i < numlibs; i++) { - printf("\tlib %s\n", &nametab[nameidx[i].name]); - } + printf("load_lib %s\n", name); #endif - pl->libmapcnt = xcalloc(numlibs, sizeof(u_int32_t)); - - /* have to do both got and plt fixups */ - for (i = 0; i < numlibs; i++) { - for (j = 0; j < pl->fixupcnt[2*i]; j++) { - pl->fixup[2*i][j].targobj_idx = - libmap[pl->fixup[2*i][j].targobj_idx]; + ignore_hints = 0; + + if(strchr(name, '/')) { + char *lpath, *lname; + lpath = strdup(name); + lname = strrchr(lpath, '/'); + if (lname == NULL || lname[1] == '\0') { + free(lpath); + return (1); /* failed */ } - for (j = 0; j < pl->fixupcnt[2*i+1]; j++) { - pl->fixup[2*i+1][j].targobj_idx = - libmap[pl->fixup[2*i+1][j].targobj_idx]; + *lname = '\0'; + lname++; + + _dl_build_sod(lname, &sod); + req_sod = sod; + + /* this code does not allow lower minors */ +fullpathagain: + object = elf_load_shlib_hint(&sod, &req_sod, + ignore_hints, lpath); + if (object != NULL) + goto fullpathdone; + + if (try_any_minor == 0) { + try_any_minor = 1; + ignore_hints = 1; + req_sod.sod_minor = -1; + goto fullpathagain; } + /* ERR */ +fullpathdone: + free(lpath); + free((char *)sod.sod_name); + return (object == NULL); /* failed */ + } + _dl_build_sod(name, &sod); + req_sod = sod; + + /* ignore LD_LIBRARY_PATH */ + +again: + if (parent->dyn.rpath != NULL) { + object = elf_load_shlib_hint(&sod, &req_sod, + ignore_hints, parent->dyn.rpath); + if (object != NULL) + goto done; + } + if (parent != load_object && load_object->dyn.rpath != NULL) { + object = elf_load_shlib_hint(&sod, &req_sod, + ignore_hints, load_object->dyn.rpath); + if (object != NULL) + goto done; + } + object = elf_load_shlib_hint(&sod, &req_sod, + ignore_hints, NULL); + + if (try_any_minor == 0) { + try_any_minor = 1; + ignore_hints = 1; + req_sod.sod_minor = -1; + goto again; + } + if (object == NULL) + printf ("unable to load %s\n", name); - pl->libmapcnt[i] = objarray[idxtolib[i]].numlibs; - if (i != 0) - for (j = 0; j < objarray[idxtolib[i]].numlibs; j++) - pl->libmap[i][j] = libmap[pl->libmap[i][j]]; - } - - ret = elf_write_lib(object, nameidx, nametab, nametablen, numlibs, - numlibs, pl->fixup, pl->fixupcnt, - pl->libmap, pl->libmapcnt, - symcachetab, symcache_cnt, - pltsymcachetab, pltsymcache_cnt); - - free(symcachetab); - free(pltsymcachetab); - free(idxtolib); - free(nameidx); - free(nametab); - free(libmap); +done: + free((char *)sod.sod_name); - return ret; + return (object == NULL); } -int64_t prebind_blocks; -int -elf_write_lib(struct elf_object *object, struct nameidx *nameidx, - char *nametab, int nametablen, int numlibs, - int nfixup, struct fixup **fixup, int *fixupcnt, - u_int32_t **libmap, int *libmapcnt, - struct symcachetab *symcachetab, int symcache_cnt, - struct symcachetab *pltsymcachetab, int pltsymcache_cnt) -{ - off_t base_offset; - struct prebind_footer footer; - struct stat ifstat; - int fd; - u_int32_t next_start; - u_int32_t *fixuptab = NULL; - u_int32_t *maptab = NULL; - u_int32_t footer_offset; - int i; - size_t len; - - /* open the file */ - fd = open(object->load_name, O_RDWR); - if (fd == -1) { - if (errno == ETXTBSY) - fd = write_txtbusy_file(object->load_name); - if (fd == -1) { - perror(object->load_name); - return 1; - } - } - lseek(fd, -((off_t)sizeof(struct prebind_footer)), SEEK_END); - len = read(fd, &footer, sizeof(struct prebind_footer)); - - if (footer.bind_id[0] == BIND_ID0 && - footer.bind_id[1] == BIND_ID1 && - footer.bind_id[2] == BIND_ID2 && - footer.bind_id[3] == BIND_ID3) { - - ftruncate(fd, footer.orig_size); - elf_clear_prog_load(fd, object); - } - - if (fstat(fd, &ifstat) == -1) { - perror(object->load_name); - exit(10); - } - bzero(&footer, sizeof(struct prebind_footer)); - - base_offset = ifstat.st_size; - prebind_blocks -= ifstat.st_blocks; /* subtract old size */ - - /* verify dev/inode - do we care about last modified? */ - - /* pieces to store on lib - * - * offset to footer - * nameidx - numlibs * sizeof nameidx - * symcache - symcache_cnt * sizeof (symcache_idx) - * pltsymcache - pltsymcache_cnt * sizeof (symcache_idx) - * fixup(N/A for lib) - nfixup * sizeof (symcache_idx) - * nametab - nametablen - * footer (not aligned) - */ - - footer.orig_size = base_offset; - base_offset = ELF_ROUND(base_offset, sizeof(u_int64_t)); - footer.prebind_base = base_offset; - footer.nameidx_idx = sizeof(u_int32_t); - footer.symcache_idx = footer.nameidx_idx + - numlibs * sizeof (struct nameidx); - footer.pltsymcache_idx = footer.symcache_idx + - symcache_cnt * sizeof (struct nameidx); - footer.symcache_cnt = symcache_cnt; - footer.pltsymcache_cnt = pltsymcache_cnt; - footer.fixup_cnt = 0; - footer.numlibs = numlibs; - next_start = footer.pltsymcache_idx + - (pltsymcache_cnt * sizeof (struct symcachetab)); - if (nfixup != 0) { - footer.fixup_cnt = nfixup; - footer.fixup_idx = next_start; - next_start += 2*nfixup * sizeof(u_int32_t); - footer.fixupcnt_idx = next_start; - next_start += 2*nfixup * sizeof(u_int32_t); - fixuptab = xcalloc( 2*nfixup, sizeof(u_int32_t)); - for ( i = 0; i < 2*nfixup; i++) { - fixuptab[i] = next_start; - next_start += fixupcnt[i] * sizeof(struct fixup); - } - footer.libmap_idx = next_start; - next_start += 2*nfixup * sizeof(u_int32_t); - maptab = xcalloc( 2*nfixup, sizeof(u_int32_t)); - maptab[0] = next_start; - for (i = 1; i < nfixup; i++) { - maptab[i] = next_start; - next_start += libmapcnt[i] * sizeof(u_int32_t); - } - - - } - footer.nametab_idx = next_start; - next_start += nametablen; - next_start = ELF_ROUND(next_start, sizeof(u_int64_t)); - footer_offset = next_start; - if (verbose > 1) { - printf("footer_offset %d\n", footer_offset); - } - footer.prebind_size = next_start + sizeof(struct prebind_footer); - - footer.prebind_version = PREBIND_VERSION; - footer.id0 = objarray[object->dyn.null].id0; - footer.id1 = objarray[object->dyn.null].id1; - footer.bind_id[0] = BIND_ID0; - footer.bind_id[1] = BIND_ID1; - footer.bind_id[2] = BIND_ID2; - footer.bind_id[3] = BIND_ID3; - - lseek(fd, footer.prebind_base, SEEK_SET); - write(fd, &footer_offset, sizeof(u_int32_t)); - - lseek(fd, footer.prebind_base+footer.nameidx_idx, SEEK_SET); - write(fd, nameidx, numlibs * sizeof (struct nameidx)); - - lseek(fd, footer.prebind_base+footer.symcache_idx, SEEK_SET); - write(fd, symcachetab, symcache_cnt * sizeof (struct symcachetab)); - - lseek(fd, footer.prebind_base+footer.pltsymcache_idx, SEEK_SET); - write(fd, pltsymcachetab, pltsymcache_cnt * - sizeof (struct symcachetab)); - - if (verbose > 3) - dump_symcachetab(symcachetab, symcache_cnt, object, 0); - if (verbose > 3) - dump_symcachetab(pltsymcachetab, pltsymcache_cnt, object, 0); - - if (nfixup != 0) { - lseek(fd, footer.prebind_base+footer.fixup_idx, SEEK_SET); - write(fd, fixuptab, 2*nfixup * sizeof(u_int32_t)); - lseek(fd, footer.prebind_base+footer.fixupcnt_idx, SEEK_SET); - write(fd, fixupcnt, 2*nfixup * sizeof(u_int32_t)); - for (i = 0; i < 2*nfixup; i++) { - lseek(fd, footer.prebind_base+fixuptab[i], - SEEK_SET); - write(fd, fixup[i], fixupcnt[i] * sizeof(struct fixup)); - } - - lseek(fd, footer.prebind_base+footer.libmap_idx, SEEK_SET); - write(fd, maptab, nfixup * sizeof(u_int32_t)); - for (i = 0; i < nfixup; i++) { - lseek(fd, footer.prebind_base+maptab[i], - SEEK_SET); - write(fd, libmap[i], libmapcnt[i] * sizeof(u_int32_t)); - } - } - lseek(fd, footer.prebind_base+footer.nametab_idx, SEEK_SET); - write(fd, nametab, nametablen); - lseek(fd, footer.prebind_base+footer_offset, SEEK_SET); - write(fd, &footer, sizeof (struct prebind_footer)); - - if (fstat(fd, &ifstat) == -1) { - perror(object->load_name); - exit(10); - } - prebind_blocks += ifstat.st_blocks; /* add new size */ - if (nfixup != 0) { - elf_fixup_prog_load(fd, &footer, object); - - free(fixuptab); - free(maptab); - } - - if (verbose > 0) - printf("%s: prebind info %d bytes old size %lld, growth %f\n", - object->load_name, footer.prebind_size, footer.orig_size, - (double)(footer.prebind_size) / footer.orig_size); - - if (verbose > 1) - elf_dump_footer(&footer); - - close (fd); - return 0; -} -void -elf_fixup_prog_load(int fd, struct prebind_footer *footer, - struct elf_object *object) +/* + * attempt to locate and load a library based on libpath, sod info and + * if it needs to respect hints, passing type and flags to perform open + */ +elf_object_t * +elf_load_shlib_hint(struct sod *sod, struct sod *req_sod, + int ignore_hints, const char *libpath) { - void *buf; - Elf_Ehdr *ehdr; - Elf_Phdr *phdr; - Elf_Phdr phdr_empty; - int loadsection; - - buf = mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_FILE | MAP_SHARED, - fd, 0); - if (buf == MAP_FAILED) { - printf("%s: cannot mmap for write\n", object->load_name); - return; - } - - ehdr = (Elf_Ehdr *) buf; - phdr = (Elf_Phdr *)((char *)buf + ehdr->e_phoff); - - for (loadsection = 0; loadsection < ehdr->e_phnum; loadsection++) { - if (phdr[loadsection].p_type == PT_LOAD) - break; - } - - /* verify that extra slot is empty */ - bzero(&phdr_empty, sizeof(phdr_empty)); - if (bcmp(&phdr[ehdr->e_phnum], &phdr_empty, sizeof(phdr_empty)) != 0) { - printf("extra slot not empty\n"); - goto done; - } - phdr[ehdr->e_phnum].p_type = PT_LOAD; - phdr[ehdr->e_phnum].p_flags = PF_R | 0x08000000; - phdr[ehdr->e_phnum].p_offset = footer->prebind_base; - phdr[ehdr->e_phnum].p_vaddr = footer->prebind_base | 0x80000000; - phdr[ehdr->e_phnum].p_paddr = footer->prebind_base | 0x40000000; - phdr[ehdr->e_phnum].p_filesz = footer->prebind_size; - phdr[ehdr->e_phnum].p_memsz = footer->prebind_size; - phdr[ehdr->e_phnum].p_align = phdr[loadsection].p_align; - ehdr->e_phnum++; - -done: - msync(buf, 8192, MS_SYNC); - munmap(buf, 8192); + elf_object_t *object = NULL; + char *hint; + + hint = elf_find_shlib(req_sod, libpath, ignore_hints); + if (hint != NULL) { + if (req_sod->sod_minor < sod->sod_minor) + printf("warning: lib%s.so.%d.%d: " + "minor version >= %d expected, " + "using it anyway\n", + (char *)sod->sod_name, sod->sod_major, + req_sod->sod_minor, sod->sod_minor); + object = elf_tryload_shlib(hint); + } + return object; } -void -elf_clear_prog_load(int fd, struct elf_object *object) -{ - void *buf; - Elf_Ehdr *ehdr; - Elf_Phdr *phdr; - Elf_Phdr phdr_empty; - int loadsection; - - buf = mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_FILE | MAP_SHARED, - fd, 0); - if (buf == MAP_FAILED) { - printf("%s: cannot mmap for write\n", object->load_name); - return; - } - - ehdr = (Elf_Ehdr *) buf; - phdr = (Elf_Phdr *)((char *)buf + ehdr->e_phoff); - - if (ehdr->e_type != ET_EXEC) { - goto done; - } - - loadsection = ehdr->e_phnum - 1; - if ((phdr[loadsection].p_type != PT_LOAD) || - ((phdr[loadsection].p_flags & 0x08000000) == 0)) { - /* doesn't look like ours */ - printf("mapped, %s id doesn't match %lx %d %d\n", - object->load_name, - (long)(phdr[loadsection].p_vaddr), - phdr[loadsection].p_flags, loadsection); - goto done; - } +char elf_hint_store[MAXPATHLEN]; - /* verify that extra slot is empty */ - bzero(&phdr[loadsection], sizeof(phdr_empty)); - - ehdr->e_phnum--; - -done: - msync(buf, 8192, MS_SYNC); - munmap(buf, 8192); -} -void -elf_calc_fixups(struct proglist *pl, struct objlist *ol, int libidx) +char * +elf_find_shlib(struct sod *sodp, const char *searchpath, int nohints) { - int i; - int numfixups; - int objidx; - int prog; - struct symcache_noflag *symcache; - struct elf_object *prog_obj; - struct elf_object *interp; - - objidx = ol->object->dyn.null, - - prog_obj = TAILQ_FIRST(&(pl->curbin_list))->object; - interp = prog_obj->load_object; - prog = prog_obj->dyn.null; - if (verbose > 3) - printf("fixup GOT %s\n", ol->object->load_name); - symcache = objarray[objidx].symcache; - - numfixups = 0; - for (i = 0; i < ol->object->nchains; i++) { - /* - * this assumes if the same object is found, the same - * symbol will be found as well - */ - if (ol->cache[i].obj != symcache[i].obj && - symcache[i].obj != interp) { - numfixups++; - } - } - pl->fixup[2*libidx] = xcalloc(numfixups, sizeof (struct fixup)); - - numfixups = 0; - for (i = 0; i < ol->object->nchains; i++) { - /* - * this assumes if the same object is found, the same - * symbol will be found as well - */ - if (ol->cache[i].obj != NULL && - ol->cache[i].obj != symcache[i].obj) { - struct fixup *f = &(pl->fixup[2*libidx][numfixups]); - f->sym = i; - f->targobj_idx = ol->cache[i].obj->dyn.null; - f->sym_idx = ol->cache[i].sym - - ol->cache[i].obj->dyn.symtab; - if (verbose > 3) { - printf("obj %d idx %d targobj %d, sym idx %d\n", - i, - f->sym, f->targobj_idx, f->sym_idx); - } - - numfixups++; - } - } - pl->fixupcnt[2*libidx] = numfixups; -#if 0 - printf("prog %s obj %s had %d got fixups\n", prog_obj->load_name, - ol->object->load_name, numfixups); -#endif - - if (verbose > 3) - printf("fixup PLT %s\n", ol->object->load_name); - /* now PLT */ - - symcache = objarray[objidx].pltsymcache; - - numfixups = 0; - for (i = 0; i < ol->object->nchains; i++) { - /* - * this assumes if the same object is found, the same - * symbol will be found as well - */ - if (ol->pltcache[i].obj != symcache[i].obj) { - numfixups++; - } - } - pl->fixup[2*libidx+1] = xcalloc(numfixups, sizeof (struct fixup)); - - numfixups = 0; - for (i = 0; i < ol->object->nchains; i++) { - /* - * this assumes if the same object is found, the same - * symbol will be found as well + char *hint, lp[PATH_MAX + 10], *path; + struct dirent *dp; + const char *pp; + int match, len; + DIR *dd; + struct sod tsod, bsod; /* transient and best sod */ + + /* if we are to search default directories, and hints + * are not to be used, search the standard path from ldconfig + * (_dl_hint_search_path) or use the default path + */ + if (nohints) + goto nohints; + + if (searchpath == NULL) { + /* search 'standard' locations, find any match in the hints */ + hint = _dl_findhint((char *)sodp->sod_name, sodp->sod_major, + sodp->sod_minor, NULL); + if (hint) + return hint; + } else { + /* search hints requesting matches for only + * the searchpath directories, */ - if (ol->pltcache[i].obj != symcache[i].obj) { - struct fixup *f = &(pl->fixup[2*libidx+1][numfixups]); - f->sym = i; - f->targobj_idx = ol->pltcache[i].obj->dyn.null; - f->sym_idx = ol->pltcache[i].sym - - ol->pltcache[i].obj->dyn.symtab; - if (verbose > 3) { - printf("obj %d idx %d targobj %d, sym idx %d\n", - i, - f->sym, f->targobj_idx, f->sym_idx); + pp = searchpath; + while (pp) { + path = lp; + while (path < lp + PATH_MAX && + *pp && *pp != ':' && *pp != ';') + *path++ = *pp++; + *path = 0; + + /* interpret "" as curdir "." */ + if (lp[0] == '\0') { + lp[0] = '.'; + lp[1] = '\0'; } - numfixups++; - } - } - pl->fixupcnt[2*libidx+1] = numfixups; + hint = _dl_findhint((char *)sodp->sod_name, + sodp->sod_major, sodp->sod_minor, lp); + if (hint != NULL) + return hint; - pl->libmap[libidx] = xcalloc( objarray[objidx].numlibs, - sizeof(u_int32_t)); - - for (i = 0; i < objarray[objidx].numlibs; i++) { - pl->libmap[libidx][i] = objarray[objidx].idxtolib[i]; - } -#if 0 - printf("prog %s obj %s had %d plt fixups\n", prog_obj->load_name, - ol->object->load_name, numfixups); -#endif - -} - -void -elf_add_object(struct elf_object *object, int objtype) -{ - struct objarray_list *newarray; - struct objlist *ol; - ol = xmalloc(sizeof (struct objlist)); - ol->object = object; - if (objtype != OBJTYPE_EXE) - TAILQ_INSERT_TAIL(&library_list, ol, list); - if (objarray_cnt+1 >= objarray_sz) { - objarray_sz += 512; - newarray = realloc(objarray, sizeof (objarray[0]) * - objarray_sz); - if (newarray != NULL) - objarray = newarray; - else { - perror("objarray"); - exit(20); + if (*pp) /* Try curdir if ':' at end */ + pp++; + else + pp = 0; } } - object->dyn.null = objarray_cnt; /* Major abuse, I know */ - TAILQ_INIT(&(objarray[objarray_cnt].inst_list)); - objarray[objarray_cnt].obj = object; - objarray[objarray_cnt].id0 = arc4random(); /* XXX FIX */ - objarray[objarray_cnt].id1 = arc4random(); - objarray[objarray_cnt].oprebind_data = NULL; - objarray[objarray_cnt].numlibs = 0; - objarray_cnt++; - - elf_add_object_curbin_list(object); -} - -void -elf_free_curbin_list(elf_object_t *object) -{ - struct objlist *ol; - int i; - - while (!TAILQ_EMPTY(&(curbin->curbin_list))) { - ol = TAILQ_FIRST(&(curbin->curbin_list)); - TAILQ_REMOVE(&(objarray[ol->object->dyn.null].inst_list), ol, inst_list); - TAILQ_REMOVE(&(curbin->curbin_list), ol, list); - free(ol); - } - printf("trying to remove %s\n", object->load_name); - for (i = objarray_cnt; i != 0;) { - i--; - printf("obj %s\n", objarray[i].obj->load_name); - if (objarray[i].obj == object) { - printf("found obj at %d max obj %d\n", i, objarray_cnt); - TAILQ_FOREACH(ol, &(curbin->curbin_list), list) { - } - /* XXX - delete references */ - objarray_cnt = i; - break; + /* + * For each directory in the searchpath, read the directory + * entries looking for a match to sod. filename compare is + * done by _dl_match_file() + */ +nohints: + if (searchpath == NULL) { + if (_dl_hint_search_path != NULL) + searchpath = _dl_hint_search_path; + else + searchpath = DEFAULT_PATH; + } + pp = searchpath; + while (pp) { + path = lp; + while (path < lp + PATH_MAX && *pp && *pp != ':' && *pp != ';') + *path++ = *pp++; + *path = 0; + + /* interpret "" as curdir "." */ + if (lp[0] == '\0') { + lp[0] = '.'; + lp[1] = '\0'; } - } -} - -void -elf_print_objarray(void) -{ - int i, j; - struct objlist *ol; - printf("loaded objs # %d\n", objarray_cnt); - for (i = 0; i < objarray_cnt; i++) { - printf("%3d: %d obj %s\n", i, (int)objarray[i].obj->dyn.null, - objarray[i].obj->load_name); - TAILQ_FOREACH(ol, &(objarray[i].inst_list), - inst_list) { - printf("\tprog %s\n", ol->load_prog->load_name); - printf("got cache:\n"); - for (j = 0; j < ol->object->nchains; j++) { - if (ol->cache[j].obj != NULL) { - printf("symidx %d: obj %d sym %ld %s\n", - j, (int)ol->cache[j].obj->dyn.null, - ol->cache[j].sym - - ol->cache[j].obj->dyn.symtab, - ol->cache[j].sym->st_name + - ol->cache[j].obj->dyn.strtab - ); + if ((dd = opendir(lp)) != NULL) { + match = 0; + while ((dp = readdir(dd)) != NULL) { + tsod = *sodp; + if (elf_match_file(&tsod, dp->d_name, + dp->d_namlen)) { + /* + * When a match is found, tsod is + * updated with the major+minor found. + * This version is compared with the + * largest so far (kept in bsod), + * and saved if larger. + */ + if (!match || + tsod.sod_major == -1 || + tsod.sod_major > bsod.sod_major || + ((tsod.sod_major == + bsod.sod_major) && + tsod.sod_minor > bsod.sod_minor)) { + bsod = tsod; + match = 1; + len = strlcpy( + elf_hint_store, lp, + MAXPATHLEN); + if (lp[len-1] != '/') { + elf_hint_store[len] = + '/'; + len++; + } + strlcpy( + &elf_hint_store[len], + dp->d_name, + MAXPATHLEN-len); + if (tsod.sod_major == -1) + break; + } } } - printf("plt cache:\n"); - for (j = 0; j < ol->object->nchains; j++) { - if (ol->pltcache[j].obj != NULL) { - printf("symidx %d: obj %d sym %ld %s\n", - j, (int)ol->pltcache[j].obj->dyn.null, - ol->pltcache[j].sym - - ol->pltcache[j].obj->dyn.symtab, - ol->pltcache[j].sym->st_name + - ol->pltcache[j].obj->dyn.strtab - ); - } + closedir(dd); + if (match) { + *sodp = bsod; + return (elf_hint_store); } } - } -} -int -write_txtbusy_file(char *name) -{ - char *prebind_name; - int fd; - int oldfd; - int err; - struct stat sb; - void *buf; - size_t len, wlen; - - err = lstat(name, &sb); /* get mode of old file (preserve mode) */ - if (err != 0) - return -1; /* stat shouldn't fail but if it does */ - - /* pick a better filename (pulling apart string?) */ - err = asprintf(&prebind_name, "%s%s", name, ".prebXXXXXXXXXX"); - if (err == -1) { - /* fail */ - exit (10); /* bail on memory failure */ - } - mkstemp(prebind_name); - - /* allocate a 256k buffer to copy the file */ -#define BUFSZ (256 * 1024) - buf = xmalloc(BUFSZ); - - fd = open(prebind_name, O_RDWR|O_CREAT|O_TRUNC, sb.st_mode); - oldfd = open(name, O_RDONLY); - while ((len = read(oldfd, buf, BUFSZ)) > 0) { - wlen = write(fd, buf, len); - if (wlen != len) { - /* write failed */ - close(fd); - close(oldfd); - unlink(prebind_name); - free(buf); - return -1; - } + if (*pp) /* Try curdir if ':' at end */ + pp++; + else + pp = 0; } - - /* this mode is used above, but is modified by umask */ - chmod (prebind_name, sb.st_mode); - close(oldfd); - unlink(name); - rename (prebind_name, name); - free (buf); - - return fd; + return NULL; } -void -elf_load_existing_prebind(struct elf_object *object, int fd) +elf_object_t * +elf_tryload_shlib(const char *libname) { - struct prebind_footer footer; - void *prebind_data; - - lseek(fd, -((off_t)sizeof(struct prebind_footer)), SEEK_END); - read(fd, &footer, sizeof(struct prebind_footer)); - - if (footer.bind_id[0] != BIND_ID0 || - footer.bind_id[1] != BIND_ID1 || - footer.bind_id[2] != BIND_ID2 || - footer.bind_id[3] != BIND_ID3) { - return; - } - - prebind_data = mmap(0, footer.prebind_size, PROT_READ, - MAP_FILE, fd, footer.prebind_base); - objarray[object->dyn.null].oprebind_data = prebind_data; - objarray[object->dyn.null].id0 = footer.id0; - objarray[object->dyn.null].id1 = footer.id1; -} -void -copy_oldsymcache(int objidx) -{ - void *prebind_map; - struct prebind_footer *footer; struct elf_object *object; - struct elf_object *tobj; - struct symcache_noflag *tcache; - struct symcachetab *symcache; - int i, j; - int found; - char *c; - u_int32_t offset; - u_int32_t *poffset; - struct nameidx *nameidx; - char *nametab; - int *idxtolib; - - - object = objarray[objidx].obj; - - prebind_map = objarray[object->dyn.null].oprebind_data; - - objarray[objidx].symcache = - xcalloc(sizeof(struct symcache_noflag), object->nchains); - objarray[objidx].pltsymcache = - xcalloc(sizeof(struct symcache_noflag), object->nchains); - - poffset = (u_int32_t *)prebind_map; - c = prebind_map; - offset = *poffset; - c += offset; - footer = (void *)c; - - nameidx = prebind_map + footer->nameidx_idx; - nametab = prebind_map + footer->nametab_idx; - - idxtolib = xcalloc(footer->numlibs, sizeof(int)); - found = 0; - for (i = 0; i < footer->numlibs; i++) { - found = 0; - for (j = 0; j < objarray_cnt; j++) { - if (objarray[j].id0 == nameidx[i].id0 && - objarray[j].id1 == nameidx[i].id1) { - found = 1; - idxtolib[i] = j; - if (strcmp(objarray[j].obj->load_name, - &nametab[nameidx[i].name]) != 0) { - printf("warning filename mismatch" - " [%s] [%s]\n", - objarray[j].obj->load_name, - &nametab[nameidx[i].name]); - } - } - } - if (found == 0) - break; - } - if (found == 0) - goto done; - - /* build idxtolibs */ - - tcache = objarray[objidx].symcache; - symcache = prebind_map + footer->symcache_idx; - - for (i = 0; i < footer->symcache_cnt; i++) { - tobj = objarray[idxtolib[symcache[i].obj_idx]].obj; - - tcache[symcache[i].idx].obj = tobj; - tcache[symcache[i].idx].sym = tobj->dyn.symtab + - symcache[i].sym_idx; - } - - tcache = objarray[objidx].pltsymcache; - symcache = prebind_map + footer->pltsymcache_idx; - for (i = 0; i < footer->pltsymcache_cnt; i++) { - tobj = objarray[idxtolib[symcache[i].obj_idx]].obj; - - tcache[symcache[i].idx].obj = tobj; - tcache[symcache[i].idx].sym = tobj->dyn.symtab + - symcache[i].sym_idx; + object = elf_lookup_object(libname); + if (object == NULL) { + object = load_file(libname, OBJTYPE_LIB); } -done: - free (idxtolib); - /* munmap(prebind_map, size);*/ + if (object == NULL) + printf("tryload_shlib %s\n", libname); + return object; } -void * -xmalloc(size_t size) -{ - void *ret; - - ret = malloc(size); - if (ret == NULL) { - printf("unable to allocate memory\n"); - exit (20); - } - return ret; -} +/* + * elf_match_file() + * + * This fucntion determines if a given name matches what is specified + * in a struct sod. The major must match exactly, and the minor must + * be same or larger. + * + * sodp is updated with the minor if this matches. + */ -void * -xcalloc(size_t nmemb, size_t size) +int +elf_match_file(struct sod *sodp, char *name, int namelen) { - void *ret; - - ret = calloc(nmemb, size); - if (ret == NULL) { - printf("unable to allocate memory\n"); - abort(); - exit (20); - } - return ret; + int match; + struct sod lsod; + char *lname; + + lname = name; + if (sodp->sod_library) { + if (strncmp(name, "lib", 3)) + return 0; + lname += 3; + } + if (strncmp(lname, (char *)sodp->sod_name, + strlen((char *)sodp->sod_name))) + return 0; + + _dl_build_sod(name, &lsod); + + match = 0; + if ((strcmp((char *)lsod.sod_name, (char *)sodp->sod_name) == 0) && + (lsod.sod_library == sodp->sod_library) && + ((sodp->sod_major == -1) || (sodp->sod_major == lsod.sod_major)) && + ((sodp->sod_minor == -1) || + (lsod.sod_minor >= sodp->sod_minor))) { + match = 1; + + /* return version matched */ + sodp->sod_major = lsod.sod_major; + sodp->sod_minor = lsod.sod_minor; + } + free((char *)lsod.sod_name); + return match; } + diff --git a/libexec/ld.so/prebind/prebind.c b/libexec/ld.so/prebind/prebind.c index e28a2408ee7..e41e4e136ab 100644 --- a/libexec/ld.so/prebind/prebind.c +++ b/libexec/ld.so/prebind/prebind.c @@ -1,4 +1,4 @@ -/* $OpenBSD: prebind.c,v 1.16 2006/05/08 20:39:44 deraadt Exp $ */ +/* $OpenBSD: prebind.c,v 1.17 2006/05/12 15:12:42 drahn Exp $ */ /* * Copyright (c) 2006 Dale Rahn <drahn@dalerahn.com> * @@ -20,6 +20,7 @@ #include <sys/syslimits.h> #include <sys/param.h> #include <sys/mman.h> +#include <errno.h> #include <fcntl.h> #include <nlist.h> #include <elf_abi.h> @@ -41,12 +42,7 @@ char *shstrtab; -#define DEBUG - -/* TODO - library path from ldconfig */ -#define DEFAULT_PATH "/usr/lib:/usr/X11R6/lib:/usr/local/qte/lib" - -/* alpha uses RELOC_JMP_SLOT */ +/* alpha uses RELOC_JMP_SLOT */ #ifdef __amd64__ #define RELOC_JMP_SLOT R_X86_64_JUMP_SLOT #endif @@ -65,9 +61,9 @@ char *shstrtab; #ifdef __mips64__ #define RELOC_JMP_SLOT 0 /* XXX mips64 doesnt have PLT reloc */ #endif -/* powerpc uses RELOC_JMP_SLOT */ -/* sparc uses RELOC_JMP_SLOT */ -/* sparc64 uses RELOC_JMP_SLOT */ +/* powerpc uses RELOC_JMP_SLOT */ +/* sparc uses RELOC_JMP_SLOT */ +/* sparc64 uses RELOC_JMP_SLOT */ #if defined(__sparc__) && !defined(__sparc64__) /* ARGH, our sparc/include/reloc.h is wrong (for the moment) */ #undef RELOC_JMP_SLOT @@ -84,11 +80,31 @@ prog_list_ty prog_list = TAILQ_HEAD_INITIALIZER(prog_list); -struct elf_object * elf_load_object (void *pexe, const char *name); +struct objarray_list { + struct elf_object *obj; + struct symcache_noflag *symcache; + struct symcache_noflag *pltsymcache; + struct proglist *proglist; + u_int32_t id0; + u_int32_t id1; + u_int32_t *idxtolib; + void *oprebind_data; + int numlibs; + + TAILQ_HEAD(, objlist) inst_list; +} *objarray; + +int objarray_cnt; +int objarray_sz; + +int write_txtbusy_file(char *name); +void copy_oldsymcache(int objidx); +void elf_load_existing_prebind(struct elf_object *object, int fd); + + +struct elf_object * elf_load_object(void *pexe, const char *name); void elf_free_object(struct elf_object *object); void map_to_virt(Elf_Phdr *, Elf_Ehdr *, Elf_Addr, u_long *); -#ifdef DEBUG -#endif int load_obj_needed(struct elf_object *object); int load_lib(const char *name, struct elf_object *parent); elf_object_t * elf_load_shlib_hint(struct sod *sod, struct sod *req_sod, @@ -107,10 +123,13 @@ struct elf_object * elf_lookup_object_devino(dev_t dev, ino_t inode, void elf_free_curbin_list(struct elf_object *obj); void elf_resolve_curbin(void); struct proglist *elf_newbin(void); -void elf_add_prog(struct proglist *object); void elf_sum_reloc(); int elf_prep_lib_prebind(struct elf_object *object); int elf_prep_bin_prebind(struct proglist *pl); +void add_fixup_prog(struct elf_object *prog, struct elf_object *obj, int idx, + const struct elf_object *ref_obj, const Elf_Sym *ref_sym, int flag); +void add_fixup_oldprog(struct elf_object *prog, struct elf_object *obj, int idx, + const struct elf_object *ref_obj, const Elf_Sym *ref_sym, int flag); void elf_dump_footer(struct prebind_footer *footer); @@ -140,9 +159,72 @@ struct elf_object *load_object; struct elf_object * load_file(const char *filename, int lib); int elf_check_note(void *buf, Elf_Phdr *phdr); +void load_file_or_dir(char *name); void load_dir(char *name); void load_exe(char *name); +void __dead usage(); + +int +main(int argc, char **argv) +{ + int i; + int ch; + extern int optind; + + /* GETOPT */ + while ((ch = getopt(argc, argv, "mv")) != -1) { + switch (ch) { + case 'm': + merge_mode = 1; + break; + case 'v': + verbose++; + break; + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (argc == 0) { + usage(); + /* NOTREACHED */ + } + + elf_init_objarray(); + for (i = 0; i < argc; i++) + load_file_or_dir(argv[i]); + + if (verbose > 4) { + elf_print_objarray(); + elf_print_prog_list(&prog_list); + } + elf_sum_reloc(); + + printf("total new blocks %lld\n", prebind_blocks); + + return 0; +} + +void __dead +usage() +{ + extern char *__progname; + printf("%s [-mv] {programlist}\n", __progname); + exit(1); +} + +/* + * load ELF objects at the specified path it could be + * either a either a directory or file, if the object is + * a file, attempt to load it as an executable (will ignore shared objects + * and any files that are not Elf execuables. + * if the object is a directory pass it to a routine to deal with + * directory parsing. + */ void load_file_or_dir(char *name) { @@ -166,6 +248,14 @@ load_file_or_dir(char *name) } } + +/* + * for all of the objects in the directory, if it is a regular file + * load it as a binary, if it is unknown (nfs mount) stat the file + * and load the file for S_IFREG + * any other type of directory object: symlink, directory, socket, ... + * is ignored. + */ void load_dir(char *name) { @@ -175,10 +265,11 @@ load_dir(char *name) char *buf; dirp = opendir(name); - if (dirp == NULL) { - /* dir failed to open, skip */ + + /* if dir failes to open, skip */ + if (dirp == NULL) return; - } + while ((dp = readdir(dirp)) != NULL) { switch (dp->d_type) { case DT_UNKNOWN: @@ -190,17 +281,27 @@ load_dir(char *name) lstat(buf, &sb); if (sb.st_mode == S_IFREG) load_exe(buf); - free (buf); + free(buf); + break; case DT_REG: asprintf(&buf, "%s/%s", name, dp->d_name); load_exe(buf); - free (buf); + free(buf); + break; default: /* other files symlinks, dirs, ... we ignore */ ; } } } + +/* + * the given pathname is a regular file, however it may or may not + * be an ELF file. Attempt to load the given path and calculate prebind + * data for it. + * if the given file is not a ELF binary this will 'fail' and + * should not change any of the prebind state. + */ void load_exe(char *name) { @@ -218,7 +319,7 @@ load_exe(char *name) TAILQ_FOREACH(ol, &(curbin->curbin_list), list) { fail = load_obj_needed(ol->object); if (fail != 0) - break; /* XXX */ + break; /* XXX */ } if (fail == 0) { @@ -231,56 +332,62 @@ load_exe(char *name) /* slight abuse of this field */ if (fail == 0) { + objarray[object->dyn.null].proglist = curbin; elf_resolve_curbin(); - elf_add_prog(curbin); + TAILQ_INSERT_TAIL(&prog_list, curbin, list); } else { printf("failed to load %s\n", name); elf_free_curbin_list(object); - free (curbin); + free(curbin); } if (load_object != NULL) { load_object = NULL; } } else { - free (curbin); + free(curbin); } } +/* + * given a path to a file, attempt to open it and load any data necessary + * for prebind. this function is used for executables, libraries and ld.so + * file, it will do a lookup on the dev/inode to use a cached version + * of the file if it was already loaded, in case a library is referenced + * by more than one program or there are hardlinks between executable names. + * if the file is not an elf file of the appropriate type, it will return + * failure. + */ struct elf_object * load_file(const char *filename, int objtype) { - int fd = -1; - void *buf = NULL; struct stat ifstat; Elf_Ehdr *ehdr; Elf_Shdr *shdr; Elf_Phdr *phdr; char *pexe; struct elf_object *obj = NULL; + void *buf = NULL; + int fd = -1, i; int note_found; - int i; fd = open(filename, O_RDONLY); if (fd == -1) { - perror (filename); + perror(filename); goto done; } if (fstat(fd, &ifstat) == -1) { - perror (filename); + perror(filename); goto done; } if ((ifstat.st_mode & S_IFMT) != S_IFREG) goto done; - if (ifstat.st_size < sizeof (Elf_Ehdr)) { - if (verbose > 0) - printf("%s: short file\n", filename); + if (ifstat.st_size < sizeof (Elf_Ehdr)) goto done; - } - obj = elf_lookup_object_devino( ifstat.st_dev, ifstat.st_ino, objtype); + obj = elf_lookup_object_devino(ifstat.st_dev, ifstat.st_ino, objtype); if (obj != NULL) goto done; @@ -291,13 +398,12 @@ load_file(const char *filename, int objtype) goto done; } - ehdr = (Elf_Ehdr *) buf; + ehdr = (Elf_Ehdr *)buf; - if (IS_ELF(*ehdr) == 0) { + if (IS_ELF(*ehdr) == 0) goto done; - } - if (ehdr->e_machine != ELF_TARG_MACH) { + if (ehdr->e_machine != ELF_TARG_MACH) { if (verbose > 0) printf("%s: wrong arch\n", filename); goto done; @@ -326,10 +432,10 @@ load_file(const char *filename, int objtype) pexe = buf; - if (ehdr->e_shstrndx == 0) { + if (ehdr->e_shstrndx == 0) goto done; - } - shdr = (Elf_Shdr *) (pexe + ehdr->e_shoff + + + shdr = (Elf_Shdr *)(pexe + ehdr->e_shoff + (ehdr->e_shstrndx * ehdr->e_shentsize)); @@ -343,7 +449,7 @@ printf("e_shentsize %x\n", ehdr->e_shentsize); printf("e_shstrndx %x\n\n", ehdr->e_shstrndx); #endif - shstrtab = (char *) (pexe + shdr->sh_offset); + shstrtab = (char *)(pexe + shdr->sh_offset); obj = elf_load_object(pexe, filename); @@ -362,26 +468,30 @@ printf("e_shstrndx %x\n\n", ehdr->e_shstrndx); elf_add_object(obj, objtype); #ifdef DEBUG1 - dump_info(obj); + dump_info(obj); #endif } if ((objtype == OBJTYPE_LIB || objtype == OBJTYPE_DLO) && merge_mode == 1) { /* - * for libraries, check if old prebind info exists - * and load it if we are in merge mode + * for libraries and dynamic linker, check if old prebind + * info exists and load it if we are in merge mode */ - elf_load_existing_prebind(obj, fd); } done: if (buf != NULL) munmap(buf, ifstat.st_size); if (fd != -1) - close (fd); + close(fd); return obj; } +/* + * check if the given executable header on a ELF executable + * has the proper OpenBSD note on the file if it is not present + * binaries will be skipped. + */ int elf_check_note(void *buf, Elf_Phdr *phdr) { @@ -405,76 +515,21 @@ elf_check_note(void *buf, Elf_Phdr *phdr) return 0; } -void __dead -usage() -{ - extern char *__progname; - printf("%s [-mv] {programlist}\n", __progname); - exit(1); -} - -extern int64_t prebind_blocks; - -int -main(int argc, char **argv) -{ - int i; - int ch; - extern int optind; - - /* GETOPT */ - while ((ch = getopt(argc, argv, "mv")) != -1) { - switch (ch) { - case 'm': - merge_mode = 1; - break; - case 'v': - verbose++; - break; - default: - usage(); - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - - if (argc == 0) { - usage(); - /* NOTREACHED */ - } - - elf_init_objarray(); - - for (i = 0; i < argc; i++) { - load_file_or_dir(argv[i]); - } - if (verbose > 4) { - elf_print_objarray(); - elf_print_prog_list(&prog_list); - } - elf_sum_reloc(); - - printf("total new blocks %lld\n", prebind_blocks); - - return 0; -} - struct elf_object * -elf_load_object (void *pexe, const char *name) +elf_load_object(void *pexe, const char *name) { int i; struct elf_object *object; Elf_Dyn *dynp = NULL, *odynp; Elf_Ehdr *ehdr; Elf_Phdr *phdr; - const Elf_Sym *symt; - const char *strt; + const Elf_Sym *symt; + const char *strt; Elf_Addr loff; Elf_Word *needed_list; int needed_cnt = 0; - object = calloc (1, sizeof (struct elf_object)); + object = calloc(1, sizeof (struct elf_object)); if (object == NULL) { printf("unable to allocate object for %s\n", name); exit(10); @@ -493,7 +548,7 @@ elf_load_object (void *pexe, const char *name) break; case PT_INTERP: /* XXX can only occur in programs */ - curbin->interp = strdup ((char *)((char *)pexe + + curbin->interp = strdup((char *)((char *)pexe + phdr[i].p_offset)); default: break; @@ -501,7 +556,8 @@ elf_load_object (void *pexe, const char *name) } if (dynp == 0) { - return NULL; /* XXX ??? */ + free(object); + return NULL; /* not a dynamic binary */ } dynp = (Elf_Dyn *)((unsigned long)dynp + loff); @@ -667,24 +723,25 @@ elf_load_object (void *pexe, const char *name) #endif return object; } + /* - * Free any extra pieces associated with 'object' + * Free any extra pieces associated with 'object' */ void elf_free_object(struct elf_object *object) { free (object->load_name); if (object->dyn.hash != NULL) - free (object->dyn.hash); - free ((void *)object->dyn.strtab); - free ((void *)object->dyn.symtab); + free(object->dyn.hash); + free((void *)object->dyn.strtab); + free((void *)object->dyn.symtab); if (object->dyn.rel != NULL) - free (object->dyn.rel); + free(object->dyn.rel); if (object->dyn.rela != NULL) - free (object->dyn.rela); + free(object->dyn.rela); if (object->dyn.rpath != NULL) - free ((void *)object->dyn.rpath); - free (object); + free((void *)object->dyn.rpath); + free(object); } /* @@ -718,6 +775,11 @@ map_to_virt(Elf_Phdr *phdr, Elf_Ehdr *ehdr, Elf_Addr base, u_long *vaddr) } } +/* + * given a dynamic elf object (executable or binary) + * load any DT_NEEDED entries which were found when + * the object was initially loaded. + */ int load_obj_needed(struct elf_object *object) { @@ -740,310 +802,11 @@ load_obj_needed(struct elf_object *object) return 0; } -int -load_lib(const char *name, struct elf_object *parent) -{ - struct sod sod, req_sod; - int ignore_hints; - int try_any_minor = 0; - struct elf_object *object = NULL; - -#if 0 - printf("load_lib %s\n", name); -#endif - - ignore_hints = 0; - - if (strchr(name, '/')) { - char *lpath, *lname; - - lpath = strdup(name); - lname = strrchr(lpath, '/'); - if (lname == NULL || lname[1] == '\0') { - free(lpath); - return (1); /* failed */ - } - *lname = '\0'; - lname++; - - _dl_build_sod(lname, &sod); - req_sod = sod; - - /* this code does not allow lower minors */ -fullpathagain: - object = elf_load_shlib_hint(&sod, &req_sod, - ignore_hints, lpath); - if (object != NULL) - goto fullpathdone; - - if (try_any_minor == 0) { - try_any_minor = 1; - ignore_hints = 1; - req_sod.sod_minor = -1; - goto fullpathagain; - } - /* ERR */ -fullpathdone: - free(lpath); - free((char *)sod.sod_name); - return (object == NULL); /* failed */ - } - _dl_build_sod(name, &sod); - req_sod = sod; - - /* ignore LD_LIBRARY_PATH */ - -again: - if (parent->dyn.rpath != NULL) { - object = elf_load_shlib_hint(&sod, &req_sod, - ignore_hints, parent->dyn.rpath); - if (object != NULL) - goto done; - } - if (parent != load_object && load_object->dyn.rpath != NULL) { - object = elf_load_shlib_hint(&sod, &req_sod, - ignore_hints, load_object->dyn.rpath); - if (object != NULL) - goto done; - } - object = elf_load_shlib_hint(&sod, &req_sod, - ignore_hints, NULL); - - if (try_any_minor == 0) { - try_any_minor = 1; - ignore_hints = 1; - req_sod.sod_minor = -1; - goto again; - } - if (object == NULL) - printf ("unable to load %s\n", name); - -done: - free((char *)sod.sod_name); - - return (object == NULL); -} /* - * attempt to locate and load a library based on libpath, sod info and - * if it needs to respect hints, passing type and flags to perform open + * allocate a proglist entry for a new binary + * so that it is available for libraries to reference */ -elf_object_t * -elf_load_shlib_hint(struct sod *sod, struct sod *req_sod, - int ignore_hints, const char *libpath) -{ - elf_object_t *object = NULL; - char *hint; - - hint = elf_find_shlib(req_sod, libpath, ignore_hints); - if (hint != NULL) { - if (req_sod->sod_minor < sod->sod_minor) - printf("warning: lib%s.so.%d.%d: " - "minor version >= %d expected, " - "using it anyway\n", - (char *)sod->sod_name, sod->sod_major, - req_sod->sod_minor, sod->sod_minor); - object = elf_tryload_shlib(hint); - } - return object; -} - -char elf_hint_store[MAXPATHLEN]; - -char * -elf_find_shlib(struct sod *sodp, const char *searchpath, int nohints) -{ - char *hint, lp[PATH_MAX + 10], *path; - struct dirent *dp; - const char *pp; - int match, len; - DIR *dd; - struct sod tsod, bsod; /* transient and best sod */ - - /* if we are to search default directories, and hints - * are not to be used, search the standard path from ldconfig - * (_dl_hint_search_path) or use the default path - */ - if (nohints) - goto nohints; - - if (searchpath == NULL) { - /* search 'standard' locations, find any match in the hints */ - hint = _dl_findhint((char *)sodp->sod_name, sodp->sod_major, - sodp->sod_minor, NULL); - if (hint) - return hint; - } else { - /* search hints requesting matches for only - * the searchpath directories, - */ - pp = searchpath; - while (pp) { - path = lp; - while (path < lp + PATH_MAX && - *pp && *pp != ':' && *pp != ';') - *path++ = *pp++; - *path = 0; - - /* interpret "" as curdir "." */ - if (lp[0] == '\0') { - lp[0] = '.'; - lp[1] = '\0'; - } - - hint = _dl_findhint((char *)sodp->sod_name, - sodp->sod_major, sodp->sod_minor, lp); - if (hint != NULL) - return hint; - - if (*pp) /* Try curdir if ':' at end */ - pp++; - else - pp = 0; - } - } - - /* - * For each directory in the searchpath, read the directory - * entries looking for a match to sod. filename compare is - * done by _dl_match_file() - */ -nohints: - if (searchpath == NULL) { - if (_dl_hint_search_path != NULL) - searchpath = _dl_hint_search_path; - else - searchpath = DEFAULT_PATH; - } - pp = searchpath; - while (pp) { - path = lp; - while (path < lp + PATH_MAX && *pp && *pp != ':' && *pp != ';') - *path++ = *pp++; - *path = 0; - - /* interpret "" as curdir "." */ - if (lp[0] == '\0') { - lp[0] = '.'; - lp[1] = '\0'; - } - - if ((dd = opendir(lp)) != NULL) { - match = 0; - while ((dp = readdir(dd)) != NULL) { - tsod = *sodp; - if (elf_match_file(&tsod, dp->d_name, - dp->d_namlen)) { - /* - * When a match is found, tsod is - * updated with the major+minor found. - * This version is compared with the - * largest so far (kept in bsod), - * and saved if larger. - */ - if (!match || - tsod.sod_major == -1 || - tsod.sod_major > bsod.sod_major || - ((tsod.sod_major == - bsod.sod_major) && - tsod.sod_minor > bsod.sod_minor)) { - bsod = tsod; - match = 1; - len = strlcpy( - elf_hint_store, lp, - MAXPATHLEN); - if (lp[len-1] != '/') { - elf_hint_store[len] = - '/'; - len++; - } - strlcpy( - &elf_hint_store[len], - dp->d_name, - MAXPATHLEN-len); - if (tsod.sod_major == -1) - break; - } - } - } - closedir(dd); - if (match) { - *sodp = bsod; - return (elf_hint_store); - } - } - - if (*pp) /* Try curdir if ':' at end */ - pp++; - else - pp = 0; - } - return NULL; -} - -elf_object_t * -elf_tryload_shlib(const char *libname) -{ - struct elf_object *object; - object = elf_lookup_object(libname); - if (object == NULL) { - object = load_file(libname, OBJTYPE_LIB); - } - if (object == NULL) - printf("tryload_shlib %s\n", libname); - return object; -} - -/* - * elf_match_file() - * - * This fucntion determines if a given name matches what is specified - * in a struct sod. The major must match exactly, and the minor must - * be same or larger. - * - * sodp is updated with the minor if this matches. - */ - -int -elf_match_file(struct sod *sodp, char *name, int namelen) -{ - int match; - struct sod lsod; - char *lname; - - lname = name; - if (sodp->sod_library) { - if (strncmp(name, "lib", 3)) - return 0; - lname += 3; - } - if (strncmp(lname, (char *)sodp->sod_name, - strlen((char *)sodp->sod_name))) - return 0; - - _dl_build_sod(name, &lsod); - - match = 0; - if ((strcmp((char *)lsod.sod_name, (char *)sodp->sod_name) == 0) && - (lsod.sod_library == sodp->sod_library) && - ((sodp->sod_major == -1) || (sodp->sod_major == lsod.sod_major)) && - ((sodp->sod_minor == -1) || - (lsod.sod_minor >= sodp->sod_minor))) { - match = 1; - - /* return version matched */ - sodp->sod_major = lsod.sod_major; - sodp->sod_minor = lsod.sod_minor; - } - free((char *)lsod.sod_name); - return match; -} -void -elf_add_prog(struct proglist *curbin) -{ - TAILQ_INSERT_TAIL(&prog_list, curbin, list); -} - struct proglist * elf_newbin(void) { @@ -1078,7 +841,7 @@ struct elf_object *badobj = &badobj_store; * symbol table note that this will skip copying the following references * 1. non-existing entries * 2. symobj == prog &&& obj != prog - * 3 symobj == prog's interpter (references to dl_open) + * 3. symobj == prog's interpter (references to dl_open) */ void elf_copy_syms(struct symcache_noflag *tcache, struct symcache_noflag *scache, @@ -1090,9 +853,9 @@ elf_copy_syms(struct symcache_noflag *tcache, struct symcache_noflag *scache, if (scache[i].obj == NULL) continue; - lib_prog_ref = (obj != prog && scache[i].obj == prog); - if (tcache[i].obj != NULL || lib_prog_ref) { + if (tcache[i].obj != NULL) { + lib_prog_ref = (obj != prog && scache[i].obj == prog); if (scache[i].obj != tcache[i].obj || lib_prog_ref) { if (verbose > 2) { printf("sym mismatch %d: " @@ -1158,6 +921,175 @@ elf_copy_syms(struct symcache_noflag *tcache, struct symcache_noflag *scache, } } +void +insert_sym_objcache(struct elf_object *obj, int idx, + const struct elf_object *ref_obj, const Elf_Sym *ref_sym, int flags) +{ + struct symcache_noflag *tcache; + struct elf_object *prog; + + prog = TAILQ_FIRST(&(curbin->curbin_list))->object; + +#if 0 + printf("inserting symbol obj %s %d to %s\n", + obj->load_name, idx, ref_obj->load_name); +#endif + + if (flags) + tcache = objarray[obj->dyn.null].pltsymcache; + else + tcache = objarray[obj->dyn.null].symcache; + + if (tcache[idx].obj != NULL) { + if (ref_obj != tcache[idx].obj || + (obj != prog && ref_obj == prog)) { + if (verbose > 2) { + printf("sym mismatch %d: " + "obj %d: sym %ld %s " + "nobj %s\n", + idx, (int)ref_obj->dyn.null, + ref_sym - + ref_obj->dyn.symtab, + ref_sym->st_name + + ref_obj->dyn.strtab, + ref_obj->load_name); + } + +#if 0 + if (tcache[idx].obj != badobj) + printf("%s: %s conflict\n", + obj->load_name, + ref_sym->st_name + + ref_obj->dyn.strtab); +#endif + /* + * if one of the symbol entries + * happens to be a self reference + * go ahead and keep that reference + * prevents some instances of fixups + * for every binary, eg one program + * overriding malloc() will not make + * ever binary have a fixup for libc + * references to malloc() + */ + if (ref_obj == obj) { + tcache[idx].obj = ref_obj; + tcache[idx].sym = ref_sym; + add_fixup_oldprog(prog, obj, idx, ref_obj, + ref_sym, flags); + } else if (tcache[idx].obj == obj) { + /* no change necessary */ + add_fixup_prog(prog, obj, idx, ref_obj, + ref_sym, flags); + } else { + add_fixup_oldprog(prog, obj, idx, + tcache[idx].obj, tcache[idx].sym, flags); + tcache[idx].obj = badobj; + tcache[idx].sym = NULL; + add_fixup_prog(prog, obj, idx, ref_obj, + ref_sym, flags); + } + } + } else { + if (ref_obj != prog) { +#if 0 + printf("%s: %s copying\n", + obj->load_name, + ref_sym->st_name + + ref_obj->dyn.strtab); +#endif + tcache[idx].obj = ref_obj; + tcache[idx].sym = ref_sym; + } else { + add_fixup_prog(prog, obj, idx, ref_obj, + ref_sym, flags); + } + } + +#if 0 + printf("symidx %d: obj %d sym %ld %s\n", + i, ref_obj->dyn.null, + ref_sym - + ref_obj->dyn.symtab, + ref_sym->st_name + + ref_obj->dyn.strtab + ); +#endif +} + +void +add_fixup_prog(struct elf_object *prog, struct elf_object *obj, int idx, + const struct elf_object *ref_obj, const Elf_Sym *ref_sym, int flag) +{ + struct proglist *pl; + int i, libidx, cnt; + + pl = objarray[prog->dyn.null].proglist; + + + libidx = -1; + for (i = 0; i < pl->nobj; i++) { + if (pl->libmap[0][i] == obj->dyn.null) { + libidx = (i * 2) + ((flag & SYM_PLT) ? 1 : 0); + break; + } + } + if (libidx == -1) { + printf("unable to find object\n"); + return; + } + + + /* have to check for duplicate patches */ + for (i = 0; i < pl->fixupcnt[libidx]; i++) { + if (pl->fixup[libidx][i].sym == idx) + return; + } + + if (verbose > 1) + printf("fixup for obj %s on prog %s sym %s: %d\n", + obj->load_name, prog->load_name, + ref_obj->dyn.strtab + ref_sym->st_name, + pl->fixupcnt[libidx]); + + + if (pl->fixupcntalloc[libidx] < pl->fixupcnt[libidx] + 1) { + pl->fixupcntalloc[libidx] += 16; + pl->fixup[libidx] = realloc(pl->fixup[libidx], + sizeof (struct fixup) * pl->fixupcntalloc[libidx]); + if (pl->fixup[libidx] == NULL) { + printf("realloc fixup, out of memory\n"); + exit (20); + } + } + cnt = pl->fixupcnt[libidx]; + pl->fixup[libidx][cnt].sym = idx; + pl->fixup[libidx][cnt].obj_idx = ref_obj->dyn.null; + pl->fixup[libidx][cnt].sym_idx = ref_sym - ref_obj->dyn.symtab; + pl->fixupcnt[libidx]++; +} + +void +add_fixup_oldprog(struct elf_object *prog, struct elf_object *obj, int idx, + const struct elf_object *ref_obj, const Elf_Sym *ref_sym, int flag) +{ + struct objlist *ol; + + TAILQ_FOREACH(ol, &(objarray[obj->dyn.null].inst_list), inst_list) { + if (ol->load_prog == prog) { +#if 0 + printf("obj %s has references to %s (skipping)\n", + obj->load_name, prog->load_name); +#endif + continue; + } + /* process here */ + + add_fixup_prog(ol->load_prog, obj, idx, ref_obj, ref_sym, flag); + } + +} + struct elf_object * elf_lookup_object(const char *name) { @@ -1270,6 +1202,12 @@ elf_find_symbol_rel(const char *name, struct elf_object *object, symcache[idx].obj = ref_object; symcache[idx].sym = ref_sym; } + +#if 0 + /* direct insert into global symcache */ + insert_sym_objcache(object, idx, ref_object, ref_sym, + flags & SYM_PLT); +#endif } else { printf("symbol not found %s\n", name); } @@ -1347,6 +1285,11 @@ elf_find_symbol_rela(const char *name, struct elf_object *object, symcache[idx].obj = ref_object; symcache[idx].sym = ref_sym; } +#if 0 + /* direct insert into global symcache */ + insert_sym_objcache(object, idx, ref_object, ref_sym, + flags & SYM_PLT); +#endif } else { printf("symbol not found %s\n", name); } @@ -1418,6 +1361,17 @@ elf_reloc(struct elf_object *object, struct symcache_noflag *symcache, #ifdef DEBUG1 printf("rel relocations: %d\n", numrel); #endif +#if 1 + symcache = calloc(sizeof(struct symcache_noflag), + object->nchains); + pltsymcache = calloc(sizeof(struct symcache_noflag), + object->nchains); + if (symcache == NULL || pltsymcache == NULL) { + printf("unable to allocate memory for cache %s\n", + object->load_name); + exit(20); + } +#endif rel = object->dyn.rel; for (i = 0; i < numrel; i++) { const char *s; @@ -1460,7 +1414,7 @@ elf_reloc(struct elf_object *object, struct symcache_noflag *symcache, ELF_R_SYM(rel[i].r_info), s, ELF_R_TYPE(rel[i].r_info)); #endif - if (ELF_R_SYM(rel[i].r_info) != 0) { + if (ELF_R_SYM(rel[i].r_info) != 0) { elf_find_symbol_rel(s, object, &rel[i], symcache, pltsymcache); } @@ -1487,7 +1441,7 @@ elf_reloc(struct elf_object *object, struct symcache_noflag *symcache, ELF_R_SYM(rela[i].r_info), s, ELF_R_TYPE(rela[i].r_info)); #endif - if (ELF_R_SYM(rela[i].r_info) != 0) { + if (ELF_R_SYM(rela[i].r_info) != 0) { elf_find_symbol_rela(s, object, &rela[i], symcache, pltsymcache); } @@ -1515,32 +1469,1179 @@ elf_reloc(struct elf_object *object, struct symcache_noflag *symcache, ELF_R_SYM(rela[i].r_info), s, ELF_R_TYPE(rela[i].r_info)); #endif - if (ELF_R_SYM(rela[i].r_info) != 0) { + if (ELF_R_SYM(rela[i].r_info) != 0) { elf_find_symbol_rela(s, object, &rela[i], symcache, pltsymcache); } } } + + for (i = 0; i < object->nchains; i++) + if (symcache[i].sym != NULL) + insert_sym_objcache(object, i, symcache[i].obj, + symcache[i].sym, 0); + + for (i = 0; i < object->nchains; i++) + if (pltsymcache[i].sym != NULL) + insert_sym_objcache(object, i, pltsymcache[i].obj, + pltsymcache[i].sym, SYM_PLT); + + free(symcache); + free(pltsymcache); } void elf_resolve_curbin(void) { struct objlist *ol; + int numobj = 0; #ifdef DEBUG1 elf_print_curbin_list(curbin); #endif TAILQ_FOREACH(ol, &(curbin->curbin_list), list) { - ol->cache = calloc(sizeof(struct symcache_noflag), - ol->object->nchains); - ol->pltcache = calloc(sizeof(struct symcache_noflag), - ol->object->nchains); - if (ol->cache == NULL || ol->pltcache == NULL) { - printf("unable to allocate memory for cache %s\n", - ol->object->load_name); + numobj++; + } + curbin->nobj = numobj; + curbin->libmap = xcalloc(numobj, sizeof (u_int32_t *)); + curbin->libmap[0] = xcalloc(numobj, sizeof (u_int32_t *)); + curbin->fixup = xcalloc(2 * numobj, sizeof (struct fixup *)); + curbin->fixupcnt = xcalloc(2 * numobj, sizeof (int)); + curbin->fixupcntalloc = xcalloc(2 * numobj, sizeof (int)); + + numobj = 0; + TAILQ_FOREACH(ol, &(curbin->curbin_list), list) { + curbin->libmap[0][numobj] = ol->object->dyn.null; + numobj++; + } + TAILQ_FOREACH(ol, &(curbin->curbin_list), list) { + elf_reloc(ol->object, ol->cache, ol->pltcache); + } +} + +void +elf_add_object_curbin_list(struct elf_object *object) +{ + struct objlist *ol; + ol = xmalloc(sizeof (struct objlist)); + ol->object = object; + TAILQ_INSERT_TAIL(&(curbin->curbin_list), ol, list); + if ( load_object == NULL) + load_object = object; + ol->load_prog = load_object; + +#if 0 + printf("adding object %s %d with prog %s\n", object->load_name, + object->dyn.null, load_object->load_name); +#endif + TAILQ_INSERT_TAIL(&(objarray[object->dyn.null].inst_list), ol, inst_list); +} +void +elf_init_objarray(void) +{ + objarray_sz = 512; + objarray = xmalloc(sizeof (objarray[0]) * objarray_sz); +} + +void +elf_sum_reloc() +{ + int i, numobjs; + int err = 0; + struct objlist *ol; + struct proglist *pl; +#if 0 + struct symcache_noflag *lcache; + struct symcache_noflag *lpcache; +#endif + + for (i = 0; i < objarray_cnt; i++) { +#if 0 + printf("%3d: %d obj %s\n", i, objarray[i].obj->dyn.null, + objarray[i].obj->load_name); +#endif + if (TAILQ_EMPTY(&objarray[i].inst_list)) { + printf("skipping %s\n", objarray[i].obj->load_name); + continue; + } +#if 0 /* early alloc */ + lcache = objarray[i].symcache; + lpcache = objarray[i].pltsymcache; + objarray[i].symcache = xcalloc(sizeof(struct symcache_noflag), + objarray[i].obj->nchains); + objarray[i].pltsymcache = xcalloc(sizeof( + struct symcache_noflag), objarray[i].obj->nchains); + + if (objarray[i].oprebind_data != NULL) { + copy_oldsymcache(i); + continue; + } +#endif + +#if 0 + TAILQ_FOREACH(ol, &(objarray[i].inst_list), inst_list) { + +#if 0 + printf("\tprog %d %s\n", ol->load_prog->dyn.null, + ol->load_prog->load_name); + printf("cache: %p %p %s\n", + objarray[i].symcache, ol->cache, + ol->object->load_name ); +#endif + + elf_copy_syms(objarray[i].symcache, + ol->cache, + ol->object, + ol->load_prog, + ol->object->nchains); + + elf_copy_syms(objarray[i].pltsymcache, + ol->pltcache, + ol->object, + ol->load_prog, + ol->object->nchains); + } +#endif + +/* check results */ +#if 0 + { + int j; + for (j = 0; j < objarray[i].obj->nchains; j++) { + if (lcache[j].obj != + objarray[i].symcache[j].obj || + lcache[j].sym != + objarray[i].symcache[j].sym) + printf("symbol mismatch l obj %s idx %d" + "newobj %s oldobj %s\n", + ol->object->load_name, j, + lcache[j].obj->load_name, + objarray[i].symcache[j].obj->load_name); + + if (lpcache[j].obj != + objarray[i].pltsymcache[j].obj || + lpcache[j].sym != + objarray[i].pltsymcache[j].sym) + printf("symbol mismatch p obj %s idx %d" + "newobj %s oldobj %s\n", + ol->object->load_name, j, + lpcache[j].obj->load_name, + objarray[i].pltsymcache[j].obj->load_name); + + } + free(lcache); + free(lpcache); + } +#endif + } + + + TAILQ_FOREACH(ol, &library_list, list) { +#if 0 + printf("processing lib %s\n", ol->object->load_name); +#endif + err += elf_prep_lib_prebind(ol->object); + } + TAILQ_FOREACH(pl, &prog_list, list) { + numobjs = 0; + TAILQ_FOREACH(ol, &(pl->curbin_list), list) { + numobjs++; + } + pl->nobj = numobjs; +#if 0 + pl->libmap = xcalloc(numobjs, sizeof (u_int32_t *)); + pl->fixup = xcalloc(2 * numobjs, sizeof (struct fixup *)); + pl->fixupcnt = xcalloc(2 * numobjs, sizeof (int)); + + numobjs = 0; + TAILQ_FOREACH(ol, &(pl->curbin_list), list) { + elf_calc_fixups(pl, ol, numobjs); + numobjs++; + } +#endif + } + TAILQ_FOREACH(pl, &prog_list, list) { + err += elf_prep_bin_prebind(pl); +#if 0 + printf("processing binary %s\n", + TAILQ_FIRST(&pl->curbin_list)->object->load_name); +#endif + } + if (err != 0) + printf("failures %d\n", err); +} + +int +elf_prep_lib_prebind(struct elf_object *object) +{ + int numlibs = 0; + int ret = 0; + int i; + int ref_obj; + int *libmap; + int *idxtolib; + struct nameidx *nameidx; + char *nametab; + int nametablen; + struct symcache_noflag *symcache; + struct symcache_noflag *pltsymcache; + struct symcachetab *symcachetab; + int symcache_cnt = 0; + struct symcachetab *pltsymcachetab; + int pltsymcache_cnt = 0; + + symcache = objarray[object->dyn.null].symcache; + pltsymcache = objarray[object->dyn.null].pltsymcache; + libmap = xcalloc(objarray_cnt, sizeof (int)); + idxtolib = xcalloc(objarray_cnt, sizeof (int)); + objarray[object->dyn.null].idxtolib = idxtolib; + + for (i = 0; i < objarray_cnt; i++) + libmap[i] = -1; + + nametablen = 0; + for (i = 0; i < object->nchains; i++) { + if (symcache[i].sym == NULL) + continue; + ref_obj = symcache[i].obj->dyn.null; + symcache_cnt++; + if (libmap[ref_obj] != -1) + continue; + libmap[ref_obj] = numlibs; + idxtolib[numlibs] = ref_obj; + printf("lib %s obj %d refobj %d\n", object->load_name, numlibs, ref_obj); + nametablen += strlen(symcache[i].obj->load_name) + 1; + numlibs++; + } + symcachetab = xcalloc(symcache_cnt , sizeof(struct symcachetab)); + + symcache_cnt = 0; + for (i = 0; i < object->nchains; i++) { + if (symcache[i].sym == NULL) + continue; + symcachetab[symcache_cnt].idx = i; + symcachetab[symcache_cnt].obj_idx = + libmap[symcache[i].obj->dyn.null]; + symcachetab[symcache_cnt].sym_idx = + symcache[i].sym - symcache[i].obj->dyn.symtab; + symcache_cnt++; + } + for (i = 0; i < object->nchains; i++) { + if (pltsymcache[i].sym == NULL) + continue; + ref_obj = pltsymcache[i].obj->dyn.null; + pltsymcache_cnt++; + if (libmap[ref_obj] != -1) + continue; + libmap[ref_obj] = numlibs; + idxtolib[numlibs] = ref_obj; +#if 0 + printf("lib %s obj %d refobj %d\n", object->load_name, numlibs, ref_obj); +#endif + nametablen += strlen(pltsymcache[i].obj->load_name) + 1; + numlibs++; + } + pltsymcachetab = xcalloc(pltsymcache_cnt , sizeof(struct symcachetab)); + + pltsymcache_cnt = 0; + for (i = 0; i < object->nchains; i++) { + if (pltsymcache[i].sym == NULL) + continue; + pltsymcachetab[pltsymcache_cnt].idx = i; + pltsymcachetab[pltsymcache_cnt].obj_idx = + libmap[pltsymcache[i].obj->dyn.null]; + pltsymcachetab[pltsymcache_cnt].sym_idx = + pltsymcache[i].sym - pltsymcache[i].obj->dyn.symtab; + pltsymcache_cnt++; + } + + objarray[object->dyn.null].numlibs = numlibs; + + nameidx = xcalloc(numlibs, sizeof (struct nameidx)); + nametab = xmalloc(nametablen); + + nametablen = 0; + for (i = 0; i < numlibs; i++) { + nameidx[i].name = nametablen; + nameidx[i].id0 = objarray[idxtolib[i]].id0; + nameidx[i].id1 = objarray[idxtolib[i]].id1; + nametablen += strlen(objarray[idxtolib[i]].obj->load_name) + 1; + strlcpy (&nametab[nameidx[i].name], + objarray[idxtolib[i]].obj->load_name, + nametablen - nameidx[i].name); + } +#if 0 + for (i = 0; i < numlibs; i++) { + printf("\tlib %s\n", &nametab[nameidx[i].name]); + } +#endif + + /* skip writing lib if using old prebind data */ + if (objarray[object->dyn.null].oprebind_data == NULL) + ret = elf_write_lib(object, nameidx, nametab, nametablen, + numlibs, 0, NULL, NULL, NULL, NULL, symcachetab, + symcache_cnt, pltsymcachetab, pltsymcache_cnt); + + free (nameidx); + free (nametab); + free (libmap); + free(pltsymcachetab); + free(symcachetab); + + return ret; +} + +int +elf_prep_bin_prebind(struct proglist *pl) +{ + int ret; + int numlibs = 0; + int i, j; + int ref_obj; + int *libmap; + int *idxtolib; + struct nameidx *nameidx; + char *nametab; + int nametablen; + struct symcache_noflag *symcache; + struct symcache_noflag *pltsymcache; + struct symcachetab *symcachetab; + int symcache_cnt; + struct symcachetab *pltsymcachetab; + int pltsymcache_cnt; + struct elf_object *object; + struct objlist *ol; + + object = TAILQ_FIRST(&(pl->curbin_list))->object; + symcache = objarray[object->dyn.null].symcache; + pltsymcache = objarray[object->dyn.null].pltsymcache; + libmap = xcalloc(objarray_cnt, sizeof (int)); + idxtolib = xcalloc(pl->nobj, sizeof (int)); + + for (i = 0; i < objarray_cnt; i++) + libmap[i] = -1; + + for (i = 0; i < pl->nobj; i++) + idxtolib[i] = -1; + + nametablen = 0; + TAILQ_FOREACH(ol, &(pl->curbin_list), list) { + ref_obj = ol->object->dyn.null; + nametablen += strlen(ol->object->load_name) + 1; + libmap[ref_obj] = numlibs; + idxtolib[numlibs] = ref_obj; +#if 1 + printf("obj :%d, idx %d %s\n", numlibs, ref_obj, ol->object->load_name); +#endif + numlibs++; + } + + /* do got */ + symcache_cnt = 0; + for (i = 0; i < object->nchains; i++) { + if (symcache[i].sym != NULL) + symcache_cnt++; + } +#if 0 + printf("program has symcache size %d\n", symcache_cnt); +#endif + + symcachetab = xcalloc(symcache_cnt , sizeof(struct symcachetab)); + + symcache_cnt = 0; + for (i = 0; i < object->nchains; i++) { + if (symcache[i].sym == NULL) + continue; + symcachetab[symcache_cnt].idx = i; + symcachetab[symcache_cnt].obj_idx = + libmap[symcache[i].obj->dyn.null]; + symcachetab[symcache_cnt].sym_idx = + symcache[i].sym - symcache[i].obj->dyn.symtab; + symcache_cnt++; + } + + /* now do plt */ + pltsymcache_cnt = 0; + for (i = 0; i < object->nchains; i++) { + if (pltsymcache[i].sym != NULL) + pltsymcache_cnt++; + } + pltsymcachetab = xcalloc(pltsymcache_cnt , sizeof(struct symcachetab)); + + pltsymcache_cnt = 0; + for (i = 0; i < object->nchains; i++) { + if (pltsymcache[i].sym == NULL) + continue; + pltsymcachetab[pltsymcache_cnt].idx = i; + pltsymcachetab[pltsymcache_cnt].obj_idx = + libmap[pltsymcache[i].obj->dyn.null]; + pltsymcachetab[pltsymcache_cnt].sym_idx = + pltsymcache[i].sym - pltsymcache[i].obj->dyn.symtab; + pltsymcache_cnt++; + } + + objarray[object->dyn.null].numlibs = numlibs; + + nameidx = xcalloc(numlibs, sizeof (struct nameidx)); + nametab = xmalloc(nametablen); + + nametablen = 0; + for (i = 0; i < numlibs; i++) { + nameidx[i].name = nametablen; + nameidx[i].id0 = objarray[idxtolib[i]].id0; + nameidx[i].id1 = objarray[idxtolib[i]].id1; + nametablen += strlen(objarray[idxtolib[i]].obj->load_name) + 1; + + strlcpy (&nametab[nameidx[i].name], + objarray[idxtolib[i]].obj->load_name, + nametablen - nameidx[i].name); + } +#if 1 + for (i = 0; i < numlibs; i++) { + printf("\tlib %s\n", &nametab[nameidx[i].name]); + } +#endif + pl->libmapcnt = xcalloc(numlibs, sizeof(u_int32_t)); + + /* have to do both got and plt fixups */ + for (i = 0; i < numlibs; i++) { + for (j = 0; j < pl->fixupcnt[2*i]; j++) { + pl->fixup[2*i][j].obj_idx = + libmap[pl->fixup[2*i][j].obj_idx]; + } + for (j = 0; j < pl->fixupcnt[2*i+1]; j++) { + pl->fixup[2*i+1][j].obj_idx = + libmap[pl->fixup[2*i+1][j].obj_idx]; + } + + pl->libmapcnt[i] = objarray[idxtolib[i]].numlibs; + pl->libmap[i] = xcalloc( objarray[idxtolib[i]].numlibs, + sizeof(u_int32_t)); + if (i != 0) { +#if 0 + printf("prog %s: lib %d numlibs %d\n", + objarray[idxtolib[i]].obj->load_name, i, + objarray[idxtolib[i]].numlibs); +#endif + for (j = 0; j < objarray[idxtolib[i]].numlibs; j++) { +#if 1 + printf("prog %s: lib %s %d: %d %d %d\n", + object->load_name, + objarray[idxtolib[i]].obj->load_name, j, + pl->libmap[i][j], + objarray[idxtolib[i]].idxtolib[j], + libmap[objarray[idxtolib[i]].idxtolib[j]] ); +#endif + pl->libmap[i][j] = + libmap[objarray[idxtolib[i]].idxtolib[j]]; + } + } + } + + ret = elf_write_lib(object, nameidx, nametab, nametablen, numlibs, + numlibs, pl->fixup, pl->fixupcnt, + pl->libmap, pl->libmapcnt, + symcachetab, symcache_cnt, + pltsymcachetab, pltsymcache_cnt); + + free(symcachetab); + free(pltsymcachetab); + free(idxtolib); + free(nameidx); + free(nametab); + free(libmap); + + return ret; +} + +int64_t prebind_blocks; +int +elf_write_lib(struct elf_object *object, struct nameidx *nameidx, + char *nametab, int nametablen, int numlibs, + int nfixup, struct fixup **fixup, int *fixupcnt, + u_int32_t **libmap, int *libmapcnt, + struct symcachetab *symcachetab, int symcache_cnt, + struct symcachetab *pltsymcachetab, int pltsymcache_cnt) +{ + off_t base_offset; + struct prebind_footer footer; + struct stat ifstat; + int fd; + u_int32_t next_start; + u_int32_t *fixuptab = NULL; + u_int32_t *maptab = NULL; + u_int32_t footer_offset; + int i; + size_t len; + + /* open the file */ + fd = open(object->load_name, O_RDWR); + if (fd == -1) { + if (errno == ETXTBSY) + fd = write_txtbusy_file(object->load_name); + if (fd == -1) { + perror(object->load_name); + return 1; + } + } + lseek(fd, -((off_t)sizeof(struct prebind_footer)), SEEK_END); + len = read(fd, &footer, sizeof(struct prebind_footer)); + + if (footer.bind_id[0] == BIND_ID0 && + footer.bind_id[1] == BIND_ID1 && + footer.bind_id[2] == BIND_ID2 && + footer.bind_id[3] == BIND_ID3) { + + ftruncate(fd, footer.orig_size); + elf_clear_prog_load(fd, object); + } + + if (fstat(fd, &ifstat) == -1) { + perror(object->load_name); + exit(10); + } + bzero(&footer, sizeof(struct prebind_footer)); + + base_offset = ifstat.st_size; + prebind_blocks -= ifstat.st_blocks; /* subtract old size */ + + /* verify dev/inode - do we care about last modified? */ + + /* pieces to store on lib + * + * offset to footer + * nameidx - numlibs * sizeof nameidx + * symcache - symcache_cnt * sizeof (symcache_idx) + * pltsymcache - pltsymcache_cnt * sizeof (symcache_idx) + * fixup(N/A for lib) - nfixup * sizeof (symcache_idx) + * nametab - nametablen + * footer (not aligned) + */ + + footer.orig_size = base_offset; + base_offset = ELF_ROUND(base_offset, sizeof(u_int64_t)); + footer.prebind_base = base_offset; + footer.nameidx_idx = sizeof(u_int32_t); + footer.symcache_idx = footer.nameidx_idx + + numlibs * sizeof (struct nameidx); + footer.pltsymcache_idx = footer.symcache_idx + + symcache_cnt * sizeof (struct nameidx); + footer.symcache_cnt = symcache_cnt; + footer.pltsymcache_cnt = pltsymcache_cnt; + footer.fixup_cnt = 0; + footer.numlibs = numlibs; + next_start = footer.pltsymcache_idx + + (pltsymcache_cnt * sizeof (struct symcachetab)); + if (nfixup != 0) { + footer.fixup_cnt = nfixup; + footer.fixup_idx = next_start; + next_start += 2*nfixup * sizeof(u_int32_t); + footer.fixupcnt_idx = next_start; + next_start += 2*nfixup * sizeof(u_int32_t); + fixuptab = xcalloc( 2*nfixup, sizeof(u_int32_t)); + for ( i = 0; i < 2*nfixup; i++) { + fixuptab[i] = next_start; + next_start += fixupcnt[i] * sizeof(struct fixup); + } + footer.libmap_idx = next_start; + next_start += 2*nfixup * sizeof(u_int32_t); + maptab = xcalloc( 2*nfixup, sizeof(u_int32_t)); + maptab[0] = next_start; + for (i = 1; i < nfixup; i++) { + maptab[i] = next_start; + next_start += libmapcnt[i] * sizeof(u_int32_t); + } + + + } + footer.nametab_idx = next_start; + next_start += nametablen; + next_start = ELF_ROUND(next_start, sizeof(u_int64_t)); + footer_offset = next_start; + if (verbose > 1) { + printf("footer_offset %d\n", footer_offset); + } + footer.prebind_size = next_start + sizeof(struct prebind_footer); + + footer.prebind_version = PREBIND_VERSION; + footer.id0 = objarray[object->dyn.null].id0; + footer.id1 = objarray[object->dyn.null].id1; + footer.bind_id[0] = BIND_ID0; + footer.bind_id[1] = BIND_ID1; + footer.bind_id[2] = BIND_ID2; + footer.bind_id[3] = BIND_ID3; + + lseek(fd, footer.prebind_base, SEEK_SET); + write(fd, &footer_offset, sizeof(u_int32_t)); + + lseek(fd, footer.prebind_base+footer.nameidx_idx, SEEK_SET); + write(fd, nameidx, numlibs * sizeof (struct nameidx)); + + lseek(fd, footer.prebind_base+footer.symcache_idx, SEEK_SET); + write(fd, symcachetab, symcache_cnt * sizeof (struct symcachetab)); + + lseek(fd, footer.prebind_base+footer.pltsymcache_idx, SEEK_SET); + write(fd, pltsymcachetab, pltsymcache_cnt * + sizeof (struct symcachetab)); + + if (verbose > 3) + dump_symcachetab(symcachetab, symcache_cnt, object, 0); + if (verbose > 3) + dump_symcachetab(pltsymcachetab, pltsymcache_cnt, object, 0); + + if (nfixup != 0) { + lseek(fd, footer.prebind_base+footer.fixup_idx, SEEK_SET); + write(fd, fixuptab, 2*nfixup * sizeof(u_int32_t)); + lseek(fd, footer.prebind_base+footer.fixupcnt_idx, SEEK_SET); + write(fd, fixupcnt, 2*nfixup * sizeof(u_int32_t)); + for (i = 0; i < 2*nfixup; i++) { + lseek(fd, footer.prebind_base+fixuptab[i], + SEEK_SET); + write(fd, fixup[i], fixupcnt[i] * sizeof(struct fixup)); + } + + lseek(fd, footer.prebind_base+footer.libmap_idx, SEEK_SET); + write(fd, maptab, nfixup * sizeof(u_int32_t)); + for (i = 0; i < nfixup; i++) { + lseek(fd, footer.prebind_base+maptab[i], + SEEK_SET); + write(fd, libmap[i], libmapcnt[i] * sizeof(u_int32_t)); + } + } + lseek(fd, footer.prebind_base+footer.nametab_idx, SEEK_SET); + write(fd, nametab, nametablen); + lseek(fd, footer.prebind_base+footer_offset, SEEK_SET); + write(fd, &footer, sizeof (struct prebind_footer)); + + if (fstat(fd, &ifstat) == -1) { + perror(object->load_name); + exit(10); + } + prebind_blocks += ifstat.st_blocks; /* add new size */ + if (nfixup != 0) { + elf_fixup_prog_load(fd, &footer, object); + + free(fixuptab); + free(maptab); + } + + if (verbose > 0) + printf("%s: prebind info %d bytes old size %lld, growth %f\n", + object->load_name, footer.prebind_size, footer.orig_size, + (double)(footer.prebind_size) / footer.orig_size); + + if (verbose > 1) + elf_dump_footer(&footer); + + close (fd); + return 0; +} +void +elf_fixup_prog_load(int fd, struct prebind_footer *footer, + struct elf_object *object) +{ + void *buf; + Elf_Ehdr *ehdr; + Elf_Phdr *phdr; + Elf_Phdr phdr_empty; + int loadsection; + + buf = mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_FILE | MAP_SHARED, + fd, 0); + if (buf == MAP_FAILED) { + printf("%s: cannot mmap for write\n", object->load_name); + return; + } + + ehdr = (Elf_Ehdr *) buf; + phdr = (Elf_Phdr *)((char *)buf + ehdr->e_phoff); + + for (loadsection = 0; loadsection < ehdr->e_phnum; loadsection++) { + if (phdr[loadsection].p_type == PT_LOAD) + break; + } + + /* verify that extra slot is empty */ + bzero(&phdr_empty, sizeof(phdr_empty)); + if (bcmp(&phdr[ehdr->e_phnum], &phdr_empty, sizeof(phdr_empty)) != 0) { + printf("extra slot not empty\n"); + goto done; + } + phdr[ehdr->e_phnum].p_type = PT_LOAD; + phdr[ehdr->e_phnum].p_flags = PF_R | 0x08000000; + phdr[ehdr->e_phnum].p_offset = footer->prebind_base; + phdr[ehdr->e_phnum].p_vaddr = footer->prebind_base | 0x80000000; + phdr[ehdr->e_phnum].p_paddr = footer->prebind_base | 0x40000000; + phdr[ehdr->e_phnum].p_filesz = footer->prebind_size; + phdr[ehdr->e_phnum].p_memsz = footer->prebind_size; + phdr[ehdr->e_phnum].p_align = phdr[loadsection].p_align; + ehdr->e_phnum++; + +done: + msync(buf, 8192, MS_SYNC); + munmap(buf, 8192); +} + +void +elf_clear_prog_load(int fd, struct elf_object *object) +{ + void *buf; + Elf_Ehdr *ehdr; + Elf_Phdr *phdr; + Elf_Phdr phdr_empty; + int loadsection; + + buf = mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_FILE | MAP_SHARED, + fd, 0); + if (buf == MAP_FAILED) { + printf("%s: cannot mmap for write\n", object->load_name); + return; + } + + ehdr = (Elf_Ehdr *) buf; + phdr = (Elf_Phdr *)((char *)buf + ehdr->e_phoff); + + if (ehdr->e_type != ET_EXEC) { + goto done; + } + + loadsection = ehdr->e_phnum - 1; + if ((phdr[loadsection].p_type != PT_LOAD) || + ((phdr[loadsection].p_flags & 0x08000000) == 0)) { + /* doesn't look like ours */ + printf("mapped, %s id doesn't match %lx %d %d\n", + object->load_name, + (long)(phdr[loadsection].p_vaddr), + phdr[loadsection].p_flags, loadsection); + goto done; + } + + /* verify that extra slot is empty */ + bzero(&phdr[loadsection], sizeof(phdr_empty)); + + ehdr->e_phnum--; + +done: + msync(buf, 8192, MS_SYNC); + munmap(buf, 8192); +} + +#if 0 +void +elf_calc_fixups(struct proglist *pl, struct objlist *ol, int libidx) +{ + int i; + int numfixups; + int objidx; + int prog; + struct symcache_noflag *symcache; + struct elf_object *prog_obj; + struct elf_object *interp; + + objidx = ol->object->dyn.null, + + prog_obj = TAILQ_FIRST(&(pl->curbin_list))->object; + interp = prog_obj->load_object; + prog = prog_obj->dyn.null; + if (verbose > 3) + printf("fixup GOT %s\n", ol->object->load_name); + symcache = objarray[objidx].symcache; + + numfixups = 0; + for (i = 0; i < ol->object->nchains; i++) { + /* + * this assumes if the same object is found, the same + * symbol will be found as well + */ + if (ol->cache[i].obj != symcache[i].obj && + symcache[i].obj != interp) { + numfixups++; + } + } + pl->fixup[2*libidx] = xcalloc(numfixups, sizeof (struct fixup)); + + numfixups = 0; + for (i = 0; i < ol->object->nchains; i++) { + /* + * this assumes if the same object is found, the same + * symbol will be found as well + */ + if (ol->cache[i].obj != NULL && + ol->cache[i].obj != symcache[i].obj) { + struct fixup *f = &(pl->fixup[2*libidx][numfixups]); + f->sym = i; + f->obj_idx = ol->cache[i].obj->dyn.null; + f->sym_idx = ol->cache[i].sym - + ol->cache[i].obj->dyn.symtab; + if (verbose > 3) { + printf("obj %d idx %d targobj %d, sym idx %d\n", + i, + f->sym, f->obj_idx, f->sym_idx); + } + + numfixups++; + } + } + pl->fixupcnt[2*libidx] = numfixups; +#if 0 + printf("prog %s obj %s had %d got fixups\n", prog_obj->load_name, + ol->object->load_name, numfixups); +#endif + + if (verbose > 3) + printf("fixup PLT %s\n", ol->object->load_name); + /* now PLT */ + + symcache = objarray[objidx].pltsymcache; + + numfixups = 0; + for (i = 0; i < ol->object->nchains; i++) { + /* + * this assumes if the same object is found, the same + * symbol will be found as well + */ + if (ol->pltcache[i].obj != symcache[i].obj) { + numfixups++; + } + } + pl->fixup[2*libidx+1] = xcalloc(numfixups, sizeof (struct fixup)); + + numfixups = 0; + for (i = 0; i < ol->object->nchains; i++) { + /* + * this assumes if the same object is found, the same + * symbol will be found as well + */ + if (ol->pltcache[i].obj != symcache[i].obj) { + struct fixup *f = &(pl->fixup[2*libidx+1][numfixups]); + f->sym = i; + f->obj_idx = ol->pltcache[i].obj->dyn.null; + f->sym_idx = ol->pltcache[i].sym - + ol->pltcache[i].obj->dyn.symtab; + if (verbose > 3) { + printf("obj %d idx %d targobj %d, sym idx %d\n", + i, + f->sym, f->obj_idx, f->sym_idx); + } + + numfixups++; + } + } + pl->fixupcnt[2*libidx+1] = numfixups; + + pl->libmap[libidx] = xcalloc( objarray[objidx].numlibs, + sizeof(u_int32_t)); + + for (i = 0; i < objarray[objidx].numlibs; i++) { + pl->libmap[libidx][i] = objarray[objidx].idxtolib[i]; + } +#if 0 + printf("prog %s obj %s had %d plt fixups\n", prog_obj->load_name, + ol->object->load_name, numfixups); +#endif + +} +#endif + +void +elf_add_object(struct elf_object *object, int objtype) +{ + struct objarray_list *newarray; + struct objlist *ol; + ol = xmalloc(sizeof (struct objlist)); + ol->object = object; + if (objtype != OBJTYPE_EXE) + TAILQ_INSERT_TAIL(&library_list, ol, list); + if (objarray_cnt+1 >= objarray_sz) { + objarray_sz += 512; + newarray = realloc(objarray, sizeof (objarray[0]) * + objarray_sz); + if (newarray != NULL) + objarray = newarray; + else { + perror("objarray"); exit(20); } - elf_reloc(ol->object, ol->cache, ol->pltcache); } +#if 0 + printf("adding object %d %s\n", objarray_cnt, object->load_name); +#endif + object->dyn.null = objarray_cnt; /* Major abuse, I know */ + TAILQ_INIT(&(objarray[objarray_cnt].inst_list)); + objarray[objarray_cnt].obj = object; + objarray[objarray_cnt].id0 = arc4random(); + objarray[objarray_cnt].id1 = arc4random(); +#if 1 /* early alloc */ + objarray[objarray_cnt].symcache = xcalloc( + sizeof(struct symcache_noflag), object->nchains); + objarray[objarray_cnt].pltsymcache = xcalloc( + sizeof(struct symcache_noflag), object->nchains); + +#if 0 + if (objarray[i].oprebind_data != NULL) { + copy_oldsymcache(i); + continue; + } +#endif +#endif + objarray[objarray_cnt].oprebind_data = NULL; + objarray[objarray_cnt].proglist = NULL; + objarray[objarray_cnt].numlibs = 0; + objarray_cnt++; + + elf_add_object_curbin_list(object); +} + +void +elf_free_curbin_list(elf_object_t *object) +{ + struct objlist *ol; + int i; + + while (!TAILQ_EMPTY(&(curbin->curbin_list))) { + ol = TAILQ_FIRST(&(curbin->curbin_list)); + TAILQ_REMOVE(&(objarray[ol->object->dyn.null].inst_list), ol, inst_list); + TAILQ_REMOVE(&(curbin->curbin_list), ol, list); + free(ol); + } + + printf("trying to remove %s\n", object->load_name); + for (i = objarray_cnt; i != 0;) { + i--; + printf("obj %s\n", objarray[i].obj->load_name); + if (objarray[i].obj == object) { + printf("found obj at %d max obj %d\n", i, objarray_cnt); + TAILQ_FOREACH(ol, &(curbin->curbin_list), list) { + } + /* XXX - delete references */ + objarray_cnt = i; + break; + } + } +} + +void +elf_print_objarray(void) +{ + int i; + struct objlist *ol; + + printf("loaded objs # %d\n", objarray_cnt); + for (i = 0; i < objarray_cnt; i++) { + printf("%3d: %d obj %s\n", i, (int)objarray[i].obj->dyn.null, + objarray[i].obj->load_name); + TAILQ_FOREACH(ol, &(objarray[i].inst_list), + inst_list) { + printf("\tprog %s\n", ol->load_prog->load_name); +#if 0 + printf("got cache:\n"); + for (j = 0; j < ol->object->nchains; j++) { + if (ol->cache[j].obj != NULL) { + printf("symidx %d: obj %d sym %ld %s\n", + j, (int)ol->cache[j].obj->dyn.null, + ol->cache[j].sym - + ol->cache[j].obj->dyn.symtab, + ol->cache[j].sym->st_name + + ol->cache[j].obj->dyn.strtab + ); + } + } + printf("plt cache:\n"); + for (j = 0; j < ol->object->nchains; j++) { + if (ol->pltcache[j].obj != NULL) { + printf("symidx %d: obj %d sym %ld %s\n", + j, (int)ol->pltcache[j].obj->dyn.null, + ol->pltcache[j].sym - + ol->pltcache[j].obj->dyn.symtab, + ol->pltcache[j].sym->st_name + + ol->pltcache[j].obj->dyn.strtab + ); + } + } +#endif + } + } +} + +int +write_txtbusy_file(char *name) +{ + char *prebind_name; + int fd; + int oldfd; + int err; + struct stat sb; + void *buf; + size_t len, wlen; + + err = lstat(name, &sb); /* get mode of old file (preserve mode) */ + if (err != 0) + return -1; /* stat shouldn't fail but if it does */ + + /* pick a better filename (pulling apart string?) */ + err = asprintf(&prebind_name, "%s%s", name, ".prebXXXXXXXXXX"); + if (err == -1) { + /* fail */ + exit (10); /* bail on memory failure */ + } + mkstemp(prebind_name); + + /* allocate a 256k buffer to copy the file */ +#define BUFSZ (256 * 1024) + buf = xmalloc(BUFSZ); + + fd = open(prebind_name, O_RDWR|O_CREAT|O_TRUNC, sb.st_mode); + oldfd = open(name, O_RDONLY); + while ((len = read(oldfd, buf, BUFSZ)) > 0) { + wlen = write(fd, buf, len); + if (wlen != len) { + /* write failed */ + close(fd); + close(oldfd); + unlink(prebind_name); + free(buf); + return -1; + } + } + + /* this mode is used above, but is modified by umask */ + chmod (prebind_name, sb.st_mode); + close(oldfd); + unlink(name); + rename (prebind_name, name); + free (buf); + + return fd; +} + +void +elf_load_existing_prebind(struct elf_object *object, int fd) +{ + struct prebind_footer footer; + void *prebind_data; + + lseek(fd, -((off_t)sizeof(struct prebind_footer)), SEEK_END); + read(fd, &footer, sizeof(struct prebind_footer)); + + if (footer.bind_id[0] != BIND_ID0 || + footer.bind_id[1] != BIND_ID1 || + footer.bind_id[2] != BIND_ID2 || + footer.bind_id[3] != BIND_ID3) { + return; + } + + prebind_data = mmap(0, footer.prebind_size, PROT_READ, + MAP_FILE, fd, footer.prebind_base); + objarray[object->dyn.null].oprebind_data = prebind_data; + objarray[object->dyn.null].id0 = footer.id0; + objarray[object->dyn.null].id1 = footer.id1; +} +void +copy_oldsymcache(int objidx) +{ + void *prebind_map; + struct prebind_footer *footer; + struct elf_object *object; + struct elf_object *tobj; + struct symcache_noflag *tcache; + struct symcachetab *symcache; + int i, j; + int found; + char *c; + u_int32_t offset; + u_int32_t *poffset; + struct nameidx *nameidx; + char *nametab; + int *idxtolib; + + + object = objarray[objidx].obj; + + prebind_map = objarray[object->dyn.null].oprebind_data; + + poffset = (u_int32_t *)prebind_map; + c = prebind_map; + offset = *poffset; + c += offset; + footer = (void *)c; + + nameidx = prebind_map + footer->nameidx_idx; + nametab = prebind_map + footer->nametab_idx; + + idxtolib = xcalloc(footer->numlibs, sizeof(int)); + found = 0; + for (i = 0; i < footer->numlibs; i++) { + found = 0; + for (j = 0; j < objarray_cnt; j++) { + if (objarray[j].id0 == nameidx[i].id0 && + objarray[j].id1 == nameidx[i].id1) { + found = 1; + idxtolib[i] = j; + if (strcmp(objarray[j].obj->load_name, + &nametab[nameidx[i].name]) != 0) { + printf("warning filename mismatch" + " [%s] [%s]\n", + objarray[j].obj->load_name, + &nametab[nameidx[i].name]); + } + } + } + if (found == 0) + break; + } + if (found == 0) + goto done; + + /* build idxtolibs */ + + tcache = objarray[objidx].symcache; + symcache = prebind_map + footer->symcache_idx; + + for (i = 0; i < footer->symcache_cnt; i++) { + tobj = objarray[idxtolib[symcache[i].obj_idx]].obj; + + tcache[symcache[i].idx].obj = tobj; + tcache[symcache[i].idx].sym = tobj->dyn.symtab + + symcache[i].sym_idx; + } + + tcache = objarray[objidx].pltsymcache; + symcache = prebind_map + footer->pltsymcache_idx; + for (i = 0; i < footer->pltsymcache_cnt; i++) { + tobj = objarray[idxtolib[symcache[i].obj_idx]].obj; + + tcache[symcache[i].idx].obj = tobj; + tcache[symcache[i].idx].sym = tobj->dyn.symtab + + symcache[i].sym_idx; + } +done: + free (idxtolib); + /* munmap(prebind_map, size);*/ +} + +void * +xmalloc(size_t size) +{ + void *ret; + + ret = malloc(size); + if (ret == NULL) { + printf("unable to allocate memory\n"); + exit (20); + } + return ret; +} + +void * +xcalloc(size_t nmemb, size_t size) +{ + void *ret; + + ret = calloc(nmemb, size); + if (ret == NULL) { + printf("unable to allocate memory\n"); + abort(); + exit (20); + } + return ret; } diff --git a/libexec/ld.so/prebind/prebind_struct.h b/libexec/ld.so/prebind/prebind_struct.h index c5533ddc64c..2dfe8478ed6 100644 --- a/libexec/ld.so/prebind/prebind_struct.h +++ b/libexec/ld.so/prebind/prebind_struct.h @@ -1,4 +1,4 @@ -/* $OpenBSD: prebind_struct.h,v 1.3 2006/05/10 23:03:53 drahn Exp $ */ +/* $OpenBSD: prebind_struct.h,v 1.4 2006/05/12 15:12:42 drahn Exp $ */ /* * Copyright (c) 2006 Dale Rahn <drahn@dalerahn.com> * @@ -34,6 +34,7 @@ struct proglist { TAILQ_HEAD(, objlist) curbin_list; struct fixup **fixup; int *fixupcnt; + int *fixupcntalloc; int nobj; u_int32_t **libmap; u_int32_t *libmapcnt; @@ -54,7 +55,6 @@ void elf_print_curbin_list(struct proglist *bin); void elf_print_prog_list (prog_list_ty *prog_list); -/* objarray */ void elf_add_object_curbin_list(struct elf_object *object); void elf_copy_syms(struct symcache_noflag *tcache, @@ -78,6 +78,11 @@ void elf_fixup_prog_load(int fd, struct prebind_footer *footer, void elf_dump_footer(struct prebind_footer *footer); extern int verbose; +extern int64_t prebind_blocks; +extern struct elf_object *load_object; +struct elf_object *elf_lookup_object(const char *name); +struct elf_object * load_file(const char *filename, int objtype); + void elf_load_existing_prebind(struct elf_object *object, int fd); void *xmalloc(size_t); |