* finding or making overcommit--main--1.0--patch-26
* finding or making ldver--patch--1.0--patch-10
* auto-adding kostikbel@ukr.net--2005-freebsd/ldver--patch--1.0--patch-10 to greedy revision library /usr/home/kostik/tla-libraries
* found immediate ancestor revision in library (kostikbel@ukr.net--2005-freebsd/ldver--patch--1.0--patch-9)
* patching for this revision (kostikbel@ukr.net--2005-freebsd/ldver--patch--1.0--patch-10)
* computing changeset
A/ {arch}/ldver
A/ {arch}/ldver/ldver--patch
A/ {arch}/ldver/ldver--patch/ldver--patch--1.0
A/ {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd
A/ {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log
A  {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/base-0
A  {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-1
A  {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-10
A  {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-2
A  {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-3
A  {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-4
A  {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-5
A  {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-6
A  {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-7
A  {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-8
A  {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-9
M  libexec/rtld-elf/Makefile
M  libexec/rtld-elf/debug.c
M  libexec/rtld-elf/i386/reloc.c
M  libexec/rtld-elf/map_object.c
M  libexec/rtld-elf/rtld.c
M  libexec/rtld-elf/rtld.h
M  sys/sys/elf32.h
M  sys/sys/elf64.h
M  sys/sys/elf_common.h
M  sys/sys/elf_generic.h
* changeset report
* added directories

    {arch}/ldver
    {arch}/ldver/ldver--patch
    {arch}/ldver/ldver--patch/ldver--patch--1.0
    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd
    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log

* added files

    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/base-0
    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-1
    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-10
    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-2
    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-3
    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-4
    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-5
    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-6
    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-7
    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-8
    {arch}/ldver/ldver--patch/ldver--patch--1.0/kostikbel@ukr.net--2005-freebsd/patch-log/patch-9

* modified files

--- orig/libexec/rtld-elf/Makefile
+++ mod/libexec/rtld-elf/Makefile
@@ -6,7 +6,7 @@
 		malloc.c xmalloc.c debug.c libmap.c
 MAN=		rtld.1
 CSTD?=		gnu99
-CFLAGS+=	-Wall -DFREEBSD_ELF -DIN_RTLD
+CFLAGS+=	-Wall -DFREEBSD_ELF -DIN_RTLD -DDEBUG -g
 CFLAGS+=	-I${.CURDIR}/${MACHINE_ARCH} -I${.CURDIR}
 LDFLAGS+=	-nostdlib -e .rtld_start
 INSTALLFLAGS=	-C -b


--- orig/libexec/rtld-elf/debug.c
+++ mod/libexec/rtld-elf/debug.c
@@ -141,3 +141,38 @@
     }
     return;
 }
+
+void
+dump_vers(Obj_Entry *obj)
+{
+	int i, j;
+	Elf_Verneed *vn = (Elf_Verneed *)(obj->verneed);
+	Elf_Verdef *vd = (Elf_Verdef *)(obj->verdef);
+
+	printf("VerInfo %s need %lu def %lu\n", obj->path, obj->verneednum, obj->verdefnum);
+
+	for (i = 0; i < obj->verneednum; i++) {
+		Elf_Vernaux *aux = (Elf_Vernaux *)((caddr_t)vn + vn->vn_aux);
+		printf("VERNEED %d ver %d cnt %d %s\n", i,
+		       vn->vn_version, vn->vn_cnt, (char *)(obj->strtab + vn->vn_file));
+		for (j = 0; j < vn->vn_cnt; j++) {
+			printf("  AUX %d flg %x other %d %s\n", j,
+			       aux->vna_flags, aux->vna_other,
+			       (char *)(obj->strtab + aux->vna_name));
+			aux = (Elf_Vernaux *)((caddr_t)aux + aux->vna_next);
+		}
+		vn = (Elf_Verneed *)((caddr_t)vn + vn->vn_next);
+	}
+
+	for (i = 0; i < obj->verdefnum; i++) {
+		Elf_Verdaux *aux = (Elf_Verdaux *)((caddr_t)vd + vd->vd_aux);
+		printf("VERDEF %d ver %d flg %x ndx %d cnt %d\n", i,
+		       vd->vd_version, vd->vd_flags, vd->vd_ndx, vd->vd_cnt);
+		for (j = 0; j < vd->vd_cnt; j++) {
+			printf("  AUX %d %s\n", j,
+			       (char *)(obj->strtab + aux->vda_name));
+			aux = (Elf_Verdaux *)((caddr_t)aux + aux->vda_next);
+		}
+		vd = (Elf_Verdef *)((caddr_t)vd + vd->vd_next);
+	}
+}


--- orig/libexec/rtld-elf/i386/reloc.c
+++ mod/libexec/rtld-elf/i386/reloc.c
@@ -75,15 +75,18 @@
 	    const void *srcaddr;
 	    const Elf_Sym *srcsym;
 	    Obj_Entry *srcobj;
+	    const VerInfo *vi;
 
 	    dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
 	    dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
 	    name = dstobj->strtab + dstsym->st_name;
 	    hash = elf_hash(name);
 	    size = dstsym->st_size;
+	    if (get_verinfo(dstobj, ELF_R_SYM(rel->r_info), &vi) == -1)
+		    return -1;
 
 	    for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next)
-		if ((srcsym = symlook_obj(name, hash, srcobj, false)) != NULL)
+		if ((srcsym = symlook_obj(name, hash, vi, srcobj, false)) != NULL)
 		    break;
 
 	    if (srcobj == NULL) {


--- orig/libexec/rtld-elf/map_object.c
+++ mod/libexec/rtld-elf/map_object.c
@@ -326,6 +326,7 @@
     }
     free(obj->origin_path);
     free(obj->priv);
+    free(obj->verinfo);
     free(obj);
 }
 


--- orig/libexec/rtld-elf/rtld.c
+++ mod/libexec/rtld-elf/rtld.c
@@ -121,9 +121,10 @@
 static const void **get_program_var_addr(const char *name);
 static void set_program_var(const char *, const void *);
 static const Elf_Sym *symlook_default(const char *, unsigned long hash,
-  const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt);
+  const Obj_Entry *refobj, const VerInfo *vi,
+  const Obj_Entry **defobj_out, bool in_plt);
 static const Elf_Sym *symlook_list(const char *, unsigned long,
-  Objlist *, const Obj_Entry **, bool in_plt, DoneList *);
+  const VerInfo *vi, Objlist *, const Obj_Entry **, bool in_plt, DoneList *);
 static void trace_loaded_objects(Obj_Entry *obj);
 static void unlink_object(Obj_Entry *);
 static void unload_object(Obj_Entry *);
@@ -359,6 +360,11 @@
     linkmap_add(obj_main);
     linkmap_add(&obj_rtld);
 
+    if (debug) {
+	    dump_vers(obj_main);
+	    dump_vers(&obj_rtld);
+    }
+
     /* Link the main program into the list of objects. */
     *obj_tail = obj_main;
     obj_tail = &obj_main->next;
@@ -545,6 +551,101 @@
     errx(1, "%s", msg);
 }
 
+/* Do the version info digest */
+static void
+digest_versions(Obj_Entry *obj)
+{
+	long max_idx = -1;
+	long i, j;
+	const Elf_Verdef *vd;
+	const Elf_Verdaux *vd_aux;
+	const Elf_Verneed *vn;
+	const Elf_Vernaux *vn_aux;
+	VerInfo *vi;
+
+	if (obj->verdefnum > 0) {
+		vd = (const Elf_Verdef *)(obj->verdef);
+		for (i = 0; i < obj->verdefnum; i++) {
+			if (vd->vd_version != VER_DEF_CURRENT) {
+				_rtld_error("%s: invalid Verdef version %d", obj->path, vd->vd_version);
+				die();
+			}
+			if (vd->vd_ndx > max_idx)
+				max_idx = vd->vd_ndx;
+			vd = (const Elf_Verdef *)((caddr_t)vd + vd->vd_next);
+		}
+	}
+
+	if (obj->verneednum > 0)
+	{
+		vn = (const Elf_Verneed *)(obj->verneed);
+		for (i = 0; i < obj->verneednum; i++) {
+			if (vn->vn_version != VER_NEED_CURRENT) {
+				_rtld_error("%s: invalid Verneed version %d", obj->path, vn->vn_version);
+				die();
+			}
+			vn_aux = (const Elf_Vernaux *)((caddr_t)vn + vn->vn_aux);
+			for (j = 0; j < vn->vn_cnt; j++) {
+				if (max_idx < vn_aux->vna_other)
+					max_idx = vn_aux->vna_other;
+				vn_aux = (Elf_Vernaux *)((caddr_t)vn_aux + vn_aux->vna_next);
+			}
+			vn = (const Elf_Verneed *)((caddr_t)vn + vn->vn_next);
+		}
+	}
+
+	obj->verinfo_len = max_idx;
+	if (max_idx == -1)
+		return;
+	obj->verinfo = calloc(max_idx + 1, sizeof(VerInfo));
+
+	vd = (const Elf_Verdef *)(obj->verdef);
+	for (i = 0; i < obj->verdefnum; i++) {
+		vd_aux = (const Elf_Verdaux *)((caddr_t)vd + vd->vd_aux);
+		if (obj->verinfo[vd->vd_ndx].vi_obj) {
+			_rtld_error("%s: More than one Verdef ndx %d", obj->path, vd->vd_ndx);
+			die();
+		}
+		vi = obj->verinfo + vd->vd_ndx;
+		vi->vi_ref = VR_DEF;
+		vi->vi_verdef = vd;
+		vi->vi_verdefaux = vd_aux;
+		vi->vi_obj = obj->objname;
+		vi->vi_name = (const char *)(obj->strtab + vd_aux->vda_name);
+		vi->vi_hash = vd->vd_hash;
+		vi->vi_ndx = vd->vd_ndx;
+
+		if (vd->vd_flags & VER_FLG_BASE) {
+			if (obj->file_verdef) {
+				_rtld_error("%s: More than one file Verdefs", obj->path);
+				die();
+			}
+			obj->file_verdef = vd;
+		}
+		vd = (const Elf_Verdef *)((caddr_t)vd + vd->vd_next);
+	}
+
+	vn = (const Elf_Verneed *)(obj->verneed);
+	for (i = 0; i < obj->verneednum; i++) {
+		vn_aux = (const Elf_Vernaux *)((caddr_t)vn + vn->vn_aux);
+		for (j = 0; j < vn->vn_cnt; j++) {
+			if (obj->verinfo[vn_aux->vna_other].vi_obj) {
+				_rtld_error("%s: More then one Verneed other %d", obj->path, vn_aux->vna_other);
+			}
+			vi = obj->verinfo + vn_aux->vna_other;
+			vi->vi_ref = VR_NEED;
+			vi->vi_verneed = vn;
+			vi->vi_verneedaux = vn_aux;
+			vi->vi_obj = (const char *)(obj->strtab + vn->vn_file);
+			vi->vi_name = (const char *)(obj->strtab + vn_aux->vna_name);
+			vi->vi_hash = vn_aux->vna_hash;
+			vi->vi_ndx = vn_aux->vna_other;
+			vn_aux = (Elf_Vernaux *)((caddr_t)vn_aux + vn_aux->vna_next);
+		}
+		vn = (const Elf_Verneed *)((caddr_t)vn + vn->vn_next);
+	}
+}
+
 /*
  * Process a shared object's DYNAMIC section, and save the important
  * information in its Obj_Entry structure.
@@ -556,6 +657,7 @@
     Needed_Entry **needed_tail = &obj->needed;
     const Elf_Dyn *dyn_rpath = NULL;
     int plttype = DT_REL;
+    Elf_Word soname = -1;
 
     obj->bind_now = false;
     for (dynp = obj->dynamic;  dynp->d_tag != DT_NULL;  dynp++) {
@@ -661,7 +763,7 @@
 	    break;
 
 	case DT_SONAME:
-	    /* Not used by the dynamic linker. */
+	    soname = dynp->d_un.d_val;
 	    break;
 
 	case DT_INIT:
@@ -695,6 +797,26 @@
 		    ;
 	    break;
 
+	case DT_VERSYM:
+		obj->versym = (Elf_Half *) (obj->relocbase + dynp->d_un.d_ptr);
+		break;
+
+	case DT_VERDEF:
+		obj->verdef = (Elf_Addr) (obj->relocbase + dynp->d_un.d_ptr);
+		break;
+
+	case DT_VERDEFNUM:
+		obj->verdefnum = dynp->d_un.d_val;
+		break;
+
+	case DT_VERNEED:
+		obj->verneed = (Elf_Addr) (obj->relocbase + dynp->d_un.d_ptr);
+		break;
+
+	case DT_VERNEEDNUM:
+		obj->verneednum = dynp->d_un.d_val;
+		break;
+
 	default:
 	    if (!early) {
 		dbg("Ignoring d_tag %ld = %#lx", (long)dynp->d_tag,
@@ -715,6 +837,27 @@
 
     if (dyn_rpath != NULL)
 	obj->rpath = obj->strtab + dyn_rpath->d_un.d_val;
+
+    if (soname != -1)
+	    obj->objname = obj->strtab + soname;
+    if (obj->objname == NULL) {
+	    if (obj->path == NULL) {
+		    obj->objname = "";
+	    } else {
+		    const char *endp = obj->path + strlen(obj->path) - 1;
+
+		    while (endp > obj->path && *endp != '/')
+			    endp--;
+		    if ((endp == obj->path) && (obj->path[0] != '/')) {
+			    obj->objname = obj->path;
+		    }
+		    else {
+			    obj->objname = endp + 1;
+		    }
+	    }
+    }
+    
+    digest_versions(obj);
 }
 
 /*
@@ -909,6 +1052,7 @@
     const Obj_Entry *defobj;
     const char *name;
     unsigned long hash;
+    const VerInfo *vi;
 
     /*
      * If we have already found this symbol, get the information from
@@ -924,6 +1068,8 @@
     ref = refobj->symtab + symnum;
     name = refobj->strtab + ref->st_name;
     defobj = NULL;
+    if (get_verinfo(refobj, symnum, &vi) == -1)
+	    return NULL;
 
     /*
      * We don't have to do a full scale lookup if the symbol is local.
@@ -939,7 +1085,7 @@
 		symnum);
 	}
 	hash = elf_hash(name);
-	def = symlook_default(name, hash, refobj, &defobj, in_plt);
+	def = symlook_default(name, hash, refobj, vi, &defobj, in_plt);
     } else {
 	def = ref;
 	defobj = refobj;
@@ -1150,6 +1296,51 @@
     return false;
 }
 
+static int
+check_req_versions(Obj_Entry *obj)
+{
+	int i, j;
+	bool *fb;
+	Obj_Entry *obj1;
+
+	if (obj->verinfo_len == -1)
+		return 0;
+
+	fb = alloca(obj->verinfo_len);
+	memset(fb, 0, sizeof(fb));
+	
+	for (obj1 = obj_list; obj1 != NULL; obj1 = obj1->next) {
+		for (j = 0; j <= obj1->verinfo_len; j++) {
+			VerInfo *vi1 = obj1->verinfo + j;
+			if (vi1->vi_name && (vi1->vi_ref == VR_DEF)) {
+				for (i = 0; i <= obj->verinfo_len; i++) {
+					VerInfo *vi = obj->verinfo + i;
+					if (vi->vi_name && (vi->vi_ref == VR_NEED) &&
+					    (vi1->vi_hash == vi->vi_hash) &&
+					    (strcmp(vi1->vi_obj, vi->vi_obj) == 0) &&
+					    (strcmp(vi->vi_name, vi1->vi_name) == 0))
+						fb[i] = true;
+				}
+			}
+		}
+	}
+	for (i = 0; i <= obj->verinfo_len; i++) {
+		VerInfo *vi = obj->verinfo + i;
+		if ((fb[i] == false) && vi->vi_name && (vi->vi_ref == VR_NEED)) {
+			dbg("XXX XXX");
+			for (obj1 = obj_list; obj1 != NULL; obj1 = obj1->next) {
+				dbg("XXX %s", obj1->path);
+				for (j = 0; j <= obj1->verinfo_len; j++)
+					dbg("  %s %s", obj1->verinfo[j].vi_obj, obj1->verinfo[j].vi_name);
+			}
+			_rtld_error("%s: required version %s %s is not found",
+				    obj->path, vi->vi_obj, vi->vi_name);
+			return -1;
+		}
+	}
+	return 0;
+}
+
 /*
  * Given a shared object, traverse its list of needed objects, and load
  * each of them.  Returns 0 on success.  Generates an error message and
@@ -1179,6 +1370,11 @@
 	}
     }
 
+    for (obj = first; obj != NULL; obj = obj->next) {
+	    if (check_req_versions(obj) == -1)
+		    return -1;		/* XXX - cleanup */
+    }
+
     return 0;
 }
 
@@ -1293,6 +1489,8 @@
 	  obj->mapbase + obj->mapsize - 1, obj->path);
 	if (obj->textrel)
 	    dbg("  WARNING: %s has impure text", obj->path);
+	if (debug)
+		dump_vers(obj);
     } else
 	free(path);
 
@@ -1788,21 +1986,21 @@
 	    return NULL;
 	}
 	if (handle == NULL) {	/* Just the caller's shared object. */
-	    def = symlook_obj(name, hash, obj, true);
+	    def = symlook_obj(name, hash, NULL, obj, true);
 	    defobj = obj;
 	} else if (handle == RTLD_NEXT || /* Objects after caller's */
 		   handle == RTLD_SELF) { /* ... caller included */
 	    if (handle == RTLD_NEXT)
 		obj = obj->next;
 	    for (; obj != NULL; obj = obj->next) {
-		if ((def = symlook_obj(name, hash, obj, true)) != NULL) {
+		if ((def = symlook_obj(name, hash, NULL, obj, true)) != NULL) {
 		    defobj = obj;
 		    break;
 		}
 	    }
 	} else {
 	    assert(handle == RTLD_DEFAULT);
-	    def = symlook_default(name, hash, obj, &defobj, true);
+	    def = symlook_default(name, hash, obj, NULL, &defobj, true);
 	}
     } else {
 	if ((obj = dlcheck(handle)) == NULL) {
@@ -1815,14 +2013,14 @@
 
 	    /* Search main program and all libraries loaded by it. */
 	    donelist_init(&donelist);
-	    def = symlook_list(name, hash, &list_main, &defobj, true,
+	    def = symlook_list(name, hash, NULL, &list_main, &defobj, true,
 	      &donelist);
 	} else {
 	    /*
 	     * XXX - This isn't correct.  The search should include the whole
 	     * DAG rooted at the given object.
 	     */
-	    def = symlook_obj(name, hash, obj, true);
+	    def = symlook_obj(name, hash, NULL, obj, true);
 	    defobj = obj;
 	}
     }
@@ -2163,7 +2361,7 @@
     for (obj = obj_main;  obj != NULL;  obj = obj->next) {
 	const Elf_Sym *def;
 
-	if ((def = symlook_obj(name, hash, obj, false)) != NULL) {
+	if ((def = symlook_obj(name, hash, NULL, obj, false)) != NULL) {
 	    const void **addr;
 
 	    addr = (const void **)(obj->relocbase + def->st_value);
@@ -2197,7 +2395,8 @@
  */
 static const Elf_Sym *
 symlook_default(const char *name, unsigned long hash,
-    const Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt)
+    const Obj_Entry *refobj, const VerInfo *vi,
+    const Obj_Entry **defobj_out, bool in_plt)
 {
     DoneList donelist;
     const Elf_Sym *def;
@@ -2211,7 +2410,7 @@
 
     /* Look first in the referencing object if linked symbolically. */
     if (refobj->symbolic && !donelist_check(&donelist, refobj)) {
-	symp = symlook_obj(name, hash, refobj, in_plt);
+	symp = symlook_obj(name, hash, vi, refobj, in_plt);
 	if (symp != NULL) {
 	    def = symp;
 	    defobj = refobj;
@@ -2220,7 +2419,7 @@
 
     /* Search all objects loaded at program start up. */
     if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
-	symp = symlook_list(name, hash, &list_main, &obj, in_plt, &donelist);
+	symp = symlook_list(name, hash, vi, &list_main, &obj, in_plt, &donelist);
 	if (symp != NULL &&
 	  (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
 	    def = symp;
@@ -2232,7 +2431,7 @@
     STAILQ_FOREACH(elm, &list_global, link) {
        if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
            break;
-       symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt,
+       symp = symlook_list(name, hash, vi, &elm->obj->dagmembers, &obj, in_plt,
          &donelist);
 	if (symp != NULL &&
 	  (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
@@ -2245,7 +2444,7 @@
     STAILQ_FOREACH(elm, &refobj->dldags, link) {
 	if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
 	    break;
-	symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt,
+	symp = symlook_list(name, hash, vi, &elm->obj->dagmembers, &obj, in_plt,
 	  &donelist);
 	if (symp != NULL &&
 	  (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
@@ -2261,7 +2460,7 @@
      * in the "exports" array can be resolved from the dynamic linker.
      */
     if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
-	symp = symlook_obj(name, hash, &obj_rtld, in_plt);
+	symp = symlook_obj(name, hash, vi, &obj_rtld, in_plt);
 	if (symp != NULL && is_exported(symp)) {
 	    def = symp;
 	    defobj = &obj_rtld;
@@ -2274,8 +2473,9 @@
 }
 
 static const Elf_Sym *
-symlook_list(const char *name, unsigned long hash, Objlist *objlist,
-  const Obj_Entry **defobj_out, bool in_plt, DoneList *dlp)
+symlook_list(const char *name, unsigned long hash,
+	     const VerInfo *vi, Objlist *objlist,
+	     const Obj_Entry **defobj_out, bool in_plt, DoneList *dlp)
 {
     const Elf_Sym *symp;
     const Elf_Sym *def;
@@ -2287,7 +2487,7 @@
     STAILQ_FOREACH(elm, objlist, link) {
 	if (donelist_check(dlp, elm->obj))
 	    continue;
-	if ((symp = symlook_obj(name, hash, elm->obj, in_plt)) != NULL) {
+	if ((symp = symlook_obj(name, hash, vi, elm->obj, in_plt)) != NULL) {
 	    if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) {
 		def = symp;
 		defobj = elm->obj;
@@ -2310,30 +2510,71 @@
  * eliminates many recomputations of the hash value.
  */
 const Elf_Sym *
-symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj,
-  bool in_plt)
+symlook_obj(const char *name, unsigned long hash,
+	    const VerInfo *vn, const Obj_Entry *obj, bool in_plt)
 {
+    const Elf_Sym *sympfirst = NULL;
+    const Elf_Sym *symp;
+
     if (obj->buckets != NULL) {
 	unsigned long symnum = obj->buckets[hash % obj->nbuckets];
 
 	while (symnum != STN_UNDEF) {
-	    const Elf_Sym *symp;
 	    const char *strp;
-
+	    
 	    if (symnum >= obj->nchains)
 		return NULL;	/* Bad object */
 	    symp = obj->symtab + symnum;
 	    strp = obj->strtab + symp->st_name;
 
-	    if (name[0] == strp[0] && strcmp(name, strp) == 0)
-		return symp->st_shndx != SHN_UNDEF ||
-		  (!in_plt && symp->st_value != 0 &&
-		  ELF_ST_TYPE(symp->st_info) == STT_FUNC) ? symp : NULL;
-
-	    symnum = obj->chains[symnum];
+	    if (name[0] == strp[0] && strcmp(name, strp) == 0) {
+		VerInfo *vd = NULL;
+		if (obj->verinfo) {
+			Elf_Half versym;
+			versym = obj->versym[symnum] & ~VER_NDX_HIDDEN;
+			if ((long)versym > obj->verinfo_len) {
+				_rtld_error("%s: symbol %s has wrong symver %d",
+					    obj->path, name, versym);
+				return NULL;
+			}
+			vd = obj->verinfo + versym;
+		}
+		if (vd && vn) {
+			if ((vn->vi_hash == vd->vi_hash) &&
+			    (strcmp(vn->vi_name, vd->vi_name) == 0))
+				goto ret;
+			dbg("discard symbol match due to ver: sym %s obj %s vn %s vd %s",
+			    name, obj->path, vn->vi_name, vd->vi_name);
+			goto cont;
+		}
+		if (vd && !vn) {
+			if (vd->vi_ndx == VER_NDX_GLOBAL)
+				goto ret;
+			else if (sympfirst)
+				return NULL;
+			sympfirst = symp;
+			goto cont;
+		}
+		if (!vd && vn) {
+			if (obj->objname && (strcmp(vn->vi_obj, obj->objname) == 0))
+				return NULL;
+			goto ret;
+		}
+		goto ret;
+	    }
+	cont:  symnum = obj->chains[symnum];
 	}
     }
+    if (sympfirst) {
+	    symp = sympfirst;
+	    goto ret;
+    }
+    
     return NULL;
+
+ ret: return symp->st_shndx != SHN_UNDEF ||
+	      (!in_plt && symp->st_value != 0 &&
+	       ELF_ST_TYPE(symp->st_info) == STT_FUNC) ? symp : NULL;
 }
 
 static void
@@ -2840,3 +3081,26 @@
     free_tls(tcb, tcbsize, tcbalign);
     wlock_release(rtld_bind_lock, lockstate);
 }
+
+int
+get_verinfo(const Obj_Entry *obj, unsigned long idx, const VerInfo **vi)
+{
+	Elf_Half versym = 0;
+
+	if (obj->verinfo) {
+		versym = obj->versym[idx] & ~VER_NDX_HIDDEN;
+		if ((long)versym > obj->verinfo_len) {
+			_rtld_error("%s: symbol %s has wrong verneed value %d",
+				    obj->path, obj->strtab + idx, versym);
+			return -1;
+		}
+	}
+
+	(*vi) = (versym ? obj->verinfo + versym : NULL);
+	if (*vi)
+		dbg("get_verneed obj %s idx %lu sym %s versym %d vername \"%s\"",
+		    obj->path, idx, obj->strtab + obj->symtab[idx].st_name, versym,
+		    (*vi)->vi_name);
+
+	return 0;
+}


--- orig/libexec/rtld-elf/rtld.h
+++ mod/libexec/rtld-elf/rtld.h
@@ -107,6 +107,30 @@
     void (*context_destroy)(void *context);
 } LockInfo;
 
+typedef enum Enum_VerRef
+{
+	VR_NEED,
+	VR_DEF
+} VerRef;
+
+typedef struct Struct_VerInfo {
+    VerRef vi_ref;
+    union {
+	    struct {
+		    const Elf_Verneed *vi_verneed;
+		    const Elf_Vernaux *vi_verneedaux;
+	    };
+	    struct {
+		    const Elf_Verdef *vi_verdef;
+		    const Elf_Verdaux *vi_verdefaux;
+	    };
+    };
+    const char *vi_obj;		/* Pointer equivalent of verneed->vn_file */
+    const char *vi_name;	/* Pointer equivalent of verneedaux->vna_name */
+    Elf_Word vi_hash;
+    Elf_Half vi_ndx;
+} VerInfo;
+
 /*
  * Shared object descriptor.
  *
@@ -128,6 +152,7 @@
     struct Struct_Obj_Entry *next;
     char *path;			/* Pathname of underlying file (%) */
     char *origin_path;		/* Directory path of origin file */
+    const char *objname;	/* The name of the object (pointer into path) */
     int refcount;
     int dl_refcount;		/* Number of times loaded by dlopen */
 
@@ -192,6 +217,16 @@
     dev_t dev;			/* Object's filesystem's device */
     ino_t ino;			/* Object's inode number */
     void *priv;			/* Platform-dependant */
+
+    Elf_Addr verdef;
+    unsigned long verdefnum;
+    Elf_Addr verneed;
+    unsigned long verneednum;
+    Elf_Half *versym;
+
+    const Elf_Verdef *file_verdef;	/* Pointer to the verdef for file */
+    long verinfo_len;
+    VerInfo *verinfo;
 } Obj_Entry;
 
 #define RTLD_MAGIC	0xd550b87a
@@ -219,6 +254,7 @@
 extern void dump_obj_relocations (Obj_Entry *);
 extern void dump_Elf_Rel (Obj_Entry *, const Elf_Rel *, u_long);
 extern void dump_Elf_Rela (Obj_Entry *, const Elf_Rela *, u_long);
+extern void dump_vers(Obj_Entry *);
 
 /*
  * Function declarations.
@@ -232,13 +268,15 @@
 Obj_Entry *obj_new(void);
 void _rtld_bind_start(void);
 const Elf_Sym *symlook_obj(const char *, unsigned long,
-  const Obj_Entry *, bool);
+  const VerInfo *vi, const Obj_Entry *, bool);
 void *tls_get_addr_common(Elf_Addr** dtvp, int index, size_t offset);
 void *allocate_tls(Obj_Entry *, void *, size_t, size_t);
 void free_tls(void *, size_t, size_t);
 void *allocate_module_tls(int index);
 bool allocate_tls_offset(Obj_Entry *obj);
 void free_tls_offset(Obj_Entry *obj);
+int get_verinfo(const Obj_Entry *obj, unsigned long idx,
+		const VerInfo **vi);
 
 /*
  * MD function declarations.


--- orig/sys/sys/elf32.h
+++ mod/sys/sys/elf32.h
@@ -153,4 +153,48 @@
 /* Macro for constructing st_info from field values. */
 #define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
 
+/* Versioning support */
+typedef struct
+{
+	Elf32_Half	vd_version;             /* Version revision */
+	Elf32_Half	vd_flags;               /* Version information */
+	Elf32_Half	vd_ndx;                 /* Version Index */
+	Elf32_Half	vd_cnt;                 /* Number of associated aux entries */
+	Elf32_Word	vd_hash;                /* Version name hash value */
+	Elf32_Word	vd_aux;                 /* Offset in bytes to verdaux array */
+	Elf32_Word	vd_next;                /* Offset in bytes to next verdef
+						   entry */
+} Elf32_Verdef;
+
+/* Auxialiary version information.  */
+typedef struct
+{
+	Elf32_Word	vda_name;               /* Version or dependency names */
+	Elf32_Word	vda_next;               /* Offset in bytes to next verdaux
+						   entry */
+} Elf32_Verdaux;
+
+/* Version dependency section.  */
+typedef struct
+{
+	Elf32_Half	vn_version;             /* Version of structure */
+	Elf32_Half	vn_cnt;                 /* Number of associated aux entries */
+	Elf32_Word	vn_file;                /* Offset of filename for this
+						 dependency */
+	Elf32_Word	vn_aux;                 /* Offset in bytes to vernaux array */
+	Elf32_Word	vn_next;                /* Offset in bytes to next verneed
+						   entry */
+} Elf32_Verneed;
+
+/* Auxiliary needed version information.  */
+typedef struct
+{
+	Elf32_Word	vna_hash;               /* Hash value of dependency name */
+	Elf32_Half	vna_flags;              /* Dependency specific information */
+	Elf32_Half	vna_other;              /* Unused */
+	Elf32_Word	vna_name;               /* Dependency name string offset */
+	Elf32_Word	vna_next;               /* Offset in bytes to next vernaux
+						   entry */
+} Elf32_Vernaux;
+
 #endif /* !_SYS_ELF32_H_ */


--- orig/sys/sys/elf64.h
+++ mod/sys/sys/elf64.h
@@ -166,4 +166,48 @@
 /* Macro for constructing st_info from field values. */
 #define ELF64_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
 
+/* Versioning support */
+typedef struct
+{
+	Elf64_Half	vd_version;             /* Version revision */
+	Elf64_Half	vd_flags;               /* Version information */
+	Elf64_Half	vd_ndx;                 /* Version Index */
+	Elf64_Half	vd_cnt;                 /* Number of associated aux entries */
+	Elf64_Word	vd_hash;                /* Version name hash value */
+	Elf64_Word	vd_aux;                 /* Offset in bytes to verdaux array */
+	Elf64_Word	vd_next;                /* Offset in bytes to next verdef
+						 entry */
+} Elf64_Verdef;
+
+/* Auxialiary version information.  */
+typedef struct
+{
+	Elf64_Word	vda_name;               /* Version or dependency names */
+	Elf64_Word	vda_next;               /* Offset in bytes to next verdaux
+                                           entry */
+} Elf64_Verdaux;
+
+/* Version dependency section.  */
+typedef struct
+{
+  Elf64_Half    vn_version;             /* Version of structure */
+  Elf64_Half    vn_cnt;                 /* Number of associated aux entries */
+  Elf64_Word    vn_file;                /* Offset of filename for this
+                                           dependency */
+  Elf64_Word    vn_aux;                 /* Offset in bytes to vernaux array */
+  Elf64_Word    vn_next;                /* Offset in bytes to next verneed
+                                           entry */
+} Elf64_Verneed;
+
+/* Auxiliary needed version information.  */
+typedef struct
+{ 
+	Elf64_Word	vna_hash;               /* Hash value of dependency name */
+	Elf64_Half	vna_flags;              /* Dependency specific information */
+	Elf64_Half	vna_other;              /* Unused */
+	Elf64_Word	vna_name;               /* Dependency name string offset */
+	Elf64_Word	vna_next;               /* Offset in bytes to next vernaux
+						 entry */
+} Elf64_Vernaux;
+
 #endif /* !_SYS_ELF64_H_ */


--- orig/sys/sys/elf_common.h
+++ mod/sys/sys/elf_common.h
@@ -164,6 +164,9 @@
 #define SHT_DYNSYM	11		/* dynamic symbol table section */ 
 #define SHT_NUM		12		/* number of section types */
 #define SHT_LOOS	0x60000000	/* First of OS specific semantics */
+#define SHT_GNU_verdef	0x6ffffffd    /* Version definition section.  */
+#define SHT_GNU_verneed	0x6ffffffe    /* Version needs section.  */
+#define SHT_GNU_versym	0x6fffffff
 #define SHT_HIOS	0x6fffffff	/* Last of OS specific semantics */
 #define SHT_LOPROC	0x70000000	/* reserved range for processor */
 #define SHT_HIPROC	0x7fffffff	/* specific section header types */
@@ -256,6 +259,20 @@
 #define	DT_LOPROC	0x70000000	/* First processor-specific type. */
 #define	DT_HIPROC	0x7fffffff	/* Last processor-specific type. */
 
+/* Versioning support */
+#define DT_VERSYM       0x6ffffff0
+#define DT_RELACOUNT    0x6ffffff9
+#define DT_RELCOUNT     0x6ffffffa
+#define DT_FLAGS_1      0x6ffffffb
+#define DT_VERDEF       0x6ffffffc      /* Address of version definition
+                                           table */
+#define DT_VERDEFNUM    0x6ffffffd      /* Number of version definitions */
+#define DT_VERNEED      0x6ffffffe      /* Address of table with needed
+                                           versions */
+#define DT_VERNEEDNUM   0x6fffffff      /* Number of needed versions */
+#define DT_VERSIONTAGIDX(tag)   (DT_VERNEEDNUM - (tag)) /* Reverse order! */
+#define DT_VERSIONTAGNUM 16
+
 /* Values for DT_FLAGS */
 #define	DF_ORIGIN	0x0001	/* Indicates that the object being loaded may
 				   make reference to the $ORIGIN substitution
@@ -296,4 +313,29 @@
 /* Special symbol table indexes. */
 #define STN_UNDEF	0	/* Undefined symbol index. */
 
+
+/* Legal values for vd_version (version revision).  */
+#define VER_DEF_NONE    0               /* No version */
+#define VER_DEF_CURRENT 1               /* Current version */
+#define VER_DEF_NUM     2               /* Given version number */
+
+/* Legal values for vd_flags (version information flags).  */
+#define VER_FLG_BASE    0x1             /* Version definition of file itself */
+#define VER_FLG_WEAK    0x2             /* Weak version identifier */
+
+/* Versym symbol index values.  */
+#define VER_NDX_LOCAL           0       /* Symbol is local.  */
+#define VER_NDX_GLOBAL          1       /* Symbol is global.  */
+#define VER_NDX_LORESERVE       0xff00  /* Beginning of reserved entries.  */
+#define VER_NDX_ELIMINATE       0xff01  /* Symbol is to be eliminated.  */
+#define VER_NDX_HIDDEN		0x8000	/* Symbol is hidden */
+
+/* Legal values for vn_version (version revision).  */
+#define VER_NEED_NONE    0              /* No version */
+#define VER_NEED_CURRENT 1              /* Current version */
+#define VER_NEED_NUM     2              /* Given version number */
+
+/* Legal values for vna_flags.  */
+#define VER_FLG_WEAK    0x2             /* Weak version identifier */
+
 #endif /* !_SYS_ELF_COMMON_H_ */


--- orig/sys/sys/elf_generic.h
+++ mod/sys/sys/elf_generic.h
@@ -69,6 +69,10 @@
 __ElfType(Rel);
 __ElfType(Rela);
 __ElfType(Sym);
+__ElfType(Verdef);
+__ElfType(Verdaux);
+__ElfType(Verneed);
+__ElfType(Vernaux);
 
 #define ELF_R_SYM	__ELFN(R_SYM)
 #define ELF_R_TYPE	__ELFN(R_TYPE)



