summaryrefslogtreecommitdiff
path: root/libexec/ld.so
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2006-05-03 16:10:53 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2006-05-03 16:10:53 +0000
commitec4b8bbf8212a67706e8bf0d84a933147a5bf89c (patch)
treef06a750d1a5fbec05783cff2a3ba488c9e288a69 /libexec/ld.so
parentb1f9a206d3729c6275222429f2ec0529817fc0b3 (diff)
prebind - how to prelink a binary without throwing security out the window
Prelink fixes the address of libraries making 'return to libc' attacks trival, prebind uses a different method to achieve most of the same gains, however without adding any security conerns. Still under development, now in-tree.
Diffstat (limited to 'libexec/ld.so')
-rw-r--r--libexec/ld.so/Makefile7
-rw-r--r--libexec/ld.so/alpha/ldasm.S9
-rw-r--r--libexec/ld.so/alpha/syscall.h3
-rw-r--r--libexec/ld.so/amd64/ldasm.S3
-rw-r--r--libexec/ld.so/amd64/syscall.h3
-rw-r--r--libexec/ld.so/arm/ldasm.S3
-rw-r--r--libexec/ld.so/arm/syscall.h3
-rw-r--r--libexec/ld.so/dl_prebind.c629
-rw-r--r--libexec/ld.so/dl_prebind.h36
-rw-r--r--libexec/ld.so/hppa/ldasm.S8
-rw-r--r--libexec/ld.so/hppa/rtld_machine.c26
-rw-r--r--libexec/ld.so/hppa/syscall.h3
-rw-r--r--libexec/ld.so/i386/ldasm.S3
-rw-r--r--libexec/ld.so/i386/syscall.h3
-rw-r--r--libexec/ld.so/ld.so.110
-rw-r--r--libexec/ld.so/library.c9
-rw-r--r--libexec/ld.so/library_mquery.c8
-rw-r--r--libexec/ld.so/loader.c27
-rw-r--r--libexec/ld.so/mips64/syscall.h21
-rw-r--r--libexec/ld.so/powerpc/syscall.h24
-rw-r--r--libexec/ld.so/prebind.h64
-rw-r--r--libexec/ld.so/prebind/Makefile18
-rw-r--r--libexec/ld.so/prebind/debug.c154
-rw-r--r--libexec/ld.so/prebind/objarray.c1073
-rw-r--r--libexec/ld.so/prebind/prebind.860
-rw-r--r--libexec/ld.so/prebind/prebind.c1437
-rw-r--r--libexec/ld.so/prebind/prebind_struct.h64
-rw-r--r--libexec/ld.so/prebind/sod.c265
-rw-r--r--libexec/ld.so/prebind_strip/Makefile13
-rw-r--r--libexec/ld.so/prebind_strip/prebind_strip.844
-rw-r--r--libexec/ld.so/prebind_strip/prebind_strip.c125
-rw-r--r--libexec/ld.so/resolve.c15
-rw-r--r--libexec/ld.so/resolve.h4
-rw-r--r--libexec/ld.so/sparc/ldasm.S14
-rw-r--r--libexec/ld.so/sparc/syscall.h3
-rw-r--r--libexec/ld.so/sparc64/ldasm.S10
-rw-r--r--libexec/ld.so/sparc64/syscall.h3
37 files changed, 4172 insertions, 32 deletions
diff --git a/libexec/ld.so/Makefile b/libexec/ld.so/Makefile
index 6e7139e0767..6f8d24692a9 100644
--- a/libexec/ld.so/Makefile
+++ b/libexec/ld.so/Makefile
@@ -1,10 +1,11 @@
-# $OpenBSD: Makefile,v 1.31 2006/05/03 15:48:16 drahn Exp $
+# $OpenBSD: Makefile,v 1.32 2006/05/03 16:10:51 drahn Exp $
-SUBDIR=ldconfig ldd
+SUBDIR=ldconfig ldd prebind prebind_strip
+#SUBDIR+=prebind prebind_strip
VPATH=${.CURDIR}/../../lib/libc/string
SRCS= ldasm.S loader.c resolve.c dlfcn.c dl_printf.c rtld_machine.c
-SRCS+= util.c sod.c strsep.c strtol.c dir.c library_subr.c
+SRCS+= util.c sod.c strsep.c strtol.c dir.c library_subr.c dl_prebind.c
.if (${MACHINE_ARCH} == "i386")
SRCS+= library_mquery.c
.else
diff --git a/libexec/ld.so/alpha/ldasm.S b/libexec/ld.so/alpha/ldasm.S
index e7f0c1b6df8..7de78da3fd0 100644
--- a/libexec/ld.so/alpha/ldasm.S
+++ b/libexec/ld.so/alpha/ldasm.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldasm.S,v 1.16 2004/05/25 15:56:18 deraadt Exp $ */
+/* $OpenBSD: ldasm.S,v 1.17 2006/05/03 16:10:51 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -306,3 +306,10 @@ LEAF_NOPROFILE(_dl_sysctl, 4)
call_pal PAL_OSF1_callsys
RET
END(_dl_sysctl)
+
+LEAF_NOPROFILE(_dl_gettimeofday, 2)
+ ldiq v0, SYS_gettimeofday
+ call_pal PAL_OSF1_callsys
+ RET
+END(_dl_gettimeofday)
+
diff --git a/libexec/ld.so/alpha/syscall.h b/libexec/ld.so/alpha/syscall.h
index 257cde79630..f1161d6c76d 100644
--- a/libexec/ld.so/alpha/syscall.h
+++ b/libexec/ld.so/alpha/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.14 2004/05/25 15:56:18 deraadt Exp $ */
+/* $OpenBSD: syscall.h,v 1.15 2006/05/03 16:10:51 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -53,6 +53,7 @@ int _dl_getdirentries(int, char*, int, long *);
long _dl__syscall(quad_t, ...);
int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
int _dl_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+int _dl_gettimeofday(struct timeval *tp, struct timezone *tzp);
static inline off_t
_dl_lseek(int fildes, off_t offset, int whence)
diff --git a/libexec/ld.so/amd64/ldasm.S b/libexec/ld.so/amd64/ldasm.S
index 6baa706e195..07fdf37fa91 100644
--- a/libexec/ld.so/amd64/ldasm.S
+++ b/libexec/ld.so/amd64/ldasm.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldasm.S,v 1.5 2005/05/04 03:59:24 drahn Exp $ */
+/* $OpenBSD: ldasm.S,v 1.6 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 2002,2004 Dale Rahn
@@ -89,6 +89,7 @@ DL_SYSCALL(issetugid)
DL_SYSCALL(getdirentries)
DL_SYSCALL(mprotect)
DL_SYSCALL(munmap)
+DL_SYSCALL(gettimeofday)
DL_SYSCALL(exit)
DL_SYSCALL2(_syscall,__syscall)
DL_SYSCALL2(sysctl,__sysctl)
diff --git a/libexec/ld.so/amd64/syscall.h b/libexec/ld.so/amd64/syscall.h
index 0656c00f685..0f6a73181b0 100644
--- a/libexec/ld.so/amd64/syscall.h
+++ b/libexec/ld.so/amd64/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.2 2004/02/23 20:52:05 deraadt Exp $ */
+/* $OpenBSD: syscall.h,v 1.3 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -53,6 +53,7 @@ int _dl_fcntl(int, int, ...);
int _dl_getdirentries(int, char*, int, long *);
int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
int _dl_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+int _dl_gettimeofday(struct timeval *tp, struct timezone *tzp);
static inline off_t
_dl_lseek(int fildes, off_t offset, int whence)
diff --git a/libexec/ld.so/arm/ldasm.S b/libexec/ld.so/arm/ldasm.S
index 44b2fa24c3b..6ac18075b04 100644
--- a/libexec/ld.so/arm/ldasm.S
+++ b/libexec/ld.so/arm/ldasm.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldasm.S,v 1.5 2005/10/23 06:04:03 drahn Exp $ */
+/* $OpenBSD: ldasm.S,v 1.6 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 2004 Dale Rahn
@@ -112,6 +112,7 @@ DL_SYSCALL(write)
DL_SYSCALL(stat)
DL_SYSCALL(fstat)
DL_SYSCALL(fcntl)
+DL_SYSCALL(gettimeofday)
DL_SYSCALL2(sysctl,__sysctl)
DL_SYSCALL(getdirentries)
diff --git a/libexec/ld.so/arm/syscall.h b/libexec/ld.so/arm/syscall.h
index b654f54dd84..74cd62d828f 100644
--- a/libexec/ld.so/arm/syscall.h
+++ b/libexec/ld.so/arm/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.2 2004/05/25 15:56:18 deraadt Exp $ */
+/* $OpenBSD: syscall.h,v 1.3 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -53,6 +53,7 @@ int _dl_fcntl(int, int, ...);
int _dl_getdirentries(int, char*, int, long *);
int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
int _dl_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+int _dl_gettimeofday(struct timeval *tp, struct timezone *tzp);
static inline off_t
_dl_lseek(int fildes, off_t offset, int whence)
diff --git a/libexec/ld.so/dl_prebind.c b/libexec/ld.so/dl_prebind.c
new file mode 100644
index 00000000000..eacd219d1a1
--- /dev/null
+++ b/libexec/ld.so/dl_prebind.c
@@ -0,0 +1,629 @@
+/* $OpenBSD: dl_prebind.c,v 1.1 2006/05/03 16:10:51 drahn 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/mman.h>
+#include <sys/exec.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <nlist.h>
+#include <string.h>
+#include <link.h>
+#include <dlfcn.h>
+#include <unistd.h>
+
+#include "syscall.h"
+#include "archdep.h"
+#include "resolve.h"
+#include "sod.h"
+#include "stdlib.h"
+#include "dl_prebind.h"
+
+void elf_dump_footer(struct prebind_footer *footer);
+void dump_prelink(Elf_Addr base, u_long size);
+void prebind_dump_footer(struct prebind_footer *footer, char *file);
+void prebind_dump_symcache(struct symcachetab *symcachetab, u_int32_t cnt);
+void prebind_dump_nameidx(struct nameidx *nameidx, u_int32_t numblibs,
+ char *nametab);
+void prebind_dump_fixup(struct fixup *fixup, u_int32_t numfixups);
+void prebind_dump_libmap(u_int32_t *libmap, u_int32_t numlibs);
+struct prebind_footer *_dl_prebind_data_to_footer(void *data);
+
+void *_dl_prog_prebind_map;
+struct prebind_footer *prog_footer;
+extern char *_dl_noprebind;
+extern char *_dl_prebind_validate;
+
+int _dl_prebind_match_failed; /* = 0 */
+
+char *prebind_bind_now = "prebind";
+
+struct prebind_footer *
+_dl_prebind_data_to_footer(void *prebind_data)
+{
+ u_int32_t *poffset;
+ u_int32_t offset;
+ char *c;
+ struct prebind_footer *footer;
+
+ poffset = prebind_data;
+ c = prebind_data;
+ offset = *poffset;
+ c += offset;
+ footer = (void *)c;
+
+ return footer;
+}
+
+void
+prebind_load_exe(Elf_Phdr *phdp, elf_object_t *exe_obj)
+{
+ struct prebind_footer *footer;
+
+ exe_obj->prebind_data = (void *)phdp->p_vaddr;
+ _dl_prog_prebind_map = exe_obj->prebind_data;
+
+ footer = _dl_prebind_data_to_footer(_dl_objects->prebind_data);
+
+ 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 &&
+ footer->prebind_version == PREBIND_VERSION) {
+ prog_footer = footer;
+ if (_dl_bindnow == NULL)
+ _dl_bindnow = prebind_bind_now;
+ } else {
+ DL_DEB(("prebind data missing\n"));
+ _dl_prog_prebind_map = NULL;
+ }
+ if (_dl_noprebind != NULL) {
+ /*prog_footer is valid, we should free it */
+ _dl_prog_prebind_map = NULL;
+ prog_footer = NULL;
+ exe_obj->prebind_data = NULL;
+ if (_dl_bindnow == prebind_bind_now)
+ _dl_bindnow = NULL;
+ }
+#if 0
+ else if (_dl_debug)
+ dump_prelink((long)_dl_prog_prebind_map,
+ prog_footer->prebind_size);
+#endif
+}
+
+void *
+prebind_load_fd(int fd, const char *name)
+{
+ struct prebind_footer footer;
+ void *prebind_data;
+ struct nameidx *nameidx;
+ char *nametab;
+ int idx;
+ ssize_t len;
+
+ if (_dl_prog_prebind_map == NULL || _dl_prebind_match_failed)
+ return 0;
+
+ _dl_lseek(fd, -(off_t)sizeof(struct prebind_footer), SEEK_END);
+ len = _dl_read(fd, (void *)&footer, sizeof(struct prebind_footer));
+
+ if (len != sizeof(struct prebind_footer) ||
+ footer.bind_id[0] != BIND_ID0 ||
+ footer.bind_id[1] != BIND_ID1 ||
+ footer.bind_id[2] != BIND_ID2 ||
+ footer.bind_id[3] != BIND_ID3 ||
+ footer.prebind_version != PREBIND_VERSION) {
+ _dl_prebind_match_failed = 1;
+ DL_DEB(("prebind match failed %s\n", name));
+ return (NULL);
+ }
+
+ prebind_data = _dl_mmap(0, footer.prebind_size, PROT_READ,
+ MAP_FILE, fd, footer.prebind_base);
+ DL_DEB(("prebind_load_fd for lib %s\n", name));
+
+ nameidx = _dl_prog_prebind_map + prog_footer->nameidx_idx;
+ nametab = _dl_prog_prebind_map + prog_footer->nametab_idx;
+
+ /* libraries are loaded in random order, so we just have
+ * to look thru the list to find ourselves
+ */
+ for (idx = 0; idx < prog_footer->numlibs; idx++) {
+ if (_dl_strcmp( nametab + nameidx[idx].name, name) == 0)
+ break;
+ }
+
+ if (idx == prog_footer->numlibs) {
+ _dl_prebind_match_failed = 1; /* not found */
+ } else if (footer.id0 != nameidx[idx].id0 ||
+ footer.id1 != nameidx[idx].id1) {
+ _dl_prebind_match_failed = 1;
+ DL_DEB(("prebind match id0 %d pid0 %d id1 %d pid1 %d\n",
+ footer.id0, nameidx[idx].id0,
+ footer.id1, nameidx[idx].id1));
+ }
+
+ if (_dl_prebind_match_failed == 1) {
+ DL_DEB(("prebind match failed for %s\n", name));
+ }
+
+ return prebind_data;
+}
+#define NUM_STATIC_OBJS 10
+elf_object_t *objarray_static[NUM_STATIC_OBJS];
+elf_object_t **objarray;
+
+void
+prebind_symcache(elf_object_t *object, int plt)
+{
+ void *prebind_map;
+ struct symcachetab *symcachetab;
+ struct nameidx *nameidx;
+ u_int32_t *fixupidx;
+ char *nametab;
+ struct fixup *fixup;
+ u_int32_t *fixupcnt;
+ u_int32_t *libmap;
+ u_int32_t *idxtolib;
+ elf_object_t *obj;
+ struct prebind_footer *footer;
+ char *c;
+ int i = 0;
+ int cur_obj = -1;
+ int idx;
+ u_int32_t *poffset;
+ u_int32_t offset;
+ u_int32_t symcache_cnt;
+
+ struct symcachetab *s;
+
+ if (object->prebind_data == NULL)
+ return;
+// DL_DEB(("prebind symcache %s\n", object->load_name));
+
+ obj = _dl_objects;
+ while (obj != NULL) {
+ if (obj == object)
+ cur_obj = i;
+ i++;
+ obj = obj->next;
+ }
+
+ if (objarray == NULL) {
+ if (i <= NUM_STATIC_OBJS) {
+ objarray = &objarray_static[0];
+ } else {
+ objarray = _dl_malloc(sizeof(elf_object_t *) * i);
+ }
+
+ obj = _dl_objects;
+ i = 0;
+ while (obj != NULL) {
+ objarray[i] = obj;
+ i++;
+ obj = obj->next;
+ }
+ }
+
+
+ poffset = (u_int32_t *)object->prebind_data;
+ c = object->prebind_data;
+ offset = *poffset;
+ c += offset;
+
+ footer = (void *)c;
+ prebind_map = (void *)object->prebind_data;
+ nameidx = prebind_map + footer->nameidx_idx;;
+ if (plt) {
+ symcachetab = prebind_map + footer->pltsymcache_idx;
+ symcache_cnt = footer->pltsymcache_cnt;
+// DL_DEB(("loading plt %d\n", symcache_cnt));
+ } else {
+ symcachetab = prebind_map + footer->symcache_idx;
+ symcache_cnt = footer->symcache_cnt;
+// DL_DEB(("loading got %d\n", symcache_cnt));
+ }
+ nametab = prebind_map + footer->nametab_idx;
+
+ libmap = _dl_prog_prebind_map + prog_footer->libmap_idx;
+ idxtolib = _dl_prog_prebind_map + libmap[cur_obj];
+
+ for (i = 0; i < symcache_cnt; i++) {
+ struct elf_object *tobj;
+ const Elf_Sym *sym;
+ const char *str;
+
+ s = &(symcachetab[i]);
+ if (cur_obj == 0)
+ idx = s->obj_idx;
+ else
+ idx = idxtolib[s->obj_idx];
+#if 0
+ DL_DEB(("%s:", object->load_name));
+ DL_DEB(("symidx %d: obj %d %d sym %d flags %x\n",
+ s->idx, s->obj_idx, idx,
+ s->sym_idx,
+ SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt));
+#endif
+ tobj = objarray[idx];
+ sym = tobj->dyn.symtab + s->sym_idx;
+ str = tobj->dyn.strtab + sym->st_name;
+#ifdef DEBUG2
+ DL_DEB(("symidx %d: obj %d %s sym %d %s flags %d %x\n",
+ s->idx, s->obj_idx, tobj->load_name,
+ s->sym_idx, str,
+ SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt,
+ object->load_addr + sym->st_value
+ ));
+#endif
+ _dl_symcache[s->idx].obj = tobj;
+ _dl_symcache[s->idx].sym = sym;
+ _dl_symcache[s->idx].flags =
+ SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt;
+ }
+
+ if (!plt) {
+ fixupidx = _dl_prog_prebind_map + prog_footer->fixup_idx;
+ fixup = _dl_prog_prebind_map + fixupidx[2*cur_obj];
+ fixupcnt = _dl_prog_prebind_map + prog_footer->fixupcnt_idx;
+
+ for (i = 0; i < fixupcnt[2*cur_obj]; i++) {
+ struct fixup *f;
+ struct elf_object *tobj;
+ const Elf_Sym *sym;
+ const char *str;
+
+ f = &(fixup[i]);
+#if 0
+ DL_DEB(("symidx %d: obj %d sym %d flags %x\n",
+ f->sym, f->targobj_idx,
+ f->sym_idx, f->flags));
+#endif
+ tobj = objarray[f->targobj_idx];
+ sym = tobj->dyn.symtab + f->sym_idx;
+ str = tobj->dyn.strtab + sym->st_name;
+#ifdef DEBUG2
+ DL_DEB(("symidx %d: obj %d %s sym %d %s flags %d %x\n",
+ f->sym, f->targobj_idx, tobj->load_name,
+ f->sym_idx, str,
+ SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt,
+ object->load_addr + sym->st_value
+ ));
+#endif
+ _dl_symcache[f->sym].obj = tobj;
+ _dl_symcache[f->sym].sym = sym;
+ _dl_symcache[f->sym].flags =
+ SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt;
+ }
+ } else {
+
+ fixupidx = _dl_prog_prebind_map + prog_footer->fixup_idx;
+ fixup = _dl_prog_prebind_map + fixupidx[2*cur_obj+1];
+ fixupcnt = _dl_prog_prebind_map + prog_footer->fixupcnt_idx;
+
+#if 0
+ DL_DEB(("prebind loading symbols fixup plt %s\n",
+ object->load_name));
+#endif
+ for (i = 0; i < fixupcnt[2*cur_obj+1]; i++) {
+ struct fixup *f;
+ struct elf_object *tobj;
+ const Elf_Sym *sym;
+ const char *str;
+
+ f = &(fixup[i]);
+#if 0
+ DL_DEB(("symidx %d: obj %d sym %d flags %x\n",
+ f->sym, f->targobj_idx,
+ f->sym_idx,
+ SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt));
+#endif
+ tobj = objarray[f->targobj_idx];
+ sym = tobj->dyn.symtab + f->sym_idx;
+ str = tobj->dyn.strtab + sym->st_name;
+#ifdef DEBUG2
+ DL_DEB(("symidx %d: obj %d %s sym %d %s flags %d %x\n",
+ f->sym, f->targobj_idx, tobj->load_name,
+ f->sym_idx, str,
+ SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt,
+ object->load_addr + sym->st_value
+ ));
+#endif
+ _dl_symcache[f->sym].obj = tobj;
+ _dl_symcache[f->sym].sym = sym;
+ _dl_symcache[f->sym].flags =
+ SYM_SEARCH_ALL|SYM_WARNNOTFOUND|plt;
+ }
+ }
+// DL_DEB(("prebind_data loaded\n"));
+}
+
+void
+prebind_free(elf_object_t *object)
+{
+ struct prebind_footer *footer;
+
+ if (object->prebind_data == NULL)
+ return;
+#ifdef DEBUG1
+ DL_DEB(("prebind_free for %s %p\n", object->load_name,
+ object->prebind_data));
+#endif
+ if (object->prebind_data != 0) {
+ footer = _dl_prebind_data_to_footer(object->prebind_data);
+
+#ifdef DEBUG1
+ DL_DEB(("freeing prebind data sz %x\n", footer->prebind_size));
+#endif
+
+ _dl_munmap((void *)ELF_TRUNC((long)object->prebind_data, _dl_pagesz),
+ ELF_ROUND((long)object->prebind_data+footer->prebind_size
+ ,_dl_pagesz) -
+ ELF_TRUNC((long)object->prebind_data, _dl_pagesz));
+
+ object->prebind_data = NULL;
+ }
+}
+
+int validate_errs;
+
+struct timeval beforetp;
+void
+_dl_prebind_pre_resolve()
+{
+ elf_object_t *object;
+ struct nameidx *nameidx;
+ char *nametab;
+ int idx;
+ char *name;
+ struct prebind_footer *footer;
+
+ if (_dl_prog_prebind_map != NULL) {
+ nameidx = _dl_prog_prebind_map + prog_footer->nameidx_idx;
+ nametab = _dl_prog_prebind_map + prog_footer->nametab_idx;
+ for (idx = 1, object = _dl_objects->next; object != NULL;
+ object = object->next, idx++) {
+ if (object->prebind_data == NULL) {
+ /* ld.so doesn't have prebind data */
+ if (object->next == NULL)
+ continue;
+ DL_DEB(("missing prebind data %s\n",
+ object->load_name));
+ _dl_prebind_match_failed = 1;
+ break;
+ }
+ footer = _dl_prebind_data_to_footer(
+ object->prebind_data);
+ if (footer == NULL ||
+ nameidx[idx].id0 != footer->id0 ||
+ nameidx[idx].id1 != footer->id1) {
+ DL_DEB(("invalid prebind data %s\n",
+ object->load_name));
+ _dl_prebind_match_failed = 1;
+ break;
+ }
+ name = object->load_name;
+ if (_dl_strcmp( nametab + nameidx[idx].name, name)
+ != 0) {
+ DL_DEB(("invalid prebind name %s\n",
+ object->load_name));
+ _dl_prebind_match_failed = 1;
+ break;
+ }
+ }
+ }
+
+ if (_dl_prebind_match_failed) {
+ for (object = _dl_objects; object != NULL;
+ object = object->next)
+ prebind_free(object);
+ if (_dl_bindnow == prebind_bind_now)
+ _dl_bindnow = NULL;
+ }
+
+ if (_dl_debug)
+ _dl_gettimeofday(&beforetp, NULL);
+}
+
+void
+_dl_prebind_post_resolve()
+{
+ char buf[7];
+ int i;
+ struct timeval after_tp;
+ struct timeval diff_tp;
+ elf_object_t *object;
+
+ if (_dl_debug) {
+ _dl_gettimeofday(&after_tp, NULL);
+
+ timersub(&after_tp, &beforetp, &diff_tp);
+
+ for (i = 0; i < 6; i++) {
+ buf[5-i] = (diff_tp.tv_usec % 10) + '0';
+ diff_tp.tv_usec /= 10;
+ }
+ buf[6] = '\0';
+
+ _dl_printf("relocation took %d.%s\n", diff_tp.tv_sec, buf);
+ }
+
+ for (object = _dl_objects; object != NULL; object = object->next)
+ prebind_free(object);
+
+ if (_dl_prebind_validate) {
+ if (validate_errs) {
+ _dl_printf("validate_errs %d\n", validate_errs);
+ _dl_exit(20);
+ } else {
+ _dl_exit(0);
+ }
+ }
+}
+
+void
+prebind_validate(elf_object_t *req_obj, unsigned int symidx, int flags,
+ const Elf_Sym *ref_sym)
+{
+ const Elf_Sym *sym;
+ const char *symn;
+ const elf_object_t *sobj;
+ Elf_Addr ret;
+ const Elf_Sym **this;
+
+ /* Dont verify non-matching flags*/
+
+ sym = req_obj->dyn.symtab;
+ sym += symidx;
+ symn = req_obj->dyn.strtab + sym->st_name;
+ this = &sym;
+
+ //_dl_printf("checking %s\n", symn);
+ ret = _dl_find_symbol(symn, this, flags, ref_sym, req_obj, &sobj);
+
+ if (_dl_symcache[symidx].sym != *this ||
+ _dl_symcache[symidx].obj != sobj) {
+ _dl_printf("symbol %d mismatch on sym %s req_obj %s,\n"
+ "should be obj %s is obj %s\n",
+ symidx,
+ symn, req_obj->load_name, sobj->load_name, _dl_symcache[symidx].obj->load_name);
+ if (req_obj == sobj)
+ _dl_printf("obj %p %p\n", _dl_symcache[symidx].obj, sobj);
+ sym = _dl_symcache[symidx].obj->dyn.symtab;
+ sym += symidx;
+ symn = _dl_symcache[symidx].obj->dyn.strtab + sym->st_name;
+ _dl_printf("obj %s name %s\n",
+ _dl_symcache[symidx].obj->load_name,
+ symn);
+ }
+}
+
+#ifdef DEBUG1
+void
+prebind_dump_symcache(struct symcachetab *symcachetab, u_int32_t cnt)
+{
+ int i;
+ struct symcachetab *s;
+ _dl_printf("cache: cnt %d\n", cnt);
+ for (i = 0; i < cnt; i++) {
+ s = &(symcachetab[i]);
+ _dl_printf("symidx %d: obj %d sym %d\n",
+ s->idx, s->obj_idx, s->sym_idx);
+ }
+}
+
+void
+prebind_dump_nameidx(struct nameidx *nameidx, u_int32_t numlibs, char *nametab)
+{
+ int i;
+ struct nameidx *n;
+ _dl_printf("libs:\n");
+ for (i = 0; i < numlibs; i++) {
+ _dl_printf("lib %d offset %d id0 %d, id1 %d\n", i,
+ nameidx[i].name, nameidx[i].id0, nameidx[i].id1);
+ }
+ for (i = 0; i < numlibs; i++) {
+ n = &(nameidx[i]);
+ _dl_printf("nametab %p n %d\n", nametab, n->name);
+ _dl_printf("lib %s %x %x\n", nametab + n->name, n->id0, n->id1);
+ }
+}
+
+void
+prebind_dump_fixup(struct fixup *fixup, u_int32_t numfixups)
+{
+ int i;
+ struct fixup *f;
+ _dl_printf("fixup: %d\n", numfixups);
+ for (i = 0; i < numfixups; i++) {
+ f = &(fixup[i]);
+
+ _dl_printf("idx %d targobj %d sym idx %d\n",
+ f->sym, f->targobj_idx, f->sym_idx);
+
+ }
+}
+
+void
+prebind_dump_libmap(u_int32_t *libmap, u_int32_t numlibs)
+{
+ int i;
+ for (i = 0; i < numlibs; i++) {
+ //_dl_printf("lib%d off %d %s\n", i, libmap[i], strtab+libmap[i]);
+ _dl_printf("lib%d off %d\n", i, libmap[i]);
+ }
+}
+
+void
+dl_dump_footer(struct prebind_footer *footer)
+{
+// _dl_printf("base %qd\n", (long long)footer->prebind_base);
+ _dl_printf("nameidx_idx %d\n", footer->nameidx_idx);
+ _dl_printf("symcache_idx %d\n", footer->symcache_idx);
+ _dl_printf("fixupcnt_idx %d\n", footer->fixupcnt_idx);
+ _dl_printf("fixup_cnt %d\n", footer->fixup_cnt);
+ _dl_printf("nametab_idx %d\n", footer->nametab_idx);
+ _dl_printf("symcache_cnt %d\n", footer->symcache_cnt);
+ _dl_printf("fixup_cnt %d\n", footer->fixup_cnt);
+ _dl_printf("numlibs %d\n", footer->numlibs);
+ _dl_printf("id0 %d\n", footer->id0);
+ _dl_printf("id1 %d\n", footer->id1);
+// _dl_printf("orig_size %lld\n", (long long)footer->orig_size);
+ _dl_printf("version %d\n", footer->prebind_version);
+ _dl_printf("bind_id %c%c%c%c\n", footer->bind_id[0],
+ footer->bind_id[1], footer->bind_id[2], footer->bind_id[3]);
+}
+void
+dump_prelink(Elf_Addr base, u_long size)
+{
+ int i;
+ char *id;
+ struct symcachetab *symcachetab;
+ struct nameidx *nameidx;
+ void *prebind_map;
+ struct prebind_footer *footer;
+ u_int32_t *fixupidx;
+ char *nametab;
+ struct fixup *fixup;
+ u_int32_t *fixupcnt;
+ u_int32_t *libmap;
+
+ id = (char *) (base+size);
+ id -=4;
+ DL_DEB(("id %c %c %c %c\n", id[0], id[1], id[2], id[3]));
+ footer = (void *) (base+size - sizeof (struct prebind_footer));
+ dl_dump_footer(footer);
+
+ prebind_map = (void *)base;
+ nameidx = prebind_map + footer->nameidx_idx;;
+ symcachetab = prebind_map + footer->symcache_idx;
+ fixupidx = prebind_map + footer->fixup_idx;
+ nametab = prebind_map + footer->nametab_idx;
+ fixupcnt = prebind_map + footer->fixupcnt_idx;
+ libmap = prebind_map + footer->libmap_idx;
+
+ prebind_dump_symcache(symcachetab, footer->symcache_cnt);
+ prebind_dump_nameidx(nameidx, footer->numlibs, nametab);
+ for(i = 0; i < footer->fixup_cnt; i++) {
+ _dl_printf("fixup %d cnt %d idx %d\n", i, fixupcnt[i], fixupidx[i]);
+ fixup = prebind_map + fixupidx[i];
+ prebind_dump_fixup(fixup, fixupcnt[i]);
+ }
+ prebind_dump_libmap(libmap, footer->numlibs);
+}
+#endif /* DEBUG1 */
diff --git a/libexec/ld.so/dl_prebind.h b/libexec/ld.so/dl_prebind.h
new file mode 100644
index 00000000000..ae1b877568a
--- /dev/null
+++ b/libexec/ld.so/dl_prebind.h
@@ -0,0 +1,36 @@
+/* $OpenBSD: dl_prebind.h,v 1.1 2006/05/03 16:10:51 drahn 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/exec_elf.h>
+#include "resolve.h"
+#include "prebind.h"
+extern char *_dl_noprebind;
+extern char *_dl_prebind_validate;
+void _dl_prebind_pre_resolve(void);
+void _dl_prebind_post_resolve(void);
+void *prebind_load_fd(int fd, const char *name);
+void prebind_load_exe(Elf_Phdr *phdp, elf_object_t *exe_obj);
+
+void
+prebind_validate(elf_object_t *req_obj, unsigned int symidx, int flags,
+ const Elf_Sym *ref_sym);
+extern char *_dl_prebind_validate; /* XXX */
+
+void prebind_symcache(elf_object_t *object, int pltflag);
+void prebind_free(elf_object_t *object);
+
+extern struct prebind_footer *footer;
diff --git a/libexec/ld.so/hppa/ldasm.S b/libexec/ld.so/hppa/ldasm.S
index b7f59ab7937..6f5f6e6446c 100644
--- a/libexec/ld.so/hppa/ldasm.S
+++ b/libexec/ld.so/hppa/ldasm.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldasm.S,v 1.3 2005/01/09 17:57:40 mickey Exp $ */
+/* $OpenBSD: ldasm.S,v 1.4 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 2004 Michael Shalayeff
@@ -255,6 +255,12 @@ ENTRY(_dl_getdirentries,0)
nop
EXIT(_dl_getdirentries)
+ENTRY(_dl_gettimeofday,0)
+ SYSCALL(gettimeofday)
+ bv r0(rp)
+ nop
+EXIT(_dl_gettimeofday)
+
ENTRY(_dl_sigprocmask,0)
stw arg2, HPPA_FRAME_ARG(2)(sp)
diff --git a/libexec/ld.so/hppa/rtld_machine.c b/libexec/ld.so/hppa/rtld_machine.c
index 5971c2cfb75..3bead5d3e9e 100644
--- a/libexec/ld.so/hppa/rtld_machine.c
+++ b/libexec/ld.so/hppa/rtld_machine.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtld_machine.c,v 1.11 2005/09/22 04:07:11 deraadt Exp $ */
+/* $OpenBSD: rtld_machine.c,v 1.12 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 2004 Michael Shalayeff
@@ -105,8 +105,10 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz)
numrela = object->Dyn.info[relasz] / sizeof(Elf_RelA);
rela = (Elf_RelA *)(object->Dyn.info[rel]);
+#ifdef DEBUG
DL_DEB(("object %s relasz %x, numrela %x loff %x\n",
object->load_name, object->Dyn.info[relasz], numrela, loff));
+#endif
if (rela == NULL)
return (0);
@@ -118,18 +120,22 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz)
if (object->dyn.init && !((Elf_Addr)object->dyn.init & 2)) {
Elf_Addr addr = _dl_md_plabel((Elf_Addr)object->dyn.init,
object->dyn.pltgot);
+#ifdef DEBUG
DL_DEB(("PLABEL32: %p:%p(_init) -> 0x%x in %s\n",
object->dyn.init, object->dyn.pltgot,
addr, object->load_name));
+#endif
object->dyn.init = (void *)addr;
}
if (object->dyn.fini && !((Elf_Addr)object->dyn.fini & 2)) {
Elf_Addr addr = _dl_md_plabel((Elf_Addr)object->dyn.fini,
object->dyn.pltgot);
+#ifdef DEBUG
DL_DEB(("PLABEL32: %p:%p(_fini) -> 0x%x in %s\n",
object->dyn.fini, object->dyn.pltgot,
addr, object->load_name));
+#endif
object->dyn.fini = (void *)addr;
}
@@ -163,7 +169,7 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz)
ooff = _dl_find_symbol_bysym(object,
ELF_R_SYM(rela->r_info), &this,
SYM_SEARCH_ALL|SYM_WARNNOTFOUND|
- ((type == RELOC_DIR32) ? SYM_NOTPLT : SYM_PLT),
+ ((type == RELOC_IPLT) ? SYM_PLT: SYM_NOTPLT),
sym, &sobj);
if (this == NULL) {
if (ELF_ST_BIND(sym->st_info) != STB_WEAK)
@@ -172,16 +178,20 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz)
}
}
+#ifdef DEBUG
DL_DEB(("*pt=%x r_addend=%x r_sym=%x\n",
*pt, rela->r_addend, ELF_R_SYM(rela->r_info)));
+#endif
switch (type) {
case RELOC_DIR32:
if (ELF_R_SYM(rela->r_info) && sym->st_name) {
*pt = ooff + this->st_value + rela->r_addend;
+#ifdef DEBUG
DL_DEB(("[%x]DIR32: %s:%s -> 0x%x in %s\n",
i, symn, object->load_name,
*pt, sobj->load_name));
+#endif
} else {
/*
* XXX should objects ever get their
@@ -194,8 +204,10 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz)
*pt += loff;
else
*pt += loff + rela->r_addend;
+#ifdef DEBUG
DL_DEB(("[%x]DIR32: %s @ 0x%x\n", i,
object->load_name, *pt));
+#endif
}
break;
@@ -208,13 +220,17 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz)
*pt = _dl_md_plabel(sobj->load_offs +
this->st_value + rela->r_addend,
sobj->dyn.pltgot);
+#ifdef DEBUG
DL_DEB(("[%x]PLABEL32: %s:%s -> 0x%x in %s\n",
i, symn, object->load_name,
*pt, sobj->load_name));
+#endif
} else {
*pt = loff + rela->r_addend;
+#ifdef DEBUG
DL_DEB(("[%x]PLABEL32: %s @ 0x%x\n", i,
object->load_name, *pt));
+#endif
}
break;
@@ -222,14 +238,18 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz)
if (ELF_R_SYM(rela->r_info)) {
pt[0] = ooff + this->st_value + rela->r_addend;
pt[1] = (Elf_Addr)sobj->dyn.pltgot;
+#ifdef DEBUG
DL_DEB(("[%x]IPLT: %s:%s -> 0x%x:0x%x in %s\n",
i, symn, object->load_name,
pt[0], pt[1], sobj->load_name));
+#endif
} else {
pt[0] = loff + rela->r_addend;
pt[1] = (Elf_Addr)object->dyn.pltgot;
+#ifdef DEBUG
DL_DEB(("[%x]IPLT: %s @ 0x%x:0x%x\n", i,
object->load_name, pt[0], pt[1]));
+#endif
}
break;
@@ -243,10 +263,12 @@ _dl_md_reloc(elf_object_t *object, int rel, int relasz)
if (cpysrc) {
_dl_bcopy((void *)(ooff + cpysrc->st_value),
pt, sym->st_size);
+#ifdef DEBUG
DL_DEB(("[%x]COPY: %s[%x]:%s -> %p[%x] in %s\n",
i, symn, ooff + cpysrc->st_value,
object->load_name, pt, sym->st_size,
sobj->load_name));
+#endif
} else
DL_DEB(("[%x]COPY: no sym\n", i));
break;
diff --git a/libexec/ld.so/hppa/syscall.h b/libexec/ld.so/hppa/syscall.h
index af725eeea13..0f6a73181b0 100644
--- a/libexec/ld.so/hppa/syscall.h
+++ b/libexec/ld.so/hppa/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.2 2004/05/25 21:56:49 deraadt Exp $ */
+/* $OpenBSD: syscall.h,v 1.3 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -53,6 +53,7 @@ int _dl_fcntl(int, int, ...);
int _dl_getdirentries(int, char*, int, long *);
int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
int _dl_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+int _dl_gettimeofday(struct timeval *tp, struct timezone *tzp);
static inline off_t
_dl_lseek(int fildes, off_t offset, int whence)
diff --git a/libexec/ld.so/i386/ldasm.S b/libexec/ld.so/i386/ldasm.S
index e177457f8be..b5248e33c77 100644
--- a/libexec/ld.so/i386/ldasm.S
+++ b/libexec/ld.so/i386/ldasm.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldasm.S,v 1.9 2006/05/03 15:37:50 drahn Exp $ */
+/* $OpenBSD: ldasm.S,v 1.10 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 2002 Dale Rahn
@@ -117,6 +117,7 @@ DL_SYSCALL(write)
DL_SYSCALL(stat)
DL_SYSCALL(fstat)
DL_SYSCALL(fcntl)
+DL_SYSCALL(gettimeofday)
DL_SYSCALL2(sysctl,__sysctl)
DL_SYSCALL(getdirentries)
diff --git a/libexec/ld.so/i386/syscall.h b/libexec/ld.so/i386/syscall.h
index f047970172c..2d2f36b7b9d 100644
--- a/libexec/ld.so/i386/syscall.h
+++ b/libexec/ld.so/i386/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.6 2004/05/25 15:56:18 deraadt Exp $ */
+/* $OpenBSD: syscall.h,v 1.7 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -53,6 +53,7 @@ int _dl_fcntl(int, int, ...);
int _dl_getdirentries(int, char*, int, long *);
int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
int _dl_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+int _dl_gettimeofday(struct timeval *tp, struct timezone *tzp);
static inline off_t
_dl_lseek(int fildes, off_t offset, int whence)
diff --git a/libexec/ld.so/ld.so.1 b/libexec/ld.so/ld.so.1
index 66daec4ea8b..51b8d4dca08 100644
--- a/libexec/ld.so/ld.so.1
+++ b/libexec/ld.so/ld.so.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ld.so.1,v 1.8 2005/08/16 12:01:43 tom Exp $
+.\" $OpenBSD: ld.so.1,v 1.9 2006/05/03 16:10:51 drahn Exp $
.\" $NetBSD: rtld.1,v 1.2 1995/10/08 23:43:28 pk Exp $
.\"
.\" Copyright (c) 1995 Paul Kranenburg
@@ -181,6 +181,14 @@ non-standard filesystem layout.
When set, be verbose about what
.Nm
does.
+.Pp
+.It Ev LD_NOPREBIND=
+When set, ignore any prebind data associated with the program or libraries.
+.Pp
+.It Ev LD_PREBINDVALIDATE=
+When set, perform symbol relocation without of the given binary
+and the associated libraries, compare the results against the prebind
+values, then exit.
.El
.Sh FILES
.Bl -tag -width /var/run/ld.so.hintsXXX -compact
diff --git a/libexec/ld.so/library.c b/libexec/ld.so/library.c
index 7c948adae24..66774882feb 100644
--- a/libexec/ld.so/library.c
+++ b/libexec/ld.so/library.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: library.c,v 1.52 2005/11/09 16:41:29 kurt Exp $ */
+/* $OpenBSD: library.c,v 1.53 2006/05/03 16:10:51 drahn Exp $ */
/*
* Copyright (c) 2002 Dale Rahn
@@ -33,6 +33,7 @@
#include <sys/param.h>
#include <fcntl.h>
#include <sys/mman.h>
+#include "dl_prebind.h"
#include "syscall.h"
#include "archdep.h"
@@ -73,7 +74,6 @@ _dl_unload_shlib(elf_object_t *object)
}
}
-
elf_object_t *
_dl_tryload_shlib(const char *libname, int type, int flags)
{
@@ -87,6 +87,7 @@ _dl_tryload_shlib(const char *libname, int type, int flags)
Elf_Ehdr *ehdr;
Elf_Phdr *phdp;
struct stat sb;
+ void *prebind_data;
#define ROUND_PG(x) (((x) + align) & ~(align))
#define TRUNC_PG(x) ((x) & ~(align))
@@ -236,11 +237,15 @@ _dl_tryload_shlib(const char *libname, int type, int flags)
}
}
}
+
+ prebind_data = prebind_load_fd(libfile, libname);
+
_dl_close(libfile);
dynp = (Elf_Dyn *)((unsigned long)dynp + loff);
object = _dl_finalize_object(libname, dynp, 0, type, libaddr, loff);
if (object) {
+ object->prebind_data = prebind_data;
object->load_size = maxva - minva; /*XXX*/
object->load_list = load_list;
/* set inode, dev from stat info */
diff --git a/libexec/ld.so/library_mquery.c b/libexec/ld.so/library_mquery.c
index fa38340b8f8..93edfe12ecd 100644
--- a/libexec/ld.so/library_mquery.c
+++ b/libexec/ld.so/library_mquery.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: library_mquery.c,v 1.32 2005/11/09 16:41:29 kurt Exp $ */
+/* $OpenBSD: library_mquery.c,v 1.33 2006/05/03 16:10:51 drahn Exp $ */
/*
* Copyright (c) 2002 Dale Rahn
@@ -33,6 +33,7 @@
#include <sys/param.h>
#include <fcntl.h>
#include <sys/mman.h>
+#include "dl_prebind.h"
#include "syscall.h"
#include "archdep.h"
@@ -92,6 +93,7 @@ _dl_tryload_shlib(const char *libname, int type, int flags)
int size;
Elf_Addr load_end = 0;
struct stat sb;
+ void *prebind_data;
#define ROUND_PG(x) (((x) + align) & ~(align))
#define TRUNC_PG(x) ((x) & ~(align))
@@ -273,12 +275,16 @@ retry:
_dl_pagesz - (ld->size & align));
load_end = (Elf_Addr)ld->start + ROUND_PG(ld->size);
}
+
+ prebind_data = prebind_load_fd(libfile, libname);
+
_dl_close(libfile);
dynp = (Elf_Dyn *)((unsigned long)dynp + LOFF);
object = _dl_finalize_object(libname, dynp, 0, type,
(Elf_Addr)lowld->start, LOFF);
if (object) {
+ object->prebind_data = prebind_data;
object->load_size = (Elf_Addr)load_end - (Elf_Addr)lowld->start;
object->load_list = lowld;
/* set inode, dev from stat info */
diff --git a/libexec/ld.so/loader.c b/libexec/ld.so/loader.c
index 31a28fbd10c..ff23ca1602b 100644
--- a/libexec/ld.so/loader.c
+++ b/libexec/ld.so/loader.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: loader.c,v 1.100 2005/11/09 16:41:29 kurt Exp $ */
+/* $OpenBSD: loader.c,v 1.101 2006/05/03 16:10:51 drahn Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -43,6 +43,7 @@
#include "resolve.h"
#include "sod.h"
#include "stdlib.h"
+#include "dl_prebind.h"
/*
* Local decls.
@@ -66,6 +67,8 @@ char *_dl_traceld;
char *_dl_debug;
char *_dl_showmap;
char *_dl_norandom;
+char *_dl_noprebind;
+char *_dl_prebind_validate;
struct r_debug *_dl_debug_map;
@@ -204,6 +207,8 @@ _dl_setup_env(char **envp)
_dl_traceld = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp);
_dl_debug = _dl_getenv("LD_DEBUG", envp);
_dl_norandom = _dl_getenv("LD_NORANDOM", envp);
+ _dl_noprebind = _dl_getenv("LD_NOPREBIND", envp);
+ _dl_prebind_validate = _dl_getenv("LD_PREBINDVALIDATE", envp);
/*
* Don't allow someone to change the search paths if he runs
@@ -332,6 +337,8 @@ _dl_load_dep_libs(elf_object_t *object, int flags, int booting)
return(0);
}
+
+
/*
* This is the dynamic loader entrypoint. When entering here, depending
* on architecture type, the stack and registers are set up according
@@ -405,6 +412,10 @@ _dl_boot(const char **argv, char **envp, const long loff, long *dl_data)
_dl_add_object(exe_obj);
} else if (phdp->p_type == PT_INTERP) {
us = _dl_strdup((char *)phdp->p_vaddr);
+ } else if ((phdp->p_type == PT_LOAD) &&
+ (phdp->p_flags & 0x08000000)) {
+// dump_prelink(phdp->p_vaddr, phdp->p_memsz);
+ prebind_load_exe(phdp, exe_obj);
}
phdp++;
}
@@ -441,10 +452,14 @@ _dl_boot(const char **argv, char **envp, const long loff, long *dl_data)
* Everything should be in place now for doing the relocation
* and binding. Call _dl_rtld to do the job. Fingers crossed.
*/
+
+ _dl_prebind_pre_resolve();
failed = 0;
if (_dl_traceld == NULL)
failed = _dl_rtld(_dl_objects);
+ _dl_prebind_post_resolve();
+
if (_dl_debug || _dl_traceld)
_dl_show_objects();
@@ -738,14 +753,14 @@ _dl_rtld(elf_object_t *object)
sz = 0;
if (object->nchains < DL_SM_SYMBUF_CNT) {
_dl_symcache = _dl_sm_symcache_buffer;
- DL_DEB(("using static buffer for %d entries\n",
- object->nchains));
+// DL_DEB(("using static buffer for %d entries\n",
+// object->nchains));
_dl_memset(_dl_symcache, 0,
sizeof (sym_cache) * object->nchains);
} else {
sz = ELF_ROUND(sizeof (sym_cache) * object->nchains,
_dl_pagesz);
- DL_DEB(("allocating symcache sz %x with mmap\n", sz));
+// DL_DEB(("allocating symcache sz %x with mmap\n", sz));
_dl_symcache = (void *)_dl_mmap(0, sz, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANON, -1, 0);
@@ -754,11 +769,14 @@ _dl_rtld(elf_object_t *object)
_dl_symcache = NULL;
}
}
+ prebind_symcache(object, SYM_NOTPLT);
+
/*
* Do relocation information first, then GOT.
*/
fails =_dl_md_reloc(object, DT_REL, DT_RELSZ);
fails += _dl_md_reloc(object, DT_RELA, DT_RELASZ);
+ prebind_symcache(object, SYM_PLT);
_dl_md_reloc_got(object, !(_dl_bindnow ||
object->obj_flags & RTLD_NOW));
@@ -772,7 +790,6 @@ _dl_rtld(elf_object_t *object)
return (fails);
}
-
void
_dl_call_init(elf_object_t *object)
{
diff --git a/libexec/ld.so/mips64/syscall.h b/libexec/ld.so/mips64/syscall.h
index 13bace0ca9d..9be5ed1c2ef 100644
--- a/libexec/ld.so/mips64/syscall.h
+++ b/libexec/ld.so/mips64/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.3 2005/09/22 04:07:11 deraadt Exp $ */
+/* $OpenBSD: syscall.h,v 1.4 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 1998-2002 Opsycon AB, Sweden.
@@ -337,5 +337,24 @@ _dl_sysctl(int *name, u_int namelen, void *oldp, size_t *oldplen, void *newp,
"$10","$11","$12","$13","$14","$15","$24","$25");
return status;
}
+extern inline int
+_dl_gettimeofday(struct timeval* tp, struct timezone *tzp)
+{
+ register int status __asm__ ("$2");
+
+ __asm__ volatile (
+ "move $4,%2\n\t"
+ "move $5,%3\n\t"
+ "li $2,%1\n\t"
+ "syscall\n\t"
+ "beq $7,$0,1f\n\t"
+ "li $2,-1\n\t"
+ "1:"
+ : "=r" (status)
+ : "I" (SYS_gettimeofday), "r" (tp), "r" (tzp)
+ : "$3", "$4", "$5", "$6", "$7", "$8", "$9",
+ "$10","$11","$12","$13","$14","$15","$24","$25");
+ return status;
+}
#endif /*__DL_SYSCALL_H__*/
diff --git a/libexec/ld.so/powerpc/syscall.h b/libexec/ld.so/powerpc/syscall.h
index 8a0ce9168e2..29878f3a988 100644
--- a/libexec/ld.so/powerpc/syscall.h
+++ b/libexec/ld.so/powerpc/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.19 2004/01/12 02:21:21 drahn Exp $ */
+/* $OpenBSD: syscall.h,v 1.20 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -32,6 +32,7 @@
#include <sys/syscall.h>
#include <sys/signal.h>
+#include <sys/time.h>
static off_t _dl_lseek(int, off_t, int);
@@ -352,5 +353,26 @@ _dl_sysctl(int *name, u_int namelen, void *oldp, size_t *oldplen, void *newp,
: "0", "3", "4", "5", "6", "7", "8");
return status;
}
+static inline int
+_dl_gettimeofday(struct timeval *tp, struct timezone *tzp)
+{
+ register int status;
+
+ __asm__ volatile ("li 0,%1\n\t"
+ "mr 3,%2\n\t"
+ "mr 4,%3\n\t"
+ "sc\n\t"
+ "cmpwi 0, 0\n\t"
+ "beq 1f\n\t"
+ "li 3,-1\n\t"
+ "1:"
+ "mr %0,3\n\t"
+ : "=r" (status)
+ : "I" (SYS_gettimeofday), "r" (tp), "r" (tzp)
+ : "0", "3", "4" );
+ return status;
+}
+
#endif /*__DL_SYSCALL_H__*/
+
diff --git a/libexec/ld.so/prebind.h b/libexec/ld.so/prebind.h
new file mode 100644
index 00000000000..6f9dd6228cf
--- /dev/null
+++ b/libexec/ld.so/prebind.h
@@ -0,0 +1,64 @@
+/* $OpenBSD: prebind.h,v 1.1 2006/05/03 16:10:51 drahn 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.
+ */
+
+#define PREBIND_VERSION 2
+struct prebind_footer {
+ off_t prebind_base;
+ u_int32_t nameidx_idx;
+ u_int32_t symcache_idx;
+ u_int32_t pltsymcache_idx;
+ u_int32_t fixup_idx;
+ u_int32_t nametab_idx;
+ u_int32_t fixupcnt_idx;
+ u_int32_t libmap_idx;
+
+ u_int32_t symcache_cnt;
+ u_int32_t pltsymcache_cnt;
+ u_int32_t fixup_cnt;
+ u_int32_t numlibs;
+ u_int32_t prebind_size;
+
+ u_int32_t id0;
+ u_int32_t id1;
+ /* do not modify or add fields below this point in the struct */
+ off_t orig_size;
+ u_int32_t prebind_version;
+ char bind_id[4];
+#define BIND_ID0 'P'
+#define BIND_ID1 'R'
+#define BIND_ID2 'E'
+#define BIND_ID3 'B'
+};
+
+
+struct nameidx {
+ u_int32_t name;
+ u_int32_t id0;
+ u_int32_t id1;
+};
+
+struct symcachetab {
+ u_int32_t idx;
+ u_int32_t obj_idx;
+ u_int32_t sym_idx;
+};
+
+struct fixup {
+ u_int32_t sym;
+ u_int32_t targobj_idx;
+ u_int32_t sym_idx;
+};
diff --git a/libexec/ld.so/prebind/Makefile b/libexec/ld.so/prebind/Makefile
new file mode 100644
index 00000000000..3eadbabc08f
--- /dev/null
+++ b/libexec/ld.so/prebind/Makefile
@@ -0,0 +1,18 @@
+# $OpenBSD: Makefile,v 1.1 2006/05/03 16:10:52 drahn Exp $
+
+SRCS= prebind.c sod.c debug.c objarray.c
+.if (${MACHINE} == "mips64")
+NOPROG=
+.else
+PROG= prebind
+.endif
+MAN= prebind.8
+
+BINDIR= /usr/sbin
+
+CFLAGS += -Wall -ggdb
+CFLAGS += -I${.CURDIR}/..
+
+BINDIR= /usr/sbin
+
+.include <bsd.prog.mk>
diff --git a/libexec/ld.so/prebind/debug.c b/libexec/ld.so/prebind/debug.c
new file mode 100644
index 00000000000..413bdb75ebe
--- /dev/null
+++ b/libexec/ld.so/prebind/debug.c
@@ -0,0 +1,154 @@
+/* $OpenBSD: debug.c,v 1.1 2006/05/03 16:10:52 drahn 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 <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"
+#include "machine/reloc.h"
+#include "prebind.h"
+#include "prebind_struct.h"
+
+#ifdef DEBUG1
+void
+dump_info(struct elf_object *object)
+{
+ int i;
+ const Elf_Sym *symt;
+ const char *strt;
+ int numrel;
+ int numrela;
+ Elf_Word *needed_list;
+
+ symt = object->dyn.symtab;
+ strt = object->dyn.strtab;
+
+ for (i = 0; i < object->nchains; i++) {
+ char * type;
+ const Elf_Sym *sym = symt + i;
+
+ switch(ELF_ST_TYPE(sym->st_info)) {
+ case STT_FUNC:
+ type = "func"; break;
+ case STT_OBJECT:
+ type = "object"; break;
+ case STT_NOTYPE:
+ type = "notype"; break;
+ default:
+ type = "UNKNOWN";
+ }
+ printf("symbol %d [%s] type %s value %x\n", i,
+ strt + sym->st_name,
+ type, sym->st_value);
+ }
+
+ numrel = object->dyn.relsz / sizeof(Elf_Rel);
+ numrela = object->dyn.relasz / sizeof(Elf_RelA);
+
+ printf("numrel %d numrela %d\n", numrel, numrela);
+
+ printf("rel relocations:\n");
+ for (i = 0; i < numrel ; i++) {
+ Elf_Rel *rel = object->dyn.rel;
+ printf("%d: %x sym %x type %d\n", i, rel[i].r_offset,
+ ELF_R_SYM(rel[i].r_info), ELF_R_TYPE(rel[i].r_info));
+ }
+ printf("rela relocations:\n");
+ for (i = 0; i < numrela ; i++) {
+ Elf_RelA *rela = object->dyn.rela;
+ printf("%d: %x sym %x type %d\n", i, rela[i].r_offset,
+ ELF_R_SYM(rela[i].r_info), ELF_R_TYPE(rela[i].r_info));
+ }
+ needed_list = (Elf_Addr *)object->dyn.needed;
+ for (i = 0; needed_list[i] != NULL; i++) {
+ printf("NEEDED %s\n", needed_list[i] + strt);
+ }
+
+}
+#endif
+
+
+void
+elf_dump_footer(struct prebind_footer *footer)
+{
+ printf("\nbase %llx\n", (long long)footer->prebind_base);
+ printf("nameidx_idx %d\n", footer->nameidx_idx);
+ printf("symcache_idx %d\n", footer->symcache_idx);
+ printf("pltsymcache_idx %d\n", footer->pltsymcache_idx);
+ printf("fixupcnt_idx %d\n", footer->fixupcnt_idx);
+ printf("fixup_cnt %d\n", footer->fixup_cnt);
+ printf("nametab_idx %d\n", footer->nametab_idx);
+ printf("symcache_cnt %d\n", footer->symcache_cnt);
+ printf("pltsymcache_cnt %d\n", footer->pltsymcache_cnt);
+ printf("fixup_cnt %d\n", footer->fixup_cnt);
+ printf("numlibs %d\n", footer->numlibs);
+ printf("id0 %d\n", footer->id0);
+ printf("id1 %d\n", footer->id1);
+ printf("orig_size %lld\n", (long long)footer->orig_size);
+ printf("version %d\n", footer->prebind_version);
+ printf("bind_id %c%c%c%c\n", footer->bind_id[0],
+ footer->bind_id[1], footer->bind_id[2], footer->bind_id[3]);
+}
+
+
+void
+dump_symcachetab(struct symcachetab *symcachetab, int symcache_cnt,
+ struct elf_object *object, int id)
+{
+ int i;
+ printf("symcache for %s\n", object->load_name);
+ for (i = 0; i < symcache_cnt; i++) {
+ printf("symidx %d: obj %d sym %d\n",
+ symcachetab[i].idx,
+ symcachetab[i].obj_idx,
+ symcachetab[i].sym_idx);
+ }
+}
+
+void
+elf_print_prog_list (prog_list_ty *prog_list)
+{
+ struct elf_object *object;
+ struct proglist *pl;
+ TAILQ_FOREACH(pl, prog_list, list) {
+ object = TAILQ_FIRST(&(pl->curbin_list))->object;
+ printf("bin: %s\n", object->load_name);
+ elf_print_curbin_list(pl);
+ }
+}
+
+void
+elf_print_curbin_list(struct proglist *bin)
+{
+ struct objlist *ol;
+ TAILQ_FOREACH(ol, &(bin->curbin_list), list) {
+ printf("\t%s\n", ol->object->load_name);
+ }
+}
+
diff --git a/libexec/ld.so/prebind/objarray.c b/libexec/ld.so/prebind/objarray.c
new file mode 100644
index 00000000000..1c4f45f751c
--- /dev/null
+++ b/libexec/ld.so/prebind/objarray.c
@@ -0,0 +1,1073 @@
+/* $OpenBSD: objarray.c,v 1.1 2006/05/03 16:10:52 drahn 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"
+#include "machine/reloc.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 = malloc(sizeof (struct objlist));
+ ol->object = object;
+ TAILQ_INSERT_TAIL(&(curbin->curbin_list), ol, list);
+ 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 = malloc(sizeof (objarray[0]) * objarray_sz);
+}
+
+void
+elf_sum_reloc()
+{
+ int i, numobjs;
+ int err = 0;
+ struct objlist *ol;
+ struct proglist *pl;
+
+ 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 = calloc(sizeof(struct symcache_noflag),
+ objarray[i].obj->nchains);
+ objarray[i].pltsymcache = calloc(sizeof(struct symcache_noflag),
+ objarray[i].obj->nchains);
+
+ if (objarray[i].symcache == NULL ||
+ objarray[i].pltsymcache == NULL) {
+ printf("out of memory allocating symcache\n");
+ exit (20);
+ }
+
+ 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:\n");
+#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 = calloc(numobjs, sizeof (u_int32_t *));
+ pl->fixup = calloc(2 * numobjs, sizeof (struct fixup *));
+ pl->fixupcnt = calloc(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;
+ 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 = calloc(objarray_cnt, sizeof (int));
+ idxtolib = calloc(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 = calloc(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 = calloc(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 = calloc(numlibs, sizeof (struct nameidx));
+ nametab = malloc(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
+
+ 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 = calloc(objarray_cnt, sizeof (int));
+ idxtolib = calloc(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 0
+ 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 = calloc(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 = calloc(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++;
+ }
+
+ nameidx = calloc(numlibs, sizeof (struct nameidx));
+ nametab = malloc(nametablen);
+
+ if (nameidx == NULL || nametab == NULL)
+ perror("buffers");
+
+ 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
+ pl->libmapcnt = calloc(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];
+ }
+ 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];
+ }
+
+ pl->libmapcnt[i] = objarray[idxtolib[i]].numlibs;
+ 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);
+
+ 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;
+
+ /* 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);
+ 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 = calloc( 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 = calloc( 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:
+ 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\n",
+ object->load_name,
+ (long)(phdr[loadsection].p_vaddr));
+ goto done;
+ }
+
+ /* verify that extra slot is empty */
+ bzero(&phdr[loadsection], sizeof(phdr_empty));
+
+ ehdr->e_phnum--;
+
+done:
+ munmap(buf, 8192);
+}
+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] = calloc(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] = calloc(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->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);
+ }
+
+ numfixups++;
+ }
+ }
+ pl->fixupcnt[2*libidx+1] = numfixups;
+
+ pl->libmap[libidx] = calloc( 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 lib)
+{
+ struct objarray_list *newarray;
+ struct objlist *ol;
+ ol = malloc(sizeof (struct objlist));
+ ol->object = object;
+ if (lib)
+ 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(); /* XXX FIX */
+ objarray[objarray_cnt].id1 = arc4random();
+ 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, 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
+ );
+ }
+ }
+ 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
+ );
+ }
+ }
+ }
+ }
+}
+
+int
+write_txtbusy_file(char *name)
+{
+ char *prebind_name;
+ int fd;
+ int oldfd;
+ int err;
+ struct stat sb;
+ void *buf;
+ size_t len, wlen;
+
+printf("txtbusy processing %s\n", name);
+ 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 = malloc(BUFSZ);
+
+ fd = open(prebind_name, O_RDWR|O_CREAT|O_TRUNC, sb.st_mode);
+ printf("opened %s %d mode %o\n", prebind_name, fd, sb.st_mode);
+ oldfd = open(name, O_RDONLY);
+ printf("opened %s %d\n", name, oldfd);
+ 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;
+
+ objarray[objidx].symcache =
+ calloc(sizeof(struct symcache_noflag), object->nchains);
+ objarray[objidx].pltsymcache =
+ calloc(sizeof(struct symcache_noflag), object->nchains);
+
+ if (objarray[objidx].symcache == NULL ||
+ objarray[objidx].pltsymcache == NULL) {
+ printf("out of memory allocating symcache\n");
+ exit (20);
+ }
+
+ 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 = calloc(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);*/
+}
diff --git a/libexec/ld.so/prebind/prebind.8 b/libexec/ld.so/prebind/prebind.8
new file mode 100644
index 00000000000..bcc26c8ef7b
--- /dev/null
+++ b/libexec/ld.so/prebind/prebind.8
@@ -0,0 +1,60 @@
+.\" $OpenBSD: prebind.8,v 1.1 2006/05/03 16:10:52 drahn Exp $
+.\"
+.\" Copyright (c) 2006 Dale Rahn <drahn@openbsd.org>
+.\"
+.\" 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.
+.\"
+.Dd May 1, 2006
+.Dt PREBIND 8
+.Os
+.Sh NAME
+.Nm prebind
+.Nd cache symbol lookup information to speed up dynamic linking.
+.Sh SYNOPSIS
+.Nm prebind
+.Op Fl mv
+.Op Ar file/dir ...
+.Sh DESCRIPTION
+Parse each of the specified files or directories and process each ELF file
+(ELF file found in the directory) and the associated DT_NEEDED libraries
+and write symbol resolution hint information to each binary and library.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl m
+Merge the results of this prebind cache with the prebind information
+previously on any libraries referenced.
+.It Fl v
+Be verbose when running prebind, prints out information about
+the file/library that is bein processed.
+.Pp
+.Sh BUGS and CAVEATS
+Prebind uses a lot of memory depending on how many files/libraries
+are being processed.
+Handling of binaries where a required library has been removed is poor.
+.Sh SEE AlSO
+.Xr ld.so 1
+.Xr prebind_strip 1
+.Sh STANDARDS
+None
+.Sh HISTORY
+A
+.Nm
+utility first appeared in OpenBSD 4.0.
+.Nm
+is based loosely on Prelinking, however prelink removes the security
+feature of libraries appearing a random order on each invocation, thus
+it was incompatible with OpenBSD's Goals.
+.Nm
+was written as attempt to improve the speed of dynamic linking
+without the penalty of loss of security features.
diff --git a/libexec/ld.so/prebind/prebind.c b/libexec/ld.so/prebind/prebind.c
new file mode 100644
index 00000000000..bb10e124009
--- /dev/null
+++ b/libexec/ld.so/prebind/prebind.c
@@ -0,0 +1,1437 @@
+/* $OpenBSD: prebind.c,v 1.1 2006/05/03 16:10:52 drahn 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 <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;
+
+#define DEBUG
+
+/* TODO - library path from ldconfig */
+#define DEFAULT_PATH "/usr/lib:/usr/X11R6/lib:/usr/local/qte/lib"
+
+/* 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 */
+
+#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 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,
+ 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 lib);
+void elf_print_objarray(void);
+
+struct elf_object * elf_lookup_object(const char *name);
+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 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);
+
+int verbose; /* how verbose to be when operating */
+int merge_mode; /* merge (do not overwrite) existing prebind library info */
+
+struct elf_object *load_object;
+
+struct elf_object * load_file(const char *filename, int lib);
+void load_dir(char *name);
+void load_exe(char *name);
+
+void
+load_file_or_dir(char *name)
+{
+ struct stat sb;
+ int ret;
+
+ ret = lstat(name, &sb);
+ printf("ret\n");
+ if (ret != 0)
+ return;
+ printf("file or dir mode %d\n", sb.st_mode & S_IFMT);
+ switch(sb.st_mode & S_IFMT) {
+ case S_IFREG:
+ load_exe(name);
+ break;
+ case S_IFDIR:
+ printf("loading dir %s\n", name);
+ load_dir(name);
+ break;
+ default:
+ ; /* links and other files we skip */
+ }
+
+}
+void
+load_dir(char *name)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ struct stat sb;
+ char *buf;
+
+ dirp = opendir(name);
+ if (dirp == NULL) {
+ /* dir failed to open, skip */
+ 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);
+ case DT_REG:
+ asprintf(&buf, "%s/%s", name, dp->d_name);
+ load_exe(buf);
+ free (buf);
+ default:
+ /* other files symlinks, dirs, ... we ignore */
+ ;
+ }
+ }
+}
+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, 0);
+ if (load_object != NULL) {
+ TAILQ_FOREACH(ol, &(curbin->curbin_list), list) {
+ fail = load_obj_needed(ol->object);
+ if (fail != 0)
+ break; /* XXX */
+
+ }
+ interp = load_file(curbin->interp, 2);
+
+ /* slight abuse of this field */
+ object->load_object = interp;
+
+ if (fail == 0) {
+ elf_resolve_curbin();
+ elf_add_prog(curbin);
+ } else {
+ printf("failed to load %s\n", name);
+ elf_free_curbin_list(object);
+ free (curbin);
+ }
+ if (load_object != NULL) {
+ load_object = NULL;
+ }
+ }
+}
+
+struct elf_object *
+load_file(const char *filename, int lib)
+{
+ int fd = -1;
+ void *buf = NULL;
+ struct stat ifstat;
+ Elf_Ehdr *pehdr;
+ Elf_Shdr *pshdr;
+ char *pexe;
+#ifdef DEBUG1
+ int i;
+#endif
+ struct elf_object *obj = NULL;
+
+
+ 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)) {
+ if (verbose > 0)
+ printf("%s: short file\n", filename);
+ goto done;
+ }
+
+ obj = elf_lookup_object_devino( ifstat.st_dev, ifstat.st_ino);
+ 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;
+ }
+
+ pehdr = (Elf_Ehdr *) buf;
+
+ if (IS_ELF(*pehdr) == 0) {
+ goto done;
+ }
+
+ if( pehdr->e_machine != ELF_TARG_MACH) {
+ if (verbose > 0)
+ printf("%s: wrong arch\n", filename);
+ goto done;
+ }
+
+ pexe = buf;
+ if (pehdr->e_shstrndx == 0) {
+ goto done;
+ }
+ pshdr = (Elf_Shdr *) (pexe + pehdr->e_shoff +
+ (pehdr->e_shstrndx * pehdr->e_shentsize));
+
+
+#if 0
+printf("e_ehsize %x\n", pehdr->e_ehsize);
+printf("e_phoff %x\n", pehdr->e_phoff);
+printf("e_shoff %x\n", pehdr->e_shoff);
+printf("e_phentsize %x\n", pehdr->e_phentsize);
+printf("e_phnum %x\n", pehdr->e_phnum);
+printf("e_shentsize %x\n", pehdr->e_shentsize);
+printf("e_shstrndx %x\n\n", pehdr->e_shstrndx);
+#endif
+
+ shstrtab = (char *) (pexe + pshdr->sh_offset);
+
+
+ obj = elf_load_object(pexe, filename);
+
+
+
+ munmap(buf, ifstat.st_size);
+ buf = NULL;
+
+ if (obj != NULL) {
+ obj->dev = ifstat.st_dev;
+ obj->inode = ifstat.st_ino;
+ if (load_object == NULL)
+ load_object = obj;
+
+ elf_add_object(obj, lib);
+
+#ifdef DEBUG1
+ dump_info(obj);
+#endif
+ }
+ if (lib == 1 && merge_mode == 1) {
+ /*
+ * for libraries, 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;
+}
+
+void __dead
+usage()
+{
+ extern char *__progname;
+ printf("%s [-v] {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 > 1) {
+ 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)
+{
+ int i;
+ 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;
+
+ 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) {
+ return NULL; /* XXX ??? */
+ }
+
+ 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 0
+ if (object->Dyn.info[DT_SONAME])
+ map_to_virt(phdr, ehdr, loff, &object->Dyn.info[DT_SONAME]);
+#endif
+ 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);
+ bcopy(object->dyn.strtab, str, object->dyn.strsz);
+ object->dyn.strtab = str;
+ strt = str;
+
+ sym = malloc(object->nchains * sizeof(Elf_Sym));
+ 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);
+ 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);
+ 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);
+ 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);
+
+
+ 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;
+ }
+ }
+}
+
+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;
+}
+
+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
+ */
+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 1
+ 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);
+#endif
+ 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, 1);
+ }
+ 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)
+{
+ 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.
+ *
+ * Note 1: If 'merge' mode is ever written, this will need to keep
+ * the 'cached' copies symbols and do fixups for the rest, regardless
+ * of conflicts
+ *
+ * Note 2: 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;
+ for (i = 0; i < nsyms; i++) {
+ if (scache[i].obj != NULL &&
+ (scache[i].obj->dyn.null != prog->dyn.null ||
+ obj->dyn.null == prog->dyn.null) &&
+ scache[i].obj != prog->load_object) {
+ if (tcache[i].obj != NULL) {
+ if (scache[i].obj != tcache[i].obj) {
+ if (verbose > 2) {
+ printf("sym mismatch %d: "
+ "obj %d: sym %ld %s "
+ "nobj %s oobj %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,
+ tcache[i].obj->load_name);
+ }
+
+#if 0
+ if (tcache[i].obj != badobj)
+ printf("%s: %s conflict\n",
+ obj->load_name,
+ scache[i].sym->st_name +
+ scache[i].obj->dyn.strtab);
+#endif
+ tcache[i].obj = badobj;
+ tcache[i].sym = NULL;
+ }
+ } else {
+ if (scache[i].obj != prog) {
+#if 0
+ printf("%s: %s copying\n",
+ obj->load_name,
+ scache[i].sym->st_name +
+ scache[i].obj->dyn.strtab);
+#endif
+ tcache[i].sym = scache[i].sym;
+ tcache[i].obj = scache[i].obj;
+ }
+ }
+
+#if 0
+ printf("symidx %d: obj %d sym %ld %s\n",
+ i, scache[i].obj->dyn.null,
+ scache[i].sym -
+ scache[i].obj->dyn.symtab,
+ scache[i].sym->st_name +
+ scache[i].obj->dyn.strtab
+ );
+#endif
+ }
+ }
+}
+
+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)
+{
+ struct objlist *ol;
+ TAILQ_FOREACH(ol, &(curbin->curbin_list), list) {
+ if (ol->object->dev == dev &&
+ ol->object->inode == inode)
+ return ol->object;
+ }
+ TAILQ_FOREACH(ol, &library_list, list) {
+ if (ol->object->dev == dev &&
+ ol->object->inode == inode) {
+ 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) {
+#if 0
+ printf("found sym %s in obj %s\n", name, ol->object->load_name);
+#endif
+ 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 0
+ printf("found sym %s in obj %s %d\n", name,
+ weak_obj->load_name, flags);
+#endif
+ }
+ if (found == 1) {
+#if 0
+ printf("object %s sym %s, ref_object %s flags %d\n",
+ object->load_name, name,
+ ref_object->load_name, flags);
+#endif
+ 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) {
+#if 0
+ printf("found sym %s in obj %s\n", name, ol->object->load_name);
+#endif
+ 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 0
+ printf("found weak sym %s in obj %s\n", name, weak_obj->load_name);
+#endif
+ }
+ if (found == 1) {
+#if 0
+ printf("object %s sym %s, ref_object %s %s\n",
+ object->load_name, name,
+ ref_object->load_name,
+ (flags & SYM_PLT) ? "plt" : "got");
+
+#endif
+ 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, struct symcache_noflag *symcache,
+ struct symcache_noflag *pltsymcache)
+{
+ int numrel;
+ int numrela;
+ int i;
+ const Elf_Sym *sym;
+ Elf_Rel *rel;
+ Elf_RelA *rela;
+ numrel = object->dyn.relsz / sizeof(Elf_Rel);
+#if 0
+ printf("rel relocations: %d\n", numrel);
+#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]);
+ 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);
+#if 0
+ 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);
+ 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);
+ }
+ }
+ }
+}
+
+void
+elf_resolve_curbin(void)
+{
+ struct objlist *ol;
+
+#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);
+ exit(20);
+ }
+ elf_reloc(ol->object, ol->cache, ol->pltcache);
+ }
+}
diff --git a/libexec/ld.so/prebind/prebind_struct.h b/libexec/ld.so/prebind/prebind_struct.h
new file mode 100644
index 00000000000..2c69105211b
--- /dev/null
+++ b/libexec/ld.so/prebind/prebind_struct.h
@@ -0,0 +1,64 @@
+struct symcache_noflag {
+ const elf_object_t *obj;
+ const Elf_Sym *sym;
+};
+
+struct objlist {
+ TAILQ_ENTRY(objlist) list;
+ TAILQ_ENTRY(objlist) inst_list;
+ struct elf_object *load_prog;
+ struct elf_object *object;
+ struct symcache_noflag *cache;
+ struct symcache_noflag *pltcache;
+};
+
+struct proglist {
+ TAILQ_ENTRY(proglist) list;
+ TAILQ_HEAD(, objlist) curbin_list;
+ struct fixup **fixup;
+ int *fixupcnt;
+ int nobj;
+ u_int32_t **libmap;
+ u_int32_t *libmapcnt;
+ char *interp;
+};
+extern struct proglist *curbin;
+extern struct elf_object *load_object;
+
+
+typedef TAILQ_HEAD(, proglist) prog_list_ty;
+typedef TAILQ_HEAD(, objlist) obj_list_ty;
+
+extern obj_list_ty library_list;
+extern prog_list_ty prog_list;
+
+/* debug */
+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,
+ struct symcache_noflag *scache, struct elf_object *obj,
+ struct elf_object *prog, int nsyms);
+int elf_prep_lib_prebind(struct elf_object *object);
+int elf_prep_bin_prebind(struct proglist *pl);
+void elf_calc_fixups(struct proglist *pl, struct objlist *ol, int libidx);
+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);
+
+void dump_symcachetab(struct symcachetab *symcachetab, int symcache_cnt, struct elf_object *object, int id);
+void dump_info(struct elf_object *object);
+void elf_clear_prog_load(int fd, struct elf_object *object);
+void elf_fixup_prog_load(int fd, struct prebind_footer *footer,
+ struct elf_object *object);
+void elf_dump_footer(struct prebind_footer *footer);
+
+extern int verbose;
+void elf_load_existing_prebind(struct elf_object *object, int fd);
diff --git a/libexec/ld.so/prebind/sod.c b/libexec/ld.so/prebind/sod.c
new file mode 100644
index 00000000000..f92213cf867
--- /dev/null
+++ b/libexec/ld.so/prebind/sod.c
@@ -0,0 +1,265 @@
+/* $OpenBSD: sod.c,v 1.1 2006/05/03 16:10:52 drahn Exp $ */
+
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/syslimits.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <nlist.h>
+#include <link.h>
+#include <limits.h>
+#include <machine/exec.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#if 0
+#include "syscall.h"
+#include "archdep.h"
+#include "util.h"
+#endif
+#include "sod.h"
+
+int _dl_hinthash(char *cp, int vmajor, int vminor);
+void _dl_maphints(void);
+
+/*
+ * Populate sod struct for dlopen's call to map_object
+ */
+void
+_dl_build_sod(const char *name, struct sod *sodp)
+{
+ unsigned int tuplet;
+ int major, minor;
+ char *realname, *tok, *etok, *cp;
+
+ /* default is an absolute or relative path */
+ sodp->sod_name = (long)strdup(name); /* strtok is destructive */
+ sodp->sod_library = 0;
+ sodp->sod_major = sodp->sod_minor = 0;
+
+ /* does it look like /^lib/ ? */
+ if (strncmp((char *)sodp->sod_name, "lib", 3) != 0)
+ goto backout;
+
+ /* is this a filename? */
+ if (strchr((char *)sodp->sod_name, '/'))
+ goto backout;
+
+ /* skip over 'lib' */
+ cp = (char *)sodp->sod_name + 3;
+
+ realname = cp;
+
+ /* dot guardian */
+ if ((strchr(cp, '.') == NULL) || (*(cp+strlen(cp)-1) == '.'))
+ goto backout;
+
+ cp = strstr(cp, ".so");
+ if (cp == NULL)
+ goto backout;
+
+ /* default */
+ major = minor = -1;
+
+ /* loop through name - parse skipping name */
+ for (tuplet = 0; (tok = strsep(&cp, ".")) != NULL; tuplet++) {
+ switch (tuplet) {
+ case 0:
+ /* empty tok, we already skipped to "\.so.*" */
+ break;
+ case 1:
+ /* 'so' extension */
+ break;
+ case 2:
+ /* major version extension */
+ major = strtol(tok, &etok, 10);
+ if (*tok == '\0' || *etok != '\0')
+ goto backout;
+ break;
+ case 3:
+ /* minor version extension */
+ minor = strtol(tok, &etok, 10);
+ if (*tok == '\0' || *etok != '\0')
+ goto backout;
+ break;
+ /* if we get here, it must be weird */
+ default:
+ goto backout;
+ }
+ }
+ if (realname == NULL)
+ goto backout;
+ cp = (char *)sodp->sod_name;
+ sodp->sod_name = (long)strdup(realname);
+ free(cp);
+ sodp->sod_library = 1;
+ sodp->sod_major = major;
+ sodp->sod_minor = minor;
+ return;
+
+backout:
+ free((char *)sodp->sod_name);
+ sodp->sod_name = (long)strdup(name);
+}
+
+static struct hints_header *hheader = NULL;
+static struct hints_bucket *hbuckets;
+static char *hstrtab;
+char *_dl_hint_search_path = NULL;
+
+#define HINTS_VALID (hheader != NULL && hheader != (struct hints_header *)-1)
+
+void
+_dl_maphints(void)
+{
+ struct stat sb;
+ caddr_t addr = MAP_FAILED;
+ long hsize = 0;
+ int hfd;
+
+ if ((hfd = open(_PATH_LD_HINTS, O_RDONLY)) < 0)
+ goto bad_hints;
+
+ if (fstat(hfd, &sb) != 0 || !S_ISREG(sb.st_mode) ||
+ sb.st_size < sizeof(struct hints_header) || sb.st_size > LONG_MAX)
+ goto bad_hints;
+
+ hsize = (long)sb.st_size;
+ addr = (void *)mmap(0, hsize, PROT_READ, MAP_PRIVATE, hfd, 0);
+ if (addr == MAP_FAILED)
+ goto bad_hints;
+
+ hheader = (struct hints_header *)addr;
+ if (HH_BADMAG(*hheader) || hheader->hh_ehints > hsize)
+ goto bad_hints;
+
+ if (hheader->hh_version != LD_HINTS_VERSION_1 &&
+ hheader->hh_version != LD_HINTS_VERSION_2)
+ goto bad_hints;
+
+ hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab);
+ hstrtab = (char *)(addr + hheader->hh_strtab);
+ if (hheader->hh_version >= LD_HINTS_VERSION_2)
+ _dl_hint_search_path = hstrtab + hheader->hh_dirlist;
+
+ /* close the file descriptor, leaving the hints mapped */
+ close(hfd);
+
+ return;
+
+bad_hints:
+ if (addr != MAP_FAILED)
+ munmap(addr, hsize);
+ if (hfd != -1)
+ close(hfd);
+ hheader = (struct hints_header *)-1;
+}
+
+char *
+_dl_findhint(char *name, int major, int minor, char *preferred_path)
+{
+ struct hints_bucket *bp;
+
+ /*
+ * If not mapped, and we have not tried before, try to map the
+ * hints, if previous attempts failed hheader is -1 and we
+ * do not wish to retry it.
+ */
+ if (hheader == NULL)
+ _dl_maphints();
+
+ /* if it failed to map, return failure */
+ if (!(HINTS_VALID))
+ return NULL;
+
+ bp = hbuckets + (_dl_hinthash(name, major, minor) % hheader->hh_nbucket);
+
+ while (1) {
+ /* Sanity check */
+ if (bp->hi_namex >= hheader->hh_strtab_sz) {
+ printf("Bad name index: %#x\n", bp->hi_namex);
+ exit(7);
+ break;
+ }
+ if (bp->hi_pathx >= hheader->hh_strtab_sz) {
+ printf("Bad path index: %#x\n", bp->hi_pathx);
+ exit(7);
+ break;
+ }
+
+ if (strcmp(name, hstrtab + bp->hi_namex) == 0) {
+ /* It's `name', check version numbers */
+ if (bp->hi_major == major &&
+ (bp->hi_ndewey < 2 || bp->hi_minor >= minor)) {
+ if (preferred_path == NULL) {
+ return hstrtab + bp->hi_pathx;
+ } else {
+ char *path = hstrtab + bp->hi_pathx;
+ char *edir = strrchr(path, '/');
+
+ if ((strncmp(preferred_path, path,
+ (edir - path)) == 0) &&
+ (preferred_path[edir - path] == '\0'))
+ return path;
+ }
+ }
+ }
+
+ if (bp->hi_next == -1)
+ break;
+
+ /* Move on to next in bucket */
+ bp = &hbuckets[bp->hi_next];
+ }
+
+ /* No hints available for name */
+ return NULL;
+}
+
+int
+_dl_hinthash(char *cp, int vmajor, int vminor)
+{
+ int k = 0;
+
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
+ if (hheader->hh_version == LD_HINTS_VERSION_1)
+ k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff;
+
+ return k;
+}
diff --git a/libexec/ld.so/prebind_strip/Makefile b/libexec/ld.so/prebind_strip/Makefile
new file mode 100644
index 00000000000..6b0fa03bbd9
--- /dev/null
+++ b/libexec/ld.so/prebind_strip/Makefile
@@ -0,0 +1,13 @@
+# $OpenBSD: Makefile,v 1.1 2006/05/03 16:10:52 drahn Exp $
+
+SRCS= prebind_strip.c
+
+PROG= prebind_strip
+MAN= prebind_strip.8
+
+BINDIR=/usr/sbin
+
+CFLAGS += -Wall -ggdb
+CFLAGS += -I${.CURDIR}/..
+
+.include <bsd.prog.mk>
diff --git a/libexec/ld.so/prebind_strip/prebind_strip.8 b/libexec/ld.so/prebind_strip/prebind_strip.8
new file mode 100644
index 00000000000..725a00d3eff
--- /dev/null
+++ b/libexec/ld.so/prebind_strip/prebind_strip.8
@@ -0,0 +1,44 @@
+.\" $OpenBSD: prebind_strip.8,v 1.1 2006/05/03 16:10:52 drahn Exp $
+.\"
+.\" Copyright (c) 2006 Dale Rahn <drahn@openbsd.org>
+.\"
+.\" 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.
+.\"
+.Dd May 1, 2006
+.Dt PREBIND_STRIP 8
+.Os
+.Sh NAME
+.Nm prebind_strip
+.Nd Remove prebind info from binaries and libraries.
+.Sh SYNOPSIS
+.Nm prebind_strip
+.Op Ar file ...
+.Sh DESCRIPTION
+Remove any prebind information from a binary or shared library.
+After this is run the library length and md5 should match the original value.
+.Sh SEE AlSO
+.Xr ld.so 1
+.Xr prebind 8
+.Sh STANDARDS
+None
+.Sh HISTORY
+A
+.Nm
+utility first appeared in OpenBSD 4.0.
+.Nm
+is based loosely on Prelinking, however prelink removes the security
+feature of libraries appearing a random order on each invocation, thus
+it was incompatible with OpenBSD's Goals.
+.Nm
+was written as attempt to improve the speed of dynamic linking
+without the penalty of loss of security features.
diff --git a/libexec/ld.so/prebind_strip/prebind_strip.c b/libexec/ld.so/prebind_strip/prebind_strip.c
new file mode 100644
index 00000000000..135626f7439
--- /dev/null
+++ b/libexec/ld.so/prebind_strip/prebind_strip.c
@@ -0,0 +1,125 @@
+/* $OpenBSD: prebind_strip.c,v 1.1 2006/05/03 16:10:52 drahn 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/mman.h>
+#include <sys/exec_elf.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include "prebind.h"
+
+void dump_prebind(char *file);
+void prebind_dump_footer(struct prebind_footer *footer, char *file);
+void prebind_dump_symcache(struct symcachetab *symcachetab, u_int32_t cnt);
+void prebind_dump_nameidx(struct nameidx *nameidx, u_int32_t numblibs,
+ char *nametab);
+void prebind_dump_fixup(struct fixup *fixup, u_int32_t numfixups);
+void prebind_dump_libmap(u_int32_t *libmap, u_int32_t numlibs, void *a);
+
+void prebind_remove_load_section(int fd, char *name);
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ for (i = 1; i < argc; i++) {
+ printf("stripping %s\n", argv[i]);
+ dump_prebind(argv[i]);
+ }
+
+ return 0;
+}
+
+void
+dump_prebind(char *file)
+{
+ struct prebind_footer footer;
+ int fd;
+ ssize_t bytes;
+
+ fd = open(file, O_RDWR);
+ if (fd == -1) {
+ perror(file);
+ return;
+ }
+ lseek(fd, -((off_t)sizeof(struct prebind_footer)), SEEK_END);
+ bytes = read(fd, &footer, sizeof(struct prebind_footer));
+ if (bytes != sizeof(struct prebind_footer)) {
+ perror("short read\n");
+ goto done;
+ }
+
+ 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) {
+
+ } else {
+ printf("%s: no prebind header\n", file);
+ goto done;
+ }
+
+ prebind_remove_load_section(fd, file);
+
+ ftruncate(fd, footer.orig_size);
+done:
+ close(fd);
+}
+
+void
+prebind_remove_load_section(int fd, char *name)
+{
+ void *buf;
+ Elf_Ehdr *ehdr;
+ Elf_Phdr *phdr;
+ int loadsection;
+
+ buf = mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_FILE | MAP_SHARED,
+ fd, 0);
+ if (buf == MAP_FAILED) {
+ perror(name);
+ printf("%s: cannot mmap for write\n", name);
+ return;
+ }
+
+ ehdr = (Elf_Ehdr *) buf;
+ phdr = (Elf_Phdr *)((char *)buf + ehdr->e_phoff);
+
+ loadsection = ehdr->e_phnum - 1;
+
+ if(ehdr->e_type != ET_EXEC ||
+ (phdr[loadsection].p_flags & 0x08000000) == 0) {
+ goto done;
+ }
+
+ 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\n", name,
+ (long)(phdr[loadsection].p_vaddr));
+ goto done;
+ }
+
+ bzero(&phdr[loadsection], sizeof(Elf_Phdr));
+
+ ehdr->e_phnum--;
+done:
+ munmap(buf, 8192);
+}
diff --git a/libexec/ld.so/resolve.c b/libexec/ld.so/resolve.c
index fc72d807584..bef723cc59a 100644
--- a/libexec/ld.so/resolve.c
+++ b/libexec/ld.so/resolve.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: resolve.c,v 1.46 2005/11/09 16:41:29 kurt Exp $ */
+/* $OpenBSD: resolve.c,v 1.47 2006/05/03 16:10:51 drahn Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -35,6 +35,7 @@
#include "syscall.h"
#include "archdep.h"
#include "resolve.h"
+#include "dl_prebind.h"
elf_object_t *_dl_objects;
elf_object_t *_dl_last_object;
@@ -249,6 +250,7 @@ sym_cache *_dl_symcache;
int _dl_symcachestat_hits;
int _dl_symcachestat_lookups;
+
Elf_Addr
_dl_find_symbol_bysym(elf_object_t *req_obj, unsigned int symidx,
const Elf_Sym **this, int flags, const Elf_Sym *ref_sym, const elf_object_t **pobj)
@@ -270,6 +272,8 @@ _dl_find_symbol_bysym(elf_object_t *req_obj, unsigned int symidx,
*this = _dl_symcache[symidx].sym;
if (pobj)
*pobj = sobj;
+ if (_dl_prebind_validate) /* XXX */
+ prebind_validate(req_obj, symidx, flags, ref_sym);
return sobj->load_offs;
}
@@ -283,6 +287,15 @@ _dl_find_symbol_bysym(elf_object_t *req_obj, unsigned int symidx,
*pobj = sobj;
if (_dl_symcache != NULL && symidx < req_obj->nchains) {
+#if 0
+ DL_DEB(("cache miss %d %p %p, %p %p %s %s %d %d %s\n",
+ symidx,
+ _dl_symcache[symidx].sym, *this,
+ _dl_symcache[symidx].obj, sobj, sobj->load_name,
+ sobj->dyn.strtab + (*this)->st_name,
+ _dl_symcache[symidx].flags, flags, req_obj->load_name));
+#endif
+
_dl_symcache[symidx].sym = *this;
_dl_symcache[symidx].obj = sobj;
_dl_symcache[symidx].flags = flags;
diff --git a/libexec/ld.so/resolve.h b/libexec/ld.so/resolve.h
index d3c20b1bdcf..2eb39d3d251 100644
--- a/libexec/ld.so/resolve.h
+++ b/libexec/ld.so/resolve.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: resolve.h,v 1.50 2005/11/09 16:41:29 kurt Exp $ */
+/* $OpenBSD: resolve.h,v 1.51 2006/05/03 16:10:51 drahn Exp $ */
/*
* Copyright (c) 1998 Per Fogelstrom, Opsycon AB
@@ -136,6 +136,8 @@ struct elf_object {
/* object that caused this module to be loaded, used in symbol lookup */
elf_object_t *load_object;
+ void *prebind_data;
+
/* for object confirmation */
dev_t dev;
ino_t inode;
diff --git a/libexec/ld.so/sparc/ldasm.S b/libexec/ld.so/sparc/ldasm.S
index 41304417ab3..1b210378132 100644
--- a/libexec/ld.so/sparc/ldasm.S
+++ b/libexec/ld.so/sparc/ldasm.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldasm.S,v 1.14 2004/05/25 15:56:18 deraadt Exp $ */
+/* $OpenBSD: ldasm.S,v 1.15 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 2001 Jason L. Wright (jason@thought.net)
@@ -319,6 +319,18 @@ _dl_sigprocmask:
retl
clr %o0
+
+ .section ".text"
+ .align 4
+ .global _dl_gettimeofday
+ .type _dl_gettimeofday,@function
+_dl_gettimeofday:
+ mov SYS_gettimeofday | SYSCALL_G2RFLAG, %g1 ! calling sys_gettimeofday
+ add %o7, 8, %g2 ! just return on success
+ t ST_SYSCALL ! off to wonderland
+ retl
+ sub %g0, %o0, %o0 ! error: result = -errno
+
/*
* V8 sparc .{,u}{mul,div,rem} replacements.
* We try to mimic them 100%. Full 64 bit sources or outputs, and
diff --git a/libexec/ld.so/sparc/syscall.h b/libexec/ld.so/sparc/syscall.h
index 92ebc12d3d3..bb07f56cab0 100644
--- a/libexec/ld.so/sparc/syscall.h
+++ b/libexec/ld.so/sparc/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.7 2004/05/25 15:56:18 deraadt Exp $ */
+/* $OpenBSD: syscall.h,v 1.8 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -53,6 +53,7 @@ int _dl_fcntl(int, int, ...);
int _dl_getdirentries(int, char*, int, long *);
int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
int _dl_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+int _dl_gettimeofday(struct timeval *tp, struct timezone *tzp);
static inline off_t
_dl_lseek(int fildes, off_t offset, int whence)
diff --git a/libexec/ld.so/sparc64/ldasm.S b/libexec/ld.so/sparc64/ldasm.S
index dcf8186fa96..332bc13ebd8 100644
--- a/libexec/ld.so/sparc64/ldasm.S
+++ b/libexec/ld.so/sparc64/ldasm.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: ldasm.S,v 1.23 2004/05/25 15:56:19 deraadt Exp $ */
+/* $OpenBSD: ldasm.S,v 1.24 2006/05/03 16:10:52 drahn Exp $ */
/* $NetBSD: rtld_start.S,v 1.5 2001/08/14 22:17:48 eeh Exp $ */
/*
@@ -315,3 +315,11 @@ _ENTRY(_dl_sysctl)
t ST_SYSCALL ! off to wonderland
retl
sub %g0, %o0, %o0 ! error: result = -errno
+
+_ENTRY(_dl_gettimeofday)
+ mov SYS_gettimeofday | SYSCALL_G2RFLAG, %g1 ! calling sys_gettimeofday
+ add %o7, 8, %g2 ! just return on success
+ t ST_SYSCALL ! off to wonderland
+ retl
+ sub %g0, %o0, %o0 ! error: result = -errno
+
diff --git a/libexec/ld.so/sparc64/syscall.h b/libexec/ld.so/sparc64/syscall.h
index f6b0638ff04..45c05b0dcbc 100644
--- a/libexec/ld.so/sparc64/syscall.h
+++ b/libexec/ld.so/sparc64/syscall.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: syscall.h,v 1.14 2003/07/06 20:04:00 deraadt Exp $ */
+/* $OpenBSD: syscall.h,v 1.15 2006/05/03 16:10:52 drahn Exp $ */
/*
* Copyright (c) 2001 Niklas Hallqvist
@@ -53,6 +53,7 @@ int _dl_fcntl(int, int, ...);
int _dl_getdirentries(int, char*, int, long *);
int _dl_sigprocmask(int, const sigset_t *, sigset_t *);
int _dl_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+int _dl_gettimeofday(struct timeval *tp, struct timezone *tzp);
static inline off_t
_dl_lseek(int fildes, off_t offset, int whence)