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;