Subject: dlsym(3) fix
To: None <tech-userlevel@netbsd.org>
From: Nick Hudson <skrll@netbsd.org>
List: tech-userlevel
Date: 10/13/2005 08:41:44
--Boundary-00=_J3hTDH4/sc0s3cQ
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Hi,

I've had this for a long time now. I'll go ahead and commit unless anyone has 
any objections.

Nick

--Boundary-00=_J3hTDH4/sc0s3cQ
Content-Type: text/x-diff;
  charset="us-ascii";
  name="symbol.c.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="symbol.c.diff"

Index: libexec/ld.elf_so/symbol.c
===================================================================
RCS file: /cvsroot/src/libexec/ld.elf_so/symbol.c,v
retrieving revision 1.39
diff -u -p -u -p -r1.39 symbol.c
--- libexec/ld.elf_so/symbol.c	10 May 2005 13:15:56 -0000	1.39
+++ libexec/ld.elf_so/symbol.c	13 Oct 2005 07:40:25 -0000
@@ -196,79 +196,33 @@ _rtld_find_symdef(unsigned long symnum, 
 {
 	const Elf_Sym  *ref;
 	const Elf_Sym  *def;
-	const Elf_Sym  *symp;
-	const Obj_Entry *obj;
 	const Obj_Entry *defobj;
-	const Objlist_Entry *elm;
 	const char     *name;
 	unsigned long   hash;
 
 	ref = refobj->symtab + symnum;
 	name = refobj->strtab + ref->st_name;
 
-	hash = _rtld_elf_hash(name);
-	def = NULL;
-	defobj = NULL;
-	
-	/* Look first in the referencing object if linked symbolically */
-	if (refobj->symbolic) {
-		symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
-		if (symp != NULL) {
-			def = symp;
-			defobj = refobj;
-		}
-	}
-	
-	/* Search all objects loaded at program start up. */
-	if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
-		rdbg(("search _rtld_list_main"));
-		symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, in_plt);
-		if (symp != NULL &&
-		    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
-			def = symp;
-			defobj = obj;
-		}
-	}
-	
-	/* Search all RTLD_GLOBAL objects. */
-	if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
-		rdbg(("search _rtld_list_global"));
-		symp = _rtld_symlook_list(name, hash, &_rtld_list_global, &obj, in_plt);
-		if (symp != NULL &&
-		    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
-			def = symp;
-			defobj = obj;
-		}
-	}
-	
-	/* Search all dlopened DAGs containing the referencing object. */
-	SIMPLEQ_FOREACH(elm, &refobj->dldags, link) {
-		if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
-			break;
-		rdbg(("search DAG with root %p (%s)", elm->obj, elm->obj->path));
-		symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt);
-		if (symp != NULL &&
-		    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
-			def = symp;
-			defobj = obj;
-		}
-	}
-	
 	/*
-	 * Search the dynamic linker itself, and possibly resolve the
-	 * symbol from there.  This is how the application links to
-	 * dynamic linker services such as dlopen.  Only the values listed
-	 * in the "_rtld_exports" array can be resolved from the dynamic linker.
+	 * We don't have to do a full scale lookup if the symbol is local.
+	 * We know it will bind to the instance in this load module; to
+	 * which we already have a pointer (ie ref).
 	 */
-	if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
-		rdbg(("search rtld itself"));
-		symp = _rtld_symlook_obj(name, hash, &_rtld_objself, in_plt);
-		if (symp != NULL && _rtld_is_exported(symp)) {
-			def = symp;
-			defobj = &_rtld_objself;
-		}
+	if (ELF_ST_BIND(ref->st_info) != STB_LOCAL) {
+		if (ELF_ST_TYPE(ref->st_info) == STT_SECTION) {
+			_rtld_error("%s: Bogus symbol table entry %lu",
+			    refobj->path, symnum);
+        	}
+
+		hash = _rtld_elf_hash(name);
+		defobj = NULL;
+		def = _rtld_symlook_default(name, hash, refobj, &defobj, in_plt);
+	} else {
+		rdbg(("STB_LOCAL symbol %s in %s", name, refobj->path));
+		def = ref;
+		defobj = refobj;
 	}
-	
+		
 	/*
 	 * If we found no definition and the reference is weak, treat the
 	 * symbol as having the value zero.
@@ -309,6 +263,7 @@ _rtld_symlook_default(const char *name, 
 
 	/* Look first in the referencing object if linked symbolically. */
 	if (refobj->symbolic) {
+		rdbg(("search referencing object"));
 		symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
 		if (symp != NULL) {
 			def = symp;
@@ -318,33 +273,36 @@ _rtld_symlook_default(const char *name, 
 
 	/* Search all objects loaded at program start up. */
 	if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
-		symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, in_plt);
+		rdbg(("search _rtld_list_main"));
+		symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj,
+		    in_plt);
 		if (symp != NULL &&
-		  (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
+		    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
 			def = symp;
 			defobj = obj;
 		}
 	}
 
-	/* Search all dlopened DAGs containing the referencing object. */
-	SIMPLEQ_FOREACH(elm, &refobj->dldags, link) {
-		if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
-			break;
-		symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj,
-		    in_plt);
+	/* Search all RTLD_GLOBAL objects. */
+	if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
+		rdbg(("search _rtld_list_global"));
+		symp = _rtld_symlook_list(name, hash, &_rtld_list_global,
+		    &obj, in_plt);
 		if (symp != NULL &&
 		    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
 			def = symp;
 			defobj = obj;
 		}
 	}
-
-	/* Search all DAGs whose roots are RTLD_GLOBAL objects. */
-	SIMPLEQ_FOREACH(elm, &_rtld_list_global, link) {
+	
+	/* Search all dlopened DAGs containing the referencing object. */
+	SIMPLEQ_FOREACH(elm, &refobj->dldags, link) {
 		if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
 			break;
-		symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj,
-		    in_plt);
+		rdbg(("search DAG with root %p (%s)", elm->obj,
+		    elm->obj->path));
+		symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers,
+		    &obj, in_plt);
 		if (symp != NULL &&
 		    (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
 			def = symp;
@@ -352,21 +310,21 @@ _rtld_symlook_default(const char *name, 
 		}
 	}
 
-#ifdef notyet
 	/*
 	 * Search the dynamic linker itself, and possibly resolve the
 	 * symbol from there.  This is how the application links to
 	 * dynamic linker services such as dlopen.  Only the values listed
-	 * in the "exports" array can be resolved from the dynamic linker.
+	 * in the "_rtld_exports" array can be resolved from the dynamic
+	 * linker.
 	 */
 	if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
+		rdbg(("Search the dynamic linker itself."));
 		symp = _rtld_symlook_obj(name, hash, &_rtld_objself, in_plt);
-		if (symp != NULL && is_exported(symp)) {
+		if (symp != NULL && _rtld_is_exported(symp)) {
 			def = symp;
 			defobj = &_rtld_objself;
 		}
 	}
-#endif
 
 	if (def != NULL)
 		*defobj_out = defobj;

--Boundary-00=_J3hTDH4/sc0s3cQ--