summaryrefslogtreecommitdiff
path: root/libexec/ld.so/ldconfig/prebind.c
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/ld.so/ldconfig/prebind.c')
-rw-r--r--libexec/ld.so/ldconfig/prebind.c2164
1 files changed, 2164 insertions, 0 deletions
diff --git a/libexec/ld.so/ldconfig/prebind.c b/libexec/ld.so/ldconfig/prebind.c
new file mode 100644
index 00000000000..6d7af426cb9
--- /dev/null
+++ b/libexec/ld.so/ldconfig/prebind.c
@@ -0,0 +1,2164 @@
+/* $OpenBSD: prebind.c,v 1.1 2006/05/12 23:20:52 deraadt Exp $ */
+/*
+ * Copyright (c) 2006 Dale Rahn <drahn@dalerahn.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#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>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dirent.h>
+#include "resolve.h"
+#include "link.h"
+#include "sod.h"
+#ifndef __mips64__
+#include "machine/reloc.h"
+#endif
+#include "prebind.h"
+
+/* seems to make sense to limit how big of file can be dealt with */
+#define MAX_FILE_SIZE (512 * 1024 * 1024)
+
+char *shstrtab;
+
+/* alpha uses RELOC_JMP_SLOT */
+#ifdef __amd64__
+#define RELOC_JMP_SLOT R_X86_64_JUMP_SLOT
+#endif
+#ifdef __arm__
+#define RELOC_JMP_SLOT R_ARM_JUMP_SLOT
+#endif
+#ifdef __hppa__
+#define RELOC_JMP_SLOT RELOC_IPLT
+#endif
+#ifdef __hppa64__
+#define RELOC_JMP_SLOT RELOC_JMPSLOT
+#endif
+#ifdef __i386__
+#define RELOC_JMP_SLOT RELOC_JUMP_SLOT
+#endif
+#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 */
+#if defined(__sparc__) && !defined(__sparc64__)
+/* ARGH, our sparc/include/reloc.h is wrong (for the moment) */
+#undef RELOC_JMP_SLOT
+#define RELOC_JMP_SLOT 21
+#endif
+
+#include "prebind_struct.h"
+struct proglist *curbin;
+
+obj_list_ty library_list =
+ TAILQ_HEAD_INITIALIZER(library_list);
+
+prog_list_ty prog_list =
+ TAILQ_HEAD_INITIALIZER(prog_list);
+
+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 *prebind_data);
+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 *);
+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,
+ int use_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);
+void elf_init_objarray(void);
+void elf_add_object(struct elf_object *object, int objtype);
+void elf_print_objarray(void);
+void elf_reloc(struct elf_object *object);
+
+struct elf_object * elf_lookup_object(const char *name);
+struct elf_object * elf_lookup_object_devino(dev_t dev, ino_t inode,
+ int objtype);
+void elf_free_curbin_list(struct elf_object *obj);
+void elf_resolve_curbin(void);
+struct proglist *elf_newbin(void);
+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);
+
+void elf_fixup_prog_load(int fd, struct prebind_footer *footer,
+ struct elf_object *object);
+void elf_clear_prog_load(int fd, struct elf_object *object);
+
+void
+elf_find_symbol_rel(const char *s, struct elf_object *object,
+ Elf_Rel *rel, struct symcache_noflag *symcache,
+ struct symcache_noflag *pltsymcache);
+
+void
+elf_find_symbol_rela(const char *s, struct elf_object *object,
+ Elf_RelA *rela, struct symcache_noflag *symcache,
+ struct symcache_noflag *pltsymcache);
+
+int elf_find_symbol_obj(elf_object_t *object, const char *name,
+ unsigned long hash, int flags, const Elf_Sym **this,
+ const Elf_Sym **weak_sym, elf_object_t **weak_object);
+
+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);
+
+int
+prebind(char **argv)
+{
+ int i;
+
+ elf_init_objarray();
+
+ for (i = 0; argv[i]; 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);
+}
+
+/*
+ * 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)
+{
+ struct stat sb;
+ int ret;
+
+ ret = lstat(name, &sb);
+ if (ret != 0)
+ return;
+ switch (sb.st_mode & S_IFMT) {
+ case S_IFREG:
+ load_exe(name);
+ break;
+ case S_IFDIR:
+ if (verbose > 0)
+ printf("loading dir %s\n", name);
+ load_dir(name);
+ break;
+ default:
+ ; /* links and other files we skip */
+ }
+
+}
+
+/*
+ * 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)
+{
+ struct dirent *dp;
+ struct stat sb;
+ DIR *dirp;
+ char *buf;
+
+ dirp = opendir(name);
+
+ /* if dir failes to open, skip */
+ if (dirp == NULL)
+ return;
+
+ while ((dp = readdir(dirp)) != NULL) {
+ switch (dp->d_type) {
+ case DT_UNKNOWN:
+ /*
+ * NFS will return unknown, since load_file
+ * does stat the file, this just
+ */
+ asprintf(&buf, "%s/%s", name, dp->d_name);
+ lstat(buf, &sb);
+ if (sb.st_mode == S_IFREG)
+ load_exe(buf);
+ free(buf);
+ break;
+ case DT_REG:
+ asprintf(&buf, "%s/%s", name, dp->d_name);
+ load_exe(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)
+{
+ struct elf_object *object;
+ struct elf_object *interp;
+ struct objlist *ol;
+ int fail = 0;
+
+ curbin = elf_newbin();
+ if (verbose > 0)
+ printf("processing %s\n", name);
+ object = load_file(name, OBJTYPE_EXE);
+ if (object != NULL && load_object != NULL &&
+ object->load_object == NULL) {
+ TAILQ_FOREACH(ol, &(curbin->curbin_list), list) {
+ fail = load_obj_needed(ol->object);
+ if (fail != 0)
+ break; /* XXX */
+
+ }
+ if (fail == 0) {
+ interp = load_file(curbin->interp, OBJTYPE_DLO);
+ object->load_object = interp;
+ if (interp == NULL)
+ fail = 1;
+ }
+
+ /* slight abuse of this field */
+
+ if (fail == 0) {
+ objarray[object->dyn.null].proglist = curbin;
+ elf_resolve_curbin();
+ TAILQ_INSERT_TAIL(&prog_list, curbin, list);
+ } else {
+ printf("failed to load %s\n", name);
+ elf_free_curbin_list(object);
+ free(curbin);
+ }
+ if (load_object != NULL) {
+ load_object = NULL;
+ }
+ } else {
+ 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)
+{
+ struct elf_object *obj = NULL;
+ int fd = -1, i, note_found;
+ struct stat ifstat;
+ void *buf = NULL;
+ Elf_Ehdr *ehdr;
+ Elf_Shdr *shdr;
+ Elf_Phdr *phdr;
+ char *pexe;
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ perror(filename);
+ goto done;
+ }
+
+ if (fstat(fd, &ifstat) == -1) {
+ perror(filename);
+ goto done;
+ }
+
+ if ((ifstat.st_mode & S_IFMT) != S_IFREG)
+ goto done;
+
+ if (ifstat.st_size < sizeof (Elf_Ehdr))
+ goto done;
+
+ obj = elf_lookup_object_devino(ifstat.st_dev, ifstat.st_ino, objtype);
+ if (obj != NULL)
+ goto done;
+
+ buf = mmap(NULL, ifstat.st_size, PROT_READ, MAP_FILE | MAP_SHARED,
+ fd, 0);
+ if (buf == MAP_FAILED) {
+ printf("%s: cannot mmap\n", filename);
+ goto done;
+ }
+
+ ehdr = (Elf_Ehdr *)buf;
+
+ if (IS_ELF(*ehdr) == 0)
+ goto done;
+
+ if (ehdr->e_machine != ELF_TARG_MACH) {
+ if (verbose > 0)
+ printf("%s: wrong arch\n", filename);
+ goto done;
+ }
+
+ if (objtype == OBJTYPE_EXE) {
+ if (ehdr->e_type != ET_EXEC)
+ goto done;
+
+ note_found = 0;
+
+ phdr = (Elf_Phdr *)((char *)buf + ehdr->e_phoff);
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ if (phdr[i].p_type == PT_NOTE) {
+ note_found = elf_check_note(buf,&phdr[i]);
+ break;
+ }
+ }
+ if (note_found == 0)
+ goto done; /* no OpenBSD note found */
+ }
+
+ if ((objtype == OBJTYPE_LIB || objtype == OBJTYPE_DLO) &&
+ (ehdr->e_type != ET_DYN))
+ goto done;
+
+ pexe = buf;
+ if (ehdr->e_shstrndx == 0)
+ goto done;
+
+ shdr = (Elf_Shdr *)(pexe + ehdr->e_shoff +
+ (ehdr->e_shstrndx * ehdr->e_shentsize));
+
+ shstrtab = (char *)(pexe + shdr->sh_offset);
+
+ obj = elf_load_object(pexe, filename);
+
+ munmap(buf, ifstat.st_size);
+ buf = NULL;
+
+ if (obj != NULL) {
+ obj->obj_type = objtype;
+
+ obj->dev = ifstat.st_dev;
+ obj->inode = ifstat.st_ino;
+ if (load_object == NULL)
+ load_object = obj;
+
+ elf_add_object(obj, objtype);
+
+#ifdef DEBUG1
+ dump_info(obj);
+#endif
+ }
+ if ((objtype == OBJTYPE_LIB || objtype == OBJTYPE_DLO) &&
+ merge == 1) {
+ /*
+ * 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);
+ 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)
+{
+ Elf_Ehdr *ehdr;
+ u_long address;
+ u_int *pint;
+ char *osname;
+
+ ehdr = (Elf_Ehdr *)buf;
+ address = phdr->p_offset;
+ pint = (u_int *)((char *)buf + address);
+ osname = (char *)buf + address + sizeof(*pint) * 3;
+
+ if (pint[0] == 8 /* OpenBSD\0 */ &&
+ pint[1] == 4 /* ??? */ &&
+ pint[2] == 1 /* type_osversion */ &&
+ strcmp("OpenBSD", osname) == 0)
+ return 1;
+
+ return 0;
+}
+
+struct elf_object *
+elf_load_object(void *pexe, const char *name)
+{
+ struct elf_object *object;
+ Elf_Dyn *dynp = NULL, *odynp;
+ Elf_Ehdr *ehdr;
+ Elf_Phdr *phdr;
+ const Elf_Sym *symt;
+ const char *strt;
+ Elf_Addr loff;
+ Elf_Word *needed_list;
+ int needed_cnt = 0, i;
+
+ object = calloc(1, sizeof (struct elf_object));
+ if (object == NULL) {
+ printf("unable to allocate object for %s\n", name);
+ exit(10);
+ }
+ ehdr = pexe;
+ loff = (Elf_Addr)pexe;
+
+ object->load_addr = 0;
+ object->load_name = strdup(name);
+
+ phdr = (Elf_Phdr *)((char *)pexe + ehdr->e_phoff);
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ switch (phdr[i].p_type) {
+ case PT_DYNAMIC:
+ dynp = (Elf_Dyn *)(phdr[i].p_offset);
+ break;
+ case PT_INTERP:
+ /* XXX can only occur in programs */
+ curbin->interp = strdup((char *)((char *)pexe +
+ phdr[i].p_offset));
+ default:
+ break;
+ }
+ }
+
+ if (dynp == 0) {
+ free(object);
+ return NULL; /* not a dynamic binary */
+ }
+
+ dynp = (Elf_Dyn *)((unsigned long)dynp + loff);
+ odynp = dynp;
+ while (dynp->d_tag != DT_NULL) {
+ if (dynp->d_tag < DT_NUM)
+ object->Dyn.info[dynp->d_tag] = dynp->d_un.d_val;
+ else if (dynp->d_tag >= DT_LOPROC &&
+ dynp->d_tag < DT_LOPROC + DT_PROCNUM)
+ object->Dyn.info[dynp->d_tag + DT_NUM - DT_LOPROC] =
+ dynp->d_un.d_val;
+ if (dynp->d_tag == DT_TEXTREL)
+ object->dyn.textrel = 1;
+ if (dynp->d_tag == DT_SYMBOLIC)
+ object->dyn.symbolic = 1;
+ if (dynp->d_tag == DT_BIND_NOW)
+ object->obj_flags = RTLD_NOW;
+ if (dynp->d_tag == DT_NEEDED)
+ needed_cnt++;
+
+ dynp++;
+ }
+
+ needed_list = calloc((needed_cnt + 1), (sizeof (Elf_Word)));
+ if (needed_list == NULL) {
+ printf("unable to allocate needed_list for %s\n", name);
+ exit(10);
+ }
+ needed_list[needed_cnt] = 0;
+ for (dynp = odynp, i = 0; dynp->d_tag != DT_NULL; dynp++) {
+ if (dynp->d_tag == DT_NEEDED) {
+ needed_list[i] = dynp->d_un.d_val;
+ i++;
+ }
+ }
+
+ if (object->Dyn.info[DT_HASH])
+ map_to_virt(phdr, ehdr, loff, &object->Dyn.info[DT_HASH]);
+ if (object->Dyn.info[DT_STRTAB])
+ map_to_virt(phdr, ehdr, loff, &object->Dyn.info[DT_STRTAB]);
+ if (object->Dyn.info[DT_SYMTAB])
+ map_to_virt(phdr, ehdr, loff, &object->Dyn.info[DT_SYMTAB]);
+
+ if (object->Dyn.info[DT_RELA])
+ map_to_virt(phdr, ehdr, loff, &object->Dyn.info[DT_RELA]);
+ if (object->Dyn.info[DT_RPATH])
+ object->Dyn.info[DT_RPATH] += object->Dyn.info[DT_STRTAB];
+ if (object->Dyn.info[DT_REL])
+ map_to_virt(phdr, ehdr, loff, &object->Dyn.info[DT_REL]);
+ if (object->Dyn.info[DT_JMPREL])
+ map_to_virt(phdr, ehdr, loff, &object->Dyn.info[DT_JMPREL]);
+
+ symt = object->dyn.symtab;
+ strt = object->dyn.strtab;
+
+ {
+ Elf_Sym *sym;
+ char *str;
+ Elf_Rel *rel;
+ Elf_RelA *rela;
+ Elf_Addr *hash;
+ Elf_Word *hashtab;
+ void *plt;
+ size_t hashsz;
+
+ if (object->Dyn.info[DT_HASH] != 0) {
+ hash = object->dyn.hash;
+ hashtab = (void *)hash;
+ object->nbuckets = hashtab[0];
+ object->nchains = hashtab[1];
+ hashsz = (2 + object->nbuckets + object->nchains) *
+ sizeof (Elf_Word);
+ hash = malloc(hashsz);
+ if (hash == NULL) {
+ printf("unable to allocate hash for %s\n",
+ name);
+ exit(10);
+ }
+ bcopy (object->dyn.hash, hash, hashsz);
+ object->dyn.hash = hash;
+ object->buckets = ((Elf_Word *)hash + 2);
+ object->chains = object->buckets + object->nbuckets;
+ }
+
+ str = malloc(object->dyn.strsz);
+ if (str == NULL) {
+ printf("unable to allocate strtab for %s\n",
+ name);
+ exit(10);
+ }
+ bcopy(object->dyn.strtab, str, object->dyn.strsz);
+ object->dyn.strtab = str;
+ strt = str;
+
+ sym = malloc(object->nchains * sizeof(Elf_Sym));
+ if (sym == NULL) {
+ printf("unable to allocate symtab for %s\n",
+ name);
+ exit(10);
+ }
+ bcopy(object->dyn.symtab, sym,
+ object->nchains * sizeof(Elf_Sym));
+ object->dyn.symtab = sym;
+ symt = sym;
+
+ if (object->dyn.relsz != 0) {
+ rel = malloc(object->dyn.relsz);
+ if (rel == NULL) {
+ printf("unable to allocate rel reloc for %s\n",
+ name);
+ exit(10);
+ }
+ bcopy(object->dyn.rel, rel, object->dyn.relsz);
+ object->dyn.rel = rel;
+ } else {
+ object->dyn.rel = NULL;
+ }
+ if (object->dyn.relasz != 0) {
+ rela = malloc(object->dyn.relasz);
+ if (rela == NULL) {
+ printf("unable to allocate rela reloc for %s\n",
+ name);
+ exit(10);
+ }
+ bcopy(object->dyn.rela, rela, object->dyn.relasz);
+ object->dyn.rela = rela;
+ } else {
+ object->dyn.rela = NULL;
+ }
+ if (object->dyn.pltrelsz != 0) {
+ plt = malloc(object->dyn.pltrelsz);
+ if (plt == NULL) {
+ printf("unable to allocate plt reloc for %s\n",
+ name);
+ exit(10);
+ }
+ bcopy((void*)object->dyn.jmprel, plt,
+ object->dyn.pltrelsz);
+ object->dyn.jmprel = (long)plt;
+ } else {
+ object->dyn.jmprel = NULL;
+ }
+ if (object->dyn.rpath != NULL){
+ object->dyn.rpath = strdup(object->dyn.rpath);
+ if (object->dyn.rpath == NULL) {
+ printf("unable to allocate rpath for %s\n",
+ name);
+ exit(10);
+ }
+ }
+ object->dyn.needed = (Elf_Addr)needed_list;
+ }
+
+#ifdef DEBUG1
+ dump_info(object);
+#endif
+ return 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);
+ if (object->dyn.rel != NULL)
+ free(object->dyn.rel);
+ if (object->dyn.rela != NULL)
+ free(object->dyn.rela);
+ if (object->dyn.rpath != NULL)
+ free((void *)object->dyn.rpath);
+ free(object);
+}
+
+/*
+ * translate an object address into a file offset for the
+ * file assuming that the file is mapped at base.
+ */
+void
+map_to_virt(Elf_Phdr *phdr, Elf_Ehdr *ehdr, Elf_Addr base, u_long *vaddr)
+{
+ int i;
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ switch (phdr[i].p_type) {
+ case PT_LOAD:
+ if (phdr[i].p_vaddr > *vaddr)
+ continue;
+ if (phdr[i].p_vaddr + phdr[i].p_memsz < *vaddr)
+ continue;
+#ifdef DEBUG1
+ printf("input address %lx translated to ", *vaddr);
+#endif
+ *vaddr += phdr[i].p_offset - phdr[i].p_vaddr + base;
+#ifdef DEBUG1
+ printf("%lx, base %lx %lx %llx\n", *vaddr, base,
+ phdr[i].p_vaddr, phdr[i].p_offset );
+#endif
+
+ default:
+ break;
+ }
+ }
+}
+
+/*
+ * 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)
+{
+ int i;
+ Elf_Word *needed_list;
+ int err;
+
+ needed_list = (Elf_Word *)object->dyn.needed;
+ for (i = 0; needed_list[i] != NULL; i++) {
+ if (verbose > 1)
+ printf("lib: %s\n", needed_list[i] +
+ object->dyn.strtab);
+ err = load_lib(needed_list[i] + object->dyn.strtab, object);
+ if (err) {
+ printf("failed to load lib %s\n",
+ needed_list[i] + object->dyn.strtab);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * allocate a proglist entry for a new binary
+ * so that it is available for libraries to reference
+ */
+struct proglist *
+elf_newbin(void)
+{
+ struct proglist *proglist;
+ proglist = malloc(sizeof (struct proglist));
+ if (proglist == NULL) {
+ printf("unable to allocate proglist\n");
+ exit(10);
+ }
+ proglist->fixup = NULL;
+ TAILQ_INIT(&(proglist->curbin_list));
+ return proglist;
+}
+
+/*
+ * Copy the contents of a libraries symbol cache instance into
+ * the 'global' symbol cache for that library
+ * this will currently resolve conflicts between mismatched
+ * libraries by flagging any mismatches as invalid
+ * which will cause all programs to generate a fixup
+ * It probably would be interesting to modify this to keep the most
+ * common entry as a library cache, and only have a fixup in programs
+ * where the symbol is overridden.
+ * This is run once each for the (got)symcache and pltsymcache
+ */
+
+struct elf_object badobj_store;
+struct elf_object *badobj = &badobj_store;
+
+/*
+ * copy the symbols found in a library symcache to the 'master/common'
+ * 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)
+ */
+void
+elf_copy_syms(struct symcache_noflag *tcache, struct symcache_noflag *scache,
+ struct elf_object *obj, struct elf_object *prog, int nsyms)
+{
+ int i;
+ int lib_prog_ref;
+ for (i = 0; i < nsyms; i++) {
+ if (scache[i].obj == NULL)
+ continue;
+
+ 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: "
+ "obj %d: sym %ld %s "
+ "nobj %s\n",
+ i, (int)scache[i].obj->dyn.null,
+ scache[i].sym -
+ scache[i].obj->dyn.symtab,
+ scache[i].sym->st_name +
+ scache[i].obj->dyn.strtab,
+ scache[i].obj->load_name);
+ }
+
+ /*
+ * 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 (scache[i].obj == obj) {
+ tcache[i].obj = scache[i].obj;
+ tcache[i].sym = scache[i].sym;
+ } else if (tcache[i].obj == obj) {
+ /* no change necessary */
+ } else {
+ tcache[i].obj = badobj;
+ tcache[i].sym = NULL;
+ }
+ }
+ } else {
+ if (scache[i].obj != prog) {
+ tcache[i].obj = scache[i].obj;
+ tcache[i].sym = scache[i].sym;
+ }
+ }
+ }
+}
+
+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 (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 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) {
+ tcache[idx].obj = ref_obj;
+ tcache[idx].sym = ref_sym;
+ } else {
+ add_fixup_prog(prog, obj, idx, ref_obj,
+ ref_sym, flags);
+ }
+ }
+}
+
+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) {
+ 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)
+{
+ struct objlist *ol;
+ TAILQ_FOREACH(ol, &(curbin->curbin_list), list) {
+ if (strcmp (name, ol->object->load_name) == 0) {
+ return ol->object;
+ }
+ }
+ TAILQ_FOREACH(ol, &library_list, list) {
+ if (strcmp (name, ol->object->load_name) == 0) {
+ elf_add_object_curbin_list(ol->object);
+ return ol->object;
+ }
+ }
+ return NULL;
+}
+
+struct elf_object *
+elf_lookup_object_devino(dev_t dev, ino_t inode, int objtype)
+{
+ struct objlist *ol;
+ TAILQ_FOREACH(ol, &(curbin->curbin_list), list) {
+ if (ol->object->dev == dev &&
+ ol->object->inode == inode) {
+ if (ol->object->obj_type != objtype)
+ return NULL;
+ return ol->object;
+ }
+ }
+ TAILQ_FOREACH(ol, &library_list, list) {
+ if (ol->object->dev == dev &&
+ ol->object->inode == inode) {
+ if (ol->object->obj_type != objtype)
+ return NULL;
+ if (objtype != OBJTYPE_EXE)
+ elf_add_object_curbin_list(ol->object);
+ return ol->object;
+ }
+ }
+ return NULL;
+}
+
+void
+elf_find_symbol_rel(const char *name, struct elf_object *object,
+ Elf_Rel *rel, struct symcache_noflag *symcache,
+ struct symcache_noflag *pltsymcache)
+{
+ struct objlist *ol;
+ unsigned long h = 0;
+ const char *p = name;
+ const Elf_Sym *sym, *ref_sym = NULL;
+ const Elf_Sym *weak_sym = NULL;
+ struct elf_object *weak_obj = NULL;
+ int flags = 0;
+ int found = 0;
+ int type, idx;
+ struct elf_object *ref_object = NULL;
+
+ sym = object->dyn.symtab + ELF_R_SYM(rel->r_info);
+
+ while (*p) {
+ unsigned long g;
+ h = (h << 4) + *p++;
+ if ((g = h & 0xf0000000))
+ h ^= g >> 24;
+ h &= ~g;
+ }
+
+ type = ELF_R_TYPE(rel->r_info);
+ flags = SYM_SEARCH_ALL|SYM_WARNNOTFOUND;
+ if (type == RELOC_JMP_SLOT)
+ flags |= SYM_PLT;
+
+ TAILQ_FOREACH(ol, &(curbin->curbin_list), list) {
+ found = elf_find_symbol_obj(ol->object, name, h, flags, &sym,
+ &weak_sym, &weak_obj);
+ if (found) {
+ ref_object = ol->object;
+ break;
+ }
+
+ }
+ if (found) {
+ ref_object = ol->object;
+ ref_sym = sym;
+ } else if (weak_obj != NULL) {
+ found = 1;
+ ref_object = weak_obj;
+ ref_sym = weak_sym;
+ }
+ if (found == 1) {
+ idx = ELF_R_SYM(rel->r_info);
+ if (flags & SYM_PLT) {
+ pltsymcache[idx].obj = ref_object;
+ pltsymcache[idx].sym = ref_sym;
+ } else {
+ symcache[idx].obj = ref_object;
+ symcache[idx].sym = ref_sym;
+ }
+ } else {
+ printf("symbol not found %s\n", name);
+ }
+}
+
+void
+elf_find_symbol_rela(const char *name, struct elf_object *object,
+ Elf_RelA *rela, struct symcache_noflag *symcache,
+ struct symcache_noflag *pltsymcache)
+{
+ struct objlist *ol;
+ unsigned long h = 0;
+ const char *p = name;
+ const Elf_Sym *sym, *ref_sym = NULL;
+ const Elf_Sym *weak_sym = NULL;
+ struct elf_object *weak_obj = NULL;
+ int flags = 0;
+ int found = 0;
+ int type, idx;
+ struct elf_object *ref_object = NULL;
+
+ sym = object->dyn.symtab + ELF_R_SYM(rela->r_info);
+
+ while (*p) {
+ unsigned long g;
+ h = (h << 4) + *p++;
+ if ((g = h & 0xf0000000))
+ h ^= g >> 24;
+ h &= ~g;
+ }
+
+ type = ELF_R_TYPE(rela->r_info);
+ flags = SYM_SEARCH_ALL|SYM_WARNNOTFOUND;
+ if (type == RELOC_JMP_SLOT)
+ flags |= SYM_PLT;
+
+ TAILQ_FOREACH(ol, &(curbin->curbin_list), list) {
+
+// printf("searching sym [%s] typ %d in obj %s\n", name, type, ol->object->load_name);
+ found = elf_find_symbol_obj(ol->object, name, h, flags, &sym,
+ &weak_sym, &weak_obj);
+ if (found) {
+ ref_object = ol->object;
+ break;
+ }
+
+ }
+ if (found) {
+ ref_object = ol->object;
+ ref_sym = sym;
+ } else if (weak_obj != NULL) {
+ found = 1;
+ ref_object = weak_obj;
+ ref_sym = weak_sym;
+ }
+ if (found == 1) {
+ idx = ELF_R_SYM(rela->r_info);
+ if (flags & SYM_PLT) {
+ pltsymcache[idx].obj = ref_object;
+ pltsymcache[idx].sym = ref_sym;
+ } else {
+ symcache[idx].obj = ref_object;
+ symcache[idx].sym = ref_sym;
+ }
+ } else {
+ printf("symbol not found %s\n", name);
+ }
+}
+
+int
+elf_find_symbol_obj(elf_object_t *object, const char *name, unsigned long hash,
+ int flags, const Elf_Sym **this, const Elf_Sym **weak_sym,
+ elf_object_t **weak_object)
+{
+ const Elf_Sym *symt = object->dyn.symtab;
+ const char *strt = object->dyn.strtab;
+ long si;
+ const char *symn;
+
+ for (si = object->buckets[hash % object->nbuckets];
+ si != STN_UNDEF; si = object->chains[si]) {
+ const Elf_Sym *sym = symt + si;
+
+ if (sym->st_value == 0)
+ continue;
+
+ if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE &&
+ ELF_ST_TYPE(sym->st_info) != STT_OBJECT &&
+ ELF_ST_TYPE(sym->st_info) != STT_FUNC)
+ continue;
+
+ symn = strt + sym->st_name;
+ if (sym != *this && strcmp(symn, name))
+ continue;
+
+ /* allow this symbol if we are referring to a function
+ * which has a value, even if section is UNDEF.
+ * this allows &func to refer to PLT as per the
+ * ELF spec. st_value is checked above.
+ * if flags has SYM_PLT set, we must have actual
+ * symbol, so this symbol is skipped.
+ */
+ if (sym->st_shndx == SHN_UNDEF) {
+ if ((flags & SYM_PLT) || sym->st_value == 0 ||
+ ELF_ST_TYPE(sym->st_info) != STT_FUNC)
+ continue;
+ }
+
+ if (ELF_ST_BIND(sym->st_info) == STB_GLOBAL) {
+ *this = sym;
+ return 1;
+ } else if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
+ if (!*weak_sym) {
+ *weak_sym = sym;
+ *weak_object = object;
+ }
+ }
+ }
+ return 0;
+}
+
+void
+elf_reloc(struct elf_object *object)
+{
+ const Elf_Sym *sym;
+ Elf_Rel *rel;
+ Elf_RelA *rela;
+ int numrel;
+ int numrela;
+ int i;
+ struct symcache_noflag *symcache;
+ struct symcache_noflag *pltsymcache;
+
+ numrel = object->dyn.relsz / sizeof(Elf_Rel);
+#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;
+ sym = object->dyn.symtab + ELF_R_SYM(rel[i].r_info);
+
+ /* hppa has entries without names, skip them */
+ if (sym->st_name == 0)
+ continue;
+
+ s = (ELF_R_SYM(rel[i].r_info) == 0) ? "<rel>" :
+ object->dyn.strtab + sym->st_name;
+#ifdef DEBUG1
+ printf("%d: %x sym %x %s type %d\n", i, rel[i].r_offset,
+ 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) {
+ elf_find_symbol_rel(s, object, &rel[i],
+ symcache, pltsymcache);
+ }
+ }
+ if (numrel) {
+ numrel = object->dyn.pltrelsz / sizeof(Elf_Rel);
+ rel = (Elf_Rel *)(object->Dyn.info[DT_JMPREL]);
+#ifdef DEBUG1
+ printf("rel plt relocations: %d\n", numrel);
+#endif
+ for (i = 0; i < numrel; i++) {
+ const char *s;
+ sym = object->dyn.symtab + ELF_R_SYM(rel[i].r_info);
+
+ /* hppa has entries without names, skip them */
+ if (sym->st_name == 0)
+ continue;
+
+ s = (ELF_R_SYM(rel[i].r_info) == 0) ? "<rel>" :
+ object->dyn.strtab + sym->st_name;
+#ifdef DEBUG1
+ printf("%d: %x sym %d %s type %d\n", i, rel[i].r_offset,
+ 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) {
+ elf_find_symbol_rel(s, object, &rel[i],
+ symcache, pltsymcache);
+ }
+ }
+ }
+
+ numrela = object->dyn.relasz / sizeof(Elf_RelA);
+#ifdef DEBUG1
+ printf("rela relocations: %d\n", numrela);
+#endif
+ rela = object->dyn.rela;
+ for (i = 0; i < numrela; i++) {
+ const char *s;
+ sym = object->dyn.symtab + ELF_R_SYM(rela[i].r_info);
+
+ /* hppa has entries without names, skip them */
+ if (sym->st_name == 0)
+ continue;
+
+ s = (ELF_R_SYM(rela[i].r_info) == 0) ? "<rel>" :
+ object->dyn.strtab + sym->st_name;
+#ifdef DEBUG1
+ printf("%d: %x sym %x %s type %d\n", i, rela[i].r_offset,
+ 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) {
+ elf_find_symbol_rela(s, object, &rela[i],
+ symcache, pltsymcache);
+ }
+ }
+ if (numrela) {
+ numrela = object->dyn.pltrelsz / sizeof(Elf_RelA);
+#ifdef DEBUG1
+ printf("rela plt relocations: %d\n", numrela);
+#endif
+ rela = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]);
+
+ for (i = 0; i < numrela; i++) {
+ const char *s;
+ sym = object->dyn.symtab + ELF_R_SYM(rela[i].r_info);
+
+ /* hppa has entries without names, skip them */
+ if (sym->st_name == 0)
+ continue;
+
+ s = (ELF_R_SYM(rela[i].r_info) == 0) ? "<rel>" :
+ object->dyn.strtab + sym->st_name;
+#ifdef DEBUG1
+ printf("%d: %x sym %x %s type %d\n", i,
+ rela[i].r_offset,
+ 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) {
+ 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) {
+ 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);
+ }
+}
+
+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;
+
+ 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 numobjs;
+ int err = 0;
+ struct objlist *ol;
+ struct proglist *pl;
+
+ TAILQ_FOREACH(ol, &library_list, list) {
+ 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;
+ }
+
+ TAILQ_FOREACH(pl, &prog_list, list)
+ err += elf_prep_bin_prebind(pl);
+
+ 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);
+ }
+
+ /* 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;
+ 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++;
+ }
+
+ 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);
+ }
+ 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) {
+ for (j = 0; j < objarray[idxtolib[i]].numlibs; j++) {
+ 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)
+{
+ u_int32_t footer_offset, *maptab = NULL;
+ u_int32_t next_start, *fixuptab = NULL;
+ struct prebind_footer footer;
+ struct stat ifstat;
+ off_t base_offset;
+ size_t len;
+ int fd, i;
+
+ /* 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);
+}
+
+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);
+ }
+ }
+ 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();
+
+ objarray[objarray_cnt].symcache = xcalloc(
+ sizeof(struct symcache_noflag), object->nchains);
+ objarray[objarray_cnt].pltsymcache = xcalloc(
+ sizeof(struct symcache_noflag), object->nchains);
+
+ 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);
+ }
+ }
+}
+
+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;
+
+ copy_oldsymcache(object->dyn.null, prebind_data);
+}
+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, found, *idxtolib;
+ char *c, *nametab;
+ u_int32_t offset;
+ u_int32_t *poffset;
+ struct nameidx *nameidx;
+
+ object = objarray[objidx].obj;
+
+ 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);*/
+}