Module Name:    src
Committed By:   roy
Date:           Sat Feb 27 11:16:38 UTC 2010

Modified Files:
        src/libexec/ld.elf_so: load.c rtld.c rtld.h symbol.c

Log Message:
Implement negative cache checks for symbol lookups.
Uses the Donelist idea from FreeBSD.


To generate a diff of this commit:
cvs rdiff -u -r1.36 -r1.37 src/libexec/ld.elf_so/load.c
cvs rdiff -u -r1.128 -r1.129 src/libexec/ld.elf_so/rtld.c
cvs rdiff -u -r1.88 -r1.89 src/libexec/ld.elf_so/rtld.h
cvs rdiff -u -r1.50 -r1.51 src/libexec/ld.elf_so/symbol.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/libexec/ld.elf_so/load.c
diff -u src/libexec/ld.elf_so/load.c:1.36 src/libexec/ld.elf_so/load.c:1.37
--- src/libexec/ld.elf_so/load.c:1.36	Tue May 19 20:44:52 2009
+++ src/libexec/ld.elf_so/load.c	Sat Feb 27 11:16:38 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: load.c,v 1.36 2009/05/19 20:44:52 christos Exp $	 */
+/*	$NetBSD: load.c,v 1.37 2010/02/27 11:16:38 roy Exp $	 */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: load.c,v 1.36 2009/05/19 20:44:52 christos Exp $");
+__RCSID("$NetBSD: load.c,v 1.37 2010/02/27 11:16:38 roy Exp $");
 #endif /* not lint */
 
 #include <err.h>
@@ -155,6 +155,7 @@
 
 		*_rtld_objtail = obj;
 		_rtld_objtail = &obj->next;
+		_rtld_objcount++;
 #ifdef RTLD_LOADER
 		_rtld_linkmap_add(obj);	/* for GDB */
 #endif

Index: src/libexec/ld.elf_so/rtld.c
diff -u src/libexec/ld.elf_so/rtld.c:1.128 src/libexec/ld.elf_so/rtld.c:1.129
--- src/libexec/ld.elf_so/rtld.c:1.128	Sun Jan 10 06:37:32 2010
+++ src/libexec/ld.elf_so/rtld.c	Sat Feb 27 11:16:38 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: rtld.c,v 1.128 2010/01/10 06:37:32 skrll Exp $	 */
+/*	$NetBSD: rtld.c,v 1.129 2010/02/27 11:16:38 roy Exp $	 */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: rtld.c,v 1.128 2010/01/10 06:37:32 skrll Exp $");
+__RCSID("$NetBSD: rtld.c,v 1.129 2010/02/27 11:16:38 roy Exp $");
 #endif /* not lint */
 
 #include <err.h>
@@ -83,6 +83,7 @@
 bool            _rtld_trust;	/* False for setuid and setgid programs */
 Obj_Entry      *_rtld_objlist;	/* Head of linked list of shared objects */
 Obj_Entry     **_rtld_objtail;	/* Link field of last object in list */
+int		_rtld_objcount;	/* Number of shared objects */
 Obj_Entry      *_rtld_objmain;	/* The main program shared object */
 Obj_Entry       _rtld_objself;	/* The dynamic linker shared object */
 const char	_rtld_path[] = _PATH_RTLD;
@@ -271,6 +272,7 @@
 	/* Make the object list empty again. */
 	_rtld_objlist = NULL;
 	_rtld_objtail = &_rtld_objlist;
+	_rtld_objcount = 0;
 
 	_rtld_debug.r_brk = _rtld_debug_state;
 	_rtld_debug.r_state = RT_CONSISTENT;
@@ -705,6 +707,7 @@
 				_rtld_objlist_remove(&_rtld_list_global, obj);
 				_rtld_linkmap_delete(obj);
 				*linkp = obj->next;
+				_rtld_objcount--;
 				_rtld_obj_free(obj);
 			} else
 				linkp = &obj->next;
@@ -810,11 +813,16 @@
 	unsigned long hash;
 	const Elf_Sym *def;
 	const Obj_Entry *obj;
+	DoneList donelist;
 
 	hash = _rtld_elf_hash(name);
 	obj = _rtld_objmain;
+	_rtld_donelist_init(&donelist);
 
-	def = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, false);
+	def = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, false,
+	    &donelist);
+
+	_rtld_donelist_clear(&donelist);
 
 	if (def != NULL)
 		return obj->relocbase + def->st_value;
@@ -838,6 +846,7 @@
 	const Elf_Sym *def;
 	const Obj_Entry *defobj;
 	void *retaddr;
+	DoneList donelist; 
 	
 	hash = _rtld_elf_hash(name);
 	def = NULL;
@@ -892,20 +901,28 @@
 		if ((obj = _rtld_dlcheck(handle)) == NULL)
 			return NULL;
 		
+		_rtld_donelist_init(&donelist);
+
 		if (obj->mainprog) {
 			/* Search main program and all libraries loaded by it */
 			def = _rtld_symlook_list(name, hash, &_rtld_list_main,
-			    &defobj, false);
+			    &defobj, false, &donelist);
 		} else {
 			Needed_Entry fake;
+			DoneList depth;
 
 			/* Search the object and all the libraries loaded by it. */
 			fake.next = NULL;
 			fake.obj = __UNCONST(obj);
 			fake.name = 0;
+
+			_rtld_donelist_init(&depth);
 			def = _rtld_symlook_needed(name, hash, &fake, &defobj,
-			    false);
+			    false, &donelist, &depth);
+			_rtld_donelist_clear(&depth);
 		}
+
+		_rtld_donelist_clear(&donelist);
 		break;
 	}
 	

Index: src/libexec/ld.elf_so/rtld.h
diff -u src/libexec/ld.elf_so/rtld.h:1.88 src/libexec/ld.elf_so/rtld.h:1.89
--- src/libexec/ld.elf_so/rtld.h:1.88	Sun Jan 17 08:04:20 2010
+++ src/libexec/ld.elf_so/rtld.h	Sat Feb 27 11:16:38 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: rtld.h,v 1.88 2010/01/17 08:04:20 skrll Exp $	 */
+/*	$NetBSD: rtld.h,v 1.89 2010/02/27 11:16:38 roy Exp $	 */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -59,6 +59,16 @@
 #define NEW(type)	((type *) xmalloc(sizeof(type)))
 #define CNEW(type)	((type *) xcalloc(sizeof(type)))
 
+/*
+ * Fill in a DoneList with an allocation large enough to hold all of
+ * the currently-loaded objects.
+ */
+#define _rtld_donelist_init(dlp)						\
+    ((dlp)->objs = xmalloc(_rtld_objcount * sizeof((dlp)->objs[0])),	\
+    (dlp)->num_alloc = _rtld_objcount,					\
+    (dlp)->num_used = 0)
+#define _rtld_donelist_clear(dlp)		xfree((dlp)->objs)
+
 #endif /* _RTLD_SOURCE */
 
 /*
@@ -198,12 +208,20 @@
 	void		*ehdr;
 } Obj_Entry;
 
+typedef struct Struct_DoneList {
+	const Obj_Entry **objs;		/* Array of object pointers */
+	unsigned int num_alloc;		/* Allocated size of the array */
+	unsigned int num_used;		/* Number of array slots used */
+} DoneList;
+
+
 #if defined(_RTLD_SOURCE)
 
 extern struct r_debug _rtld_debug;
 extern Search_Path *_rtld_default_paths;
 extern Obj_Entry *_rtld_objlist;
 extern Obj_Entry **_rtld_objtail;
+extern int _rtld_objcount;
 extern Obj_Entry *_rtld_objmain;
 extern Obj_Entry _rtld_objself;
 extern Search_Path *_rtld_paths;
@@ -276,11 +294,12 @@
     const Obj_Entry **, bool);
 
 const Elf_Sym *_rtld_symlook_list(const char *, unsigned long,
-    const Objlist *, const Obj_Entry **, bool);
+    const Objlist *, const Obj_Entry **, bool, DoneList *);
 const Elf_Sym *_rtld_symlook_default(const char *, unsigned long,
     const Obj_Entry *, const Obj_Entry **, bool);
 const Elf_Sym *_rtld_symlook_needed(const char *, unsigned long,
-    const Needed_Entry *, const Obj_Entry **, bool);
+    const Needed_Entry *, const Obj_Entry **, bool,
+    DoneList *, DoneList *);
 #ifdef COMBRELOC
 void _rtld_combreloc_reset(const Obj_Entry *);
 #endif

Index: src/libexec/ld.elf_so/symbol.c
diff -u src/libexec/ld.elf_so/symbol.c:1.50 src/libexec/ld.elf_so/symbol.c:1.51
--- src/libexec/ld.elf_so/symbol.c:1.50	Wed Jan 13 20:17:21 2010
+++ src/libexec/ld.elf_so/symbol.c	Sat Feb 27 11:16:38 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: symbol.c,v 1.50 2010/01/13 20:17:21 christos Exp $	 */
+/*	$NetBSD: symbol.c,v 1.51 2010/02/27 11:16:38 roy Exp $	 */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: symbol.c,v 1.50 2010/01/13 20:17:21 christos Exp $");
+__RCSID("$NetBSD: symbol.c,v 1.51 2010/02/27 11:16:38 roy Exp $");
 #endif /* not lint */
 
 #include <err.h>
@@ -60,6 +60,27 @@
 
 typedef void (*fptr_t)(void);
 
+/*
+ * If the given object is already in the donelist, return true.  Otherwise
+ * add the object to the list and return false.
+ */
+static bool
+_rtld_donelist_check(DoneList *dlp, const Obj_Entry *obj)
+{
+	unsigned int i;
+
+	for (i = 0;  i < dlp->num_used;  i++)
+		if (dlp->objs[i] == obj)
+			return true;
+	/*
+	 * Our donelist allocation may not always be sufficient as we're not
+	 * thread safe. We'll handle it properly anyway.
+	 */
+	if (dlp->num_used < dlp->num_alloc)
+		dlp->objs[dlp->num_used++] = obj;
+	return false;
+}
+
 static bool
 _rtld_is_exported(const Elf_Sym *def)
 {
@@ -108,7 +129,7 @@
 
 const Elf_Sym *
 _rtld_symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
-    const Obj_Entry **defobj_out, bool in_plt)
+    const Obj_Entry **defobj_out, bool in_plt, DoneList *dlp)
 {
 	const Elf_Sym *symp;
 	const Elf_Sym *def;
@@ -118,6 +139,8 @@
 	def = NULL;
 	defobj = NULL;
 	SIMPLEQ_FOREACH(elm, objlist, link) {
+		if (_rtld_donelist_check(dlp, elm->obj))
+			continue;
 		rdbg(("search object %p (%s) for %s", elm->obj, elm->obj->path,
 		    name));
 		if ((symp = _rtld_symlook_obj(name, hash, elm->obj, in_plt))
@@ -143,7 +166,8 @@
  */
 const Elf_Sym *
 _rtld_symlook_needed(const char *name, unsigned long hash,
-    const Needed_Entry *needed, const Obj_Entry **defobj_out, bool inplt)
+    const Needed_Entry *needed, const Obj_Entry **defobj_out, bool inplt,
+    DoneList *breadth, DoneList *depth)
 {
 	const Elf_Sym *def, *def_w;
 	const Needed_Entry *n;
@@ -152,8 +176,11 @@
 	def = def_w = NULL;
 	defobj = NULL;
 	for (n = needed; n != NULL; n = n->next) {
-		if ((obj = n->obj) == NULL ||
-		     (def = _rtld_symlook_obj(name, hash, obj, inplt)) == NULL)
+		if ((obj = n->obj) == NULL)
+			continue;
+		if (_rtld_donelist_check(breadth, obj))
+			continue;
+		if ((def = _rtld_symlook_obj(name, hash, obj, inplt)) == NULL)
 			continue;
 		defobj = obj;
 		if (ELF_ST_BIND(def->st_info) != STB_WEAK) {
@@ -169,8 +196,10 @@
 	for (n = needed; n != NULL; n = n->next) {
 		if ((obj = n->obj) == NULL)
 			continue;
+		if (_rtld_donelist_check(depth, obj))
+			continue;
 		def_w = _rtld_symlook_needed(name, hash, obj->needed, &defobj1,
-		    inplt);
+		    inplt, breadth, depth);
 		if (def_w == NULL)
 			continue;
 		if (def == NULL || ELF_ST_BIND(def_w->st_info) != STB_WEAK) {
@@ -381,9 +410,12 @@
 	const Objlist_Entry *elm;
 	def = NULL;
 	defobj = NULL;
+	DoneList donelist;
+
+	_rtld_donelist_init(&donelist);
 
 	/* Look first in the referencing object if linked symbolically. */
-	if (refobj->symbolic) {
+	if (refobj->symbolic && !_rtld_donelist_check(&donelist, refobj)) {
 		rdbg(("search referencing object for %s", name));
 		symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
 		if (symp != NULL) {
@@ -396,7 +428,7 @@
 	if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
 		rdbg(("search _rtld_list_main for %s", name));
 		symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj,
-		    in_plt);
+		    in_plt, &donelist);
 		if (symp != NULL &&
 		    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
 			def = symp;
@@ -408,7 +440,7 @@
 	if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
 		rdbg(("search _rtld_list_global for %s", name));
 		symp = _rtld_symlook_list(name, hash, &_rtld_list_global,
-		    &obj, in_plt);
+		    &obj, in_plt, &donelist);
 		if (symp != NULL &&
 		    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
 			def = symp;
@@ -423,7 +455,7 @@
 		rdbg(("search DAG with root %p (%s) for %s", elm->obj,
 		    elm->obj->path, name));
 		symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers,
-		    &obj, in_plt);
+		    &obj, in_plt, &donelist);
 		if (symp != NULL &&
 		    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
 			def = symp;
@@ -447,6 +479,8 @@
 		}
 	}
 
+	_rtld_donelist_clear(&donelist);
+
 	if (def != NULL)
 		*defobj_out = defobj;
 	return def;

Reply via email to