Subject: SymCache optimization (was Re: New ld.elf_so from FreeBSD)
To: Jaromir Dolecek <jdolecek@netbsd.org>
From: Bang Jun-Young <junyoung@mogua.com>
List: tech-toolchain
Date: 09/06/2002 03:51:15
--/04w6evG8XlLl3ft
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Thu, Sep 05, 2002 at 07:45:37PM +0900, Bang Jun-Young wrote:
> The problem is that FreeBSD rtld code is now quite different from our
> ld.elf_so, although they were very similar long time ago. To reduce
> pain of modifying it so that it has support for other platforms not
> in the FreeBSD rtld, I'd like to propose to import only necessary 
> features into our ld.elf_so, not rtld itself. I think I can do at
> least "SymCache" C++ optimization part myself until the end of this
> week. 

I'm attaching a patch that makes use of SymCache for our ld.elf_so.
With a new ld.elf_so, I got tons of "found!" messages on the screen
while loading mozilla (LD_DEBUG=1). 

Note that it's still only for i386. However, it wouldn't be difficult
to make it work on other platforms.

Any comments?

Jun-Young

-- 
Bang Jun-Young <junyoung@mogua.com>

--/04w6evG8XlLl3ft
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="symcache.patch"

Index: reloc.c
===================================================================
RCS file: /usr/local/cvs/prebind/src/libexec/ld.elf_so/reloc.c,v
retrieving revision 1.4
diff -u -r1.4 reloc.c
--- reloc.c	2002/09/05 17:28:45	1.4
+++ reloc.c	2002/09/05 18:29:33
@@ -150,9 +150,10 @@
 #if !defined(__sparc__) && !defined(__x86_64__)
 
 int
-_rtld_relocate_nonplt_object(obj, rela, dodebug)
+_rtld_relocate_nonplt_object(obj, rela, cache, dodebug)
 	Obj_Entry *obj;
 	const Elf_Rela *rela;
+	SymCache *cache;
 	bool dodebug;
 {
 	Elf_Addr        *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
@@ -172,7 +173,8 @@
 #if defined(__i386__)
 	case R_TYPE(GOT32):
 
-		def = _rtld_find_symdef(rela->r_info, obj, &defobj, false);
+		def = _rtld_find_symdef(rela->r_info, obj, &defobj, false,
+		    cache);
 		if (def == NULL)
 			return -1;
 
@@ -191,7 +193,8 @@
 		 * generate it.
 		 */
 
-		def = _rtld_find_symdef(rela->r_info, obj, &defobj, false);
+		def = _rtld_find_symdef(rela->r_info, obj, &defobj, false,
+		    cache);
 		if (def == NULL)
 			return -1;
 
@@ -203,7 +206,8 @@
 		break;
 
 	case R_TYPE(32):
-		def = _rtld_find_symdef(rela->r_info, obj, &defobj, false);
+		def = _rtld_find_symdef(rela->r_info, obj, &defobj, false,
+		    cache);
 		if (def == NULL)
 			return -1;
 
@@ -340,7 +344,8 @@
 #if defined(__alpha__) || defined(__i386__) || defined(__m68k__) || \
     defined(__sh__)
 	case R_TYPE(GLOB_DAT):
-		def = _rtld_find_symdef(rela->r_info, obj, &defobj, false);
+		def = _rtld_find_symdef(rela->r_info, obj, &defobj, false,
+		    cache);
 		if (def == NULL)
 			return -1;
 
@@ -621,7 +626,7 @@
 #endif /* __hppa__ */
 
 	default:
-		def = _rtld_find_symdef(rela->r_info, obj, &defobj, true);
+		def = _rtld_find_symdef(rela->r_info, obj, &defobj, true, NULL);
 		rdbg(dodebug, ("sym = %lu, type = %lu, offset = %p, "
 		    "addend = %p, contents = %p, symbol = %s",
 		    (u_long)ELF_R_SYM(rela->r_info),
@@ -665,7 +670,7 @@
 		assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JUMP_SLOT));
 #endif
 
-		def = _rtld_find_symdef(rela->r_info, obj, &defobj, true);
+		def = _rtld_find_symdef(rela->r_info, obj, &defobj, true, NULL);
 		if (def == NULL)
 			return -1;
 
@@ -769,9 +774,12 @@
 	bool dodebug;
 {
 	Obj_Entry *obj;
+	SymCache *cache;
 	int ok = 1;
 
 	for (obj = first; obj != NULL; obj = obj->next) {
+		int bytes = obj->nchains * sizeof(SymCache);
+
 		if (obj->nbuckets == 0 || obj->nchains == 0 ||
 		    obj->buckets == NULL || obj->symtab == NULL ||
 		    obj->strtab == NULL) {
@@ -799,6 +807,14 @@
 				return -1;
 			}
 		}
+
+		cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 
+		    0);
+		if (cache == MAP_FAILED)
+			cache = NULL;
+		if (cache != NULL)
+			memset(cache, 0, bytes);
+		
 		if (obj->rel != NULL) {
 			/* Process the non-PLT relocations. */
 			const Elf_Rel  *rel;
@@ -817,7 +833,7 @@
 					    rel->r_offset);
 
 				if (_rtld_relocate_nonplt_object(obj, &ourrela,
-				    dodebug) < 0)
+				    cache, dodebug) < 0)
 					ok = 0;
 			}
 		}
@@ -826,10 +842,14 @@
 			const Elf_Rela *rela;
 			for (rela = obj->rela; rela < obj->relalim; ++rela) {
 				if (_rtld_relocate_nonplt_object(obj, rela,
-				    dodebug) < 0)
+				    cache, dodebug) < 0)
 					ok = 0;
 			}
 		}
+		
+		if (cache)
+			munmap(cache, bytes);
+		
 		if (obj->textrel) {	/* Re-protected the text segment. */
 			if (mprotect(obj->mapbase, obj->textsize,
 				     PROT_READ | PROT_EXEC) == -1) {
Index: rtld.h
===================================================================
RCS file: /usr/local/cvs/prebind/src/libexec/ld.elf_so/rtld.h,v
retrieving revision 1.3
diff -u -r1.3 rtld.h
--- rtld.h	2002/09/05 17:28:45	1.3
+++ rtld.h	2002/09/05 17:50:25
@@ -217,6 +217,15 @@
 					   repeat visits */
 } Obj_Entry;
 
+/*
+ * Symbol cache entry used during relocation to avoid multiple lookups
+ * of the same symbol.
+ */
+typedef struct Struct_SymCache {
+	const Elf_Sym *sym;	/* Symbol table entry */
+	const Obj_Entry *obj;	/* Shared object which defines it */
+} SymCache;
+
 #if defined(_RTLD_SOURCE)
 
 extern struct r_debug _rtld_debug;
@@ -272,7 +281,7 @@
 caddr_t _rtld_bind __P((Obj_Entry *, Elf_Word));
 int _rtld_relocate_objects __P((Obj_Entry *, bool, bool));
 int _rtld_relocate_nonplt_object __P((Obj_Entry *,
-    const Elf_Rela *, bool));
+    const Elf_Rela *, SymCache *, bool));
 int _rtld_relocate_plt_object __P((Obj_Entry *, const Elf_Rela *,
     caddr_t *, bool, bool));
 
@@ -284,7 +293,7 @@
 const Elf_Sym *_rtld_symlook_obj __P((const char *, unsigned long,
     const Obj_Entry *, bool));
 const Elf_Sym *_rtld_find_symdef __P((Elf_Addr, Obj_Entry *,
-    const Obj_Entry **, bool));
+    const Obj_Entry **, bool, SymCache *));
 const Elf_Sym *_rtld_symlook_list(const char *, unsigned long,
   Objlist *, const Obj_Entry **, bool in_plt);
 
Index: symbol.c
===================================================================
RCS file: /usr/local/cvs/prebind/src/libexec/ld.elf_so/symbol.c,v
retrieving revision 1.4
diff -u -r1.4 symbol.c
--- symbol.c	2002/09/05 17:28:45	1.4
+++ symbol.c	2002/09/05 18:31:34
@@ -154,11 +154,12 @@
  * defining object via the reference parameter DEFOBJ_OUT.
  */
 const Elf_Sym *
-_rtld_find_symdef(r_info, refobj, defobj_out, in_plt)
+_rtld_find_symdef(r_info, refobj, defobj_out, in_plt, cache)
 	Elf_Addr r_info;
 	Obj_Entry *refobj;
 	const Obj_Entry **defobj_out;
 	bool in_plt;
+	SymCache *cache;
 {
 	Elf_Addr symnum = ELF_R_SYM(r_info);
 	const Elf_Sym  *ref;
@@ -170,6 +171,18 @@
 	const char     *name;
 	unsigned long   hash;
 
+	/*
+	 * If we have already found this symbol, get the information from
+	 * the cache.
+	 */
+	if (symnum >= refobj->nchains)
+		return NULL;	/* Bad object */
+	if (cache != NULL && cache[symnum].sym != NULL) {
+		*defobj_out = cache[symnum].obj;
+		dbg(("found!"));
+		return cache[symnum].sym;
+	}
+
 	ref = refobj->symtab + symnum;
 	name = refobj->strtab + ref->st_name;
 
@@ -230,9 +243,14 @@
 		defobj = _rtld_objmain;
 	}
 	
-	if (def != NULL)
+	if (def != NULL) {
 		*defobj_out = defobj;
-	else if (ELF_R_TYPE(r_info) != R_TYPE(NONE)) {
+		/* Record the information in the cache to avoid subsequent lookups. */
+		if (cache != NULL) {
+			cache[symnum].sym = def;
+			cache[symnum].obj = defobj;
+		}
+	} else if (ELF_R_TYPE(r_info) != R_TYPE(NONE)) {
 		_rtld_error(
 	    "%s: Undefined %ssymbol \"%s\" (reloc type = %ld, symnum = %ld)",
 			    refobj->path, in_plt ? "PLT " : "", name,
Index: arch/sparc/mdreloc.c
===================================================================
RCS file: /usr/local/cvs/prebind/src/libexec/ld.elf_so/arch/sparc/mdreloc.c,v
retrieving revision 1.3
diff -u -r1.3 mdreloc.c
--- arch/sparc/mdreloc.c	2002/09/05 17:28:50	1.3
+++ arch/sparc/mdreloc.c	2002/09/05 17:50:09
@@ -161,9 +161,10 @@
 #define RELOC_VALUE_BITMASK(t)	(reloc_target_bitmask[t])
 
 int
-_rtld_relocate_nonplt_object(obj, rela, dodebug)
+_rtld_relocate_nonplt_object(obj, rela, cache, dodebug)
 	Obj_Entry *obj;
 	const Elf_Rela *rela;
+	SymCache *cache;
 	bool dodebug;
 {
 	Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);

--/04w6evG8XlLl3ft--