Subject: ld.elf_so DAG (was Re: PTL2 (pkgsrc/devel/ptl2) doesn't work with i386/ELF)
To: None <k-abe@kuroneko.media.osaka-cu.ac.jp>
From: msaitoh <msaitoh@spa.is.uec.ac.jp>
List: tech-kern
Date: 10/20/1999 16:46:11
 Please test following patch.

 This patch fixes PR#5890 and PR#8572. This patch is stoled from FreeBSD :)

diff -cr src/libexec/ld.elf_so/headers.c src/libexec/ld.newelf_so/headers.c
*** src/libexec/ld.elf_so/headers.c	Tue Mar  2 21:15:44 1999
--- src/libexec/ld.newelf_so/headers.c	Tue Oct 12 07:43:20 1999
***************
*** 258,268 ****
  	int phnum;
  	caddr_t entry;
  {
! 	Obj_Entry      *obj = CNEW(Obj_Entry);
  	const Elf_Phdr *phlimit = phdr + phnum;
  	const Elf_Phdr *ph;
  	int             nsegs = 0;
  
  	for (ph = phdr; ph < phlimit; ++ph) {
  		switch (ph->p_type) {
  
--- 258,269 ----
  	int phnum;
  	caddr_t entry;
  {
! 	Obj_Entry      *obj;
  	const Elf_Phdr *phlimit = phdr + phnum;
  	const Elf_Phdr *ph;
  	int             nsegs = 0;
  
+ 	obj = _rtld_obj_new();
  	for (ph = phdr; ph < phlimit; ++ph) {
  		switch (ph->p_type) {
  
***************
*** 270,275 ****
--- 271,280 ----
  			assert((const Elf_Phdr *) ph->p_vaddr == phdr);
  			obj->phdr = (const Elf_Phdr *) ph->p_vaddr;
  			obj->phsize = ph->p_memsz;
+ 			break;
+ 
+ 		case Elf_pt_interp:
+ 			obj->interp = (const char *) ph->p_vaddr;
  			break;
  
  		case Elf_pt_load:
diff -cr src/libexec/ld.elf_so/load.c src/libexec/ld.newelf_so/load.c
*** src/libexec/ld.elf_so/load.c	Tue Jun 29 09:00:16 1999
--- src/libexec/ld.newelf_so/load.c	Thu Oct 14 03:13:46 1999
***************
*** 66,84 ****
  	bool dodebug;
  {
  	Obj_Entry *obj;
  
  	for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next)
  		if (strcmp(obj->path, filepath) == 0)
  			break;
  
! 	if (obj == NULL) { /* First use of this object, so we must map it in */
! 		int fd;
! 
  		if ((fd = open(filepath, O_RDONLY)) == -1) {
  			_rtld_error("Cannot open \"%s\"", filepath);
  			return NULL;
  		}
! 		obj = _rtld_map_object(filepath, fd);
  		(void)close(fd);
  		if (obj == NULL) {
  			free(filepath);
--- 66,106 ----
  	bool dodebug;
  {
  	Obj_Entry *obj;
+ 	int fd = -1;
+ 	struct stat sb;
  
  	for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next)
  		if (strcmp(obj->path, filepath) == 0)
  			break;
  
! 	/*
! 	 * If we didn't find a match by pathname, open the file and check
! 	 * again by device and inode.  This avoids false mismatches caused
! 	 * by multiple links or ".." in pathnames.
! 	 *
! 	 * To avoid a race, we open the file and use fstat() rather than
! 	 * using stat().
! 	 */
! 	if (obj == NULL) {
  		if ((fd = open(filepath, O_RDONLY)) == -1) {
  			_rtld_error("Cannot open \"%s\"", filepath);
  			return NULL;
  		}
! 		if (fstat(fd, &sb) == -1) {
! 			_rtld_error("Cannot fstat \"%s\"", filepath);
! 			close(fd);
! 			return NULL;
! 		}
! 		for (obj = _rtld_objlist->next; obj != NULL; obj = obj->next) {
! 			if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) {
! 				close(fd);
! 				break;
! 			}
! 		}
! 	}
! 
! 	if (obj == NULL) { /* First use of this object, so we must map it in */
! 		obj = _rtld_map_object(filepath, fd, &sb);
  		(void)close(fd);
  		if (obj == NULL) {
  			free(filepath);
***************
*** 124,130 ****
--- 146,159 ----
  		for (needed = obj->needed; needed != NULL;
  		    needed = needed->next) {
  			const char *name = obj->strtab + needed->name;
+ #if 0
  			char *libpath = _rtld_find_library(name, obj);
+ #else
+ 			char *libpath;
+ dbg(("called from _rtld_load_needed_objects\n"));
+ 			libpath = _rtld_find_library(name, obj);
+ dbg(("returned from _rtld_load_needed_objects\n"));
+ #endif
  
  			if (libpath == NULL) {
  				status = -1;
diff -cr src/libexec/ld.elf_so/map_object.c src/libexec/ld.newelf_so/map_object.c
*** src/libexec/ld.elf_so/map_object.c	Sat Aug  7 20:09:46 1999
--- src/libexec/ld.newelf_so/map_object.c	Thu Oct 14 03:14:50 1999
***************
*** 33,40 ****
--- 33,42 ----
  
  #include <errno.h>
  #include <stddef.h>
+ #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
+ #include <sys/stat.h>
  #include <sys/types.h>
  #include <sys/mman.h>
  
***************
*** 56,64 ****
   * for the shared object.  Returns NULL on failure.
   */
  Obj_Entry *
! _rtld_map_object(path, fd)
  	const char *path;
  	int fd;
  {
  	Obj_Entry      *obj;
  	union {
--- 58,67 ----
   * for the shared object.  Returns NULL on failure.
   */
  Obj_Entry *
! _rtld_map_object(path, fd, sb)
  	const char *path;
  	int fd;
+ 	const struct stat *sb;
  {
  	Obj_Entry      *obj;
  	union {
***************
*** 72,77 ****
--- 75,81 ----
  	int             nsegs;
  	Elf_Phdr       *phdyn;
  	Elf_Phdr       *phphdr;
+ 	Elf_Phdr       *phinterp;
  	caddr_t         mapbase;
  	size_t          mapsize;
  	Elf_Off         base_offset;
***************
*** 137,146 ****
  	phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff);
  	phlimit = phdr + u.hdr.e_phnum;
  	nsegs = 0;
! 	phdyn = NULL;
! 	phphdr = NULL;
  	while (phdr < phlimit) {
  		switch (phdr->p_type) {
  
  		case Elf_pt_load:
  #ifdef __mips__
--- 141,152 ----
  	phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff);
  	phlimit = phdr + u.hdr.e_phnum;
  	nsegs = 0;
! 	phdyn = phphdr = phinterp = NULL;
  	while (phdr < phlimit) {
  		switch (phdr->p_type) {
+ 		case Elf_pt_interp:
+ 			phinterp = phdr;
+ 			break;
  
  		case Elf_pt_load:
  #ifdef __mips__
***************
*** 250,256 ****
  	/* Non-file portion of BSS mapped above. */
  #endif
  
! 	obj = CNEW(Obj_Entry);
  	obj->mapbase = mapbase;
  	obj->mapsize = mapsize;
  	obj->textsize = round_up(segs[0]->p_vaddr + segs[0]->p_memsz) -
--- 256,266 ----
  	/* Non-file portion of BSS mapped above. */
  #endif
  
! 	obj = _rtld_obj_new();
! 	if (sb != NULL) {
! 		obj->dev = sb->st_dev;
! 		obj->ino = sb->st_ino;
! 	}
  	obj->mapbase = mapbase;
  	obj->mapsize = mapsize;
  	obj->textsize = round_up(segs[0]->p_vaddr + segs[0]->p_memsz) -
***************
*** 265,270 ****
--- 275,319 ----
  		    (obj->relocbase + phphdr->p_vaddr);
  		obj->phsize = phphdr->p_memsz;
  	}
+ 	if (phinterp != NULL)
+ 		obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr);
+ 
+ 	return obj;
+ }
+ 
+ void
+ _rtld_obj_free(obj)
+ 	Obj_Entry *obj;
+ {
+ 	Objlist_Entry *elm;
+ 
+ 	free(obj->path);
+ 	while (obj->needed != NULL) {
+ 		Needed_Entry *needed = obj->needed;
+ 		obj->needed = needed->next;
+ 		free(needed);
+ 	}
+ 	while (SIMPLEQ_FIRST(&obj->dldags) != NULL) {
+ 		elm = SIMPLEQ_FIRST(&obj->dldags);
+ 		SIMPLEQ_REMOVE_HEAD(&obj->dldags, elm, link);
+ 		free(elm);
+ 	}
+ 	while (SIMPLEQ_FIRST(&obj->dagmembers) != NULL) {
+ 		elm = SIMPLEQ_FIRST(&obj->dagmembers);
+ 		SIMPLEQ_REMOVE_HEAD(&obj->dagmembers, elm, link);
+ 		free(elm);
+ 	}
+ 	free(obj);
+ }
+ 
+ Obj_Entry *
+ _rtld_obj_new(void)
+ {
+ 	Obj_Entry *obj;
+ 
+ 	obj = CNEW(Obj_Entry);
+ 	SIMPLEQ_INIT(&obj->dldags);
+ 	SIMPLEQ_INIT(&obj->dagmembers);
  	return obj;
  }
  
diff -cr src/libexec/ld.elf_so/reloc.c src/libexec/ld.newelf_so/reloc.c
*** src/libexec/ld.elf_so/reloc.c	Sun Aug 22 20:19:13 1999
--- src/libexec/ld.newelf_so/reloc.c	Tue Oct 12 11:53:40 1999
***************
*** 150,156 ****
  #ifndef __sparc__
  int
  _rtld_relocate_nonplt_object(obj, rela, dodebug)
! 	const Obj_Entry *obj;
  	const Elf_RelA *rela;
  	bool dodebug;
  {
--- 150,156 ----
  #ifndef __sparc__
  int
  _rtld_relocate_nonplt_object(obj, rela, dodebug)
! 	Obj_Entry *obj;
  	const Elf_RelA *rela;
  	bool dodebug;
  {
***************
*** 378,384 ****
  
  int
  _rtld_relocate_plt_object(obj, rela, addrp, bind_now, dodebug)
! 	const Obj_Entry *obj;
  	const Elf_RelA *rela;
  	caddr_t *addrp;
  	bool bind_now;
--- 378,384 ----
  
  int
  _rtld_relocate_plt_object(obj, rela, addrp, bind_now, dodebug)
! 	Obj_Entry *obj;
  	const Elf_RelA *rela;
  	caddr_t *addrp;
  	bool bind_now;
***************
*** 435,441 ****
  
  caddr_t
  _rtld_bind(obj, reloff)
! 	const Obj_Entry *obj;
  	Elf_Word reloff;
  {
  	const Elf_RelA *rela;
--- 435,441 ----
  
  caddr_t
  _rtld_bind(obj, reloff)
! 	Obj_Entry *obj;
  	Elf_Word reloff;
  {
  	const Elf_RelA *rela;
diff -cr src/libexec/ld.elf_so/rtld.c src/libexec/ld.newelf_so/rtld.c
*** src/libexec/ld.elf_so/rtld.c	Fri Aug 20 20:10:44 1999
--- src/libexec/ld.newelf_so/rtld.c	Thu Oct 14 03:35:29 1999
***************
*** 59,64 ****
--- 59,66 ----
  #include "sysident.h"
  #endif
  
+ #define END_SYM		"_end"
+ 
  /*
   * Debugging support.
   */
***************
*** 86,95 ****
--- 88,104 ----
  Obj_Entry      *_rtld_objmain;	/* The main program shared object */
  Obj_Entry       _rtld_objself;	/* The dynamic linker shared object */
  char            _rtld_path[] = _PATH_RTLD;
+ unsigned long   curmark;		/* Current mark value */
+ Elf_Sym         _rtld_sym_zero;	/* For resolving undefined weak refs. */
  #ifdef	VARPSZ
  int		_rtld_pagesz;	/* Page size, as provided by kernel */
  #endif
  
+ Objlist _rtld_list_global =	/* Objects dlopened with RTLD_GLOBAL */
+   SIMPLEQ_HEAD_INITIALIZER(_rtld_list_global);
+ Objlist _rtld_list_main =	/* Objects loaded at program startup */
+   SIMPLEQ_HEAD_INITIALIZER(_rtld_list_main);
+ 
  Search_Path    *_rtld_default_paths;
  Search_Path    *_rtld_paths;
  /*
***************
*** 108,114 ****
  static void _rtld_call_fini_functions __P((Obj_Entry *));
  static void _rtld_call_init_functions __P((Obj_Entry *));
  static Obj_Entry *_rtld_dlcheck __P((void *));
! static void _rtld_unref_object_dag __P((Obj_Entry *));
  
  static void
  _rtld_call_fini_functions(first)
--- 117,130 ----
  static void _rtld_call_fini_functions __P((Obj_Entry *));
  static void _rtld_call_init_functions __P((Obj_Entry *));
  static Obj_Entry *_rtld_dlcheck __P((void *));
! static void _rtld_init_dag __P((Obj_Entry *));
! static void _rtld_init_dag1 __P((Obj_Entry *, Obj_Entry *));
! static void _rtld_objlist_add __P((Objlist *, Obj_Entry *));
! static Objlist_Entry *_rtld_objlist_find __P((Objlist *, const Obj_Entry *));
! static void _rtld_objlist_remove __P((Objlist *, Obj_Entry *));
! static void _rtld_unload_object __P((Obj_Entry *, bool));
! static void _rtld_unref_dag __P((Obj_Entry *));
! static Obj_Entry *_rtld_obj_from_addr __P((const void *));
  
  static void
  _rtld_call_fini_functions(first)
***************
*** 257,262 ****
--- 273,279 ----
  	bool            bind_now = 0;
  	const char     *ld_bind_now;
  	const char    **argv;
+ 	Obj_Entry	*obj;
  #if defined(RTLD_DEBUG) && !defined(RTLD_RELOCATE_SELF)
  	int             i = 0;
  #endif
***************
*** 364,370 ****
  	if (pAUX_execfd != NULL) {	/* Load the main program. */
  		int             fd = pAUX_execfd->au_v;
  		dbg(("loading main program"));
! 		_rtld_objmain = _rtld_map_object(argv[0], fd);
  		close(fd);
  		if (_rtld_objmain == NULL)
  			_rtld_die();
--- 381,387 ----
  	if (pAUX_execfd != NULL) {	/* Load the main program. */
  		int             fd = pAUX_execfd->au_v;
  		dbg(("loading main program"));
! 		_rtld_objmain = _rtld_map_object(argv[0], fd, NULL);
  		close(fd);
  		if (_rtld_objmain == NULL)
  			_rtld_die();
***************
*** 387,392 ****
--- 404,422 ----
  
  	_rtld_objmain->path = xstrdup("main program");
  	_rtld_objmain->mainprog = true;
+ 	
+ 	/*
+ 	 * Get the actual dynamic linker pathname from the executable if
+ 	 * possible.  (It should always be possible.)  That ensures that
+ 	 * gdb will find the right dynamic linker even if a non-standard
+ 	 * one is being used.
+ 	 */
+ 	if (_rtld_objmain->interp != NULL &&
+ 	    strcmp(_rtld_objmain->interp, _rtld_objself.path) != 0) {
+ 		free(_rtld_objself.path);
+ 		_rtld_objself.path = xstrdup(_rtld_objmain->interp);
+ 	}
+ 	
  	_rtld_digest_dynamic(_rtld_objmain);
  
  	_rtld_linkmap_add(_rtld_objmain);
***************
*** 397,402 ****
--- 427,436 ----
  	_rtld_objtail = &_rtld_objmain->next;
  	++_rtld_objmain->refcount;
  
+ 	/* Initialize a fake symbol for resolving undefined weak references. */
+ 	_rtld_sym_zero.st_info = ELF_SYM_INFO(Elf_estb_global, Elf_estt_notype);
+ 	_rtld_sym_zero.st_shndx = Elf_eshn_absolute;
+ 
  	/*
  	 * Pre-load user-specified objects after the main program but before
  	 * any shared object dependencies.
***************
*** 409,414 ****
--- 443,451 ----
  	if (_rtld_load_needed_objects(_rtld_objmain) == -1)
  		_rtld_die();
  
+ 	for (obj = _rtld_objlist;  obj != NULL;  obj = obj->next)
+ 		_rtld_objlist_add(&_rtld_list_main, obj);
+ 
  	dbg(("relocating objects"));
  	if (_rtld_relocate_objects(_rtld_objmain, bind_now, true) == -1)
  		_rtld_die();
***************
*** 463,469 ****
  }
  
  static void
! _rtld_unref_object_dag(root)
  	Obj_Entry *root;
  {
  	assert(root->refcount != 0);
--- 500,576 ----
  }
  
  static void
! _rtld_init_dag(root)
! 	Obj_Entry *root;
! {
! 	curmark++;
! 	_rtld_init_dag1(root, root);
! }
! 
! static void
! _rtld_init_dag1(root, obj)
! 	Obj_Entry *root;
! 	Obj_Entry *obj;
! {
! 	const Needed_Entry *needed;
! 
! 	if (obj->mark == curmark)
! 		return;
! 	obj->mark = curmark;
! 	_rtld_objlist_add(&obj->dldags, root);
! 	_rtld_objlist_add(&root->dagmembers, obj);
! 	for (needed = obj->needed; needed != NULL; needed = needed->next)
! 		if (needed->obj != NULL)
! 			_rtld_init_dag1(root, needed->obj);
! }
! 
! /*
!  * Note, this is called only for objects loaded by dlopen().
!  */
! static void
! _rtld_unload_object(root, do_fini_funcs)
! 	Obj_Entry *root;
! 	bool do_fini_funcs;
! {
! 	_rtld_unref_dag(root);
! 	if (root->refcount == 0) { /* We are finished with some objects. */
! 		Obj_Entry *obj;
! 		Obj_Entry **linkp;
! 		Objlist_Entry *elm;
! 
! 		/* Finalize objects that are about to be unmapped. */
! 		if (do_fini_funcs)
! 			for (obj = _rtld_objlist->next;  obj != NULL;  obj = obj->next)
! 				if (obj->refcount == 0 && obj->fini != NULL)
! 					(*obj->fini)();
! 
! 		/* Remove the DAG from all objects' DAG lists. */
! 		for (elm = SIMPLEQ_FIRST(&root->dagmembers); elm; elm = SIMPLEQ_NEXT(elm, link))
! 			_rtld_objlist_remove(&elm->obj->dldags, root);
! 
! 		/* Remove the DAG from the RTLD_GLOBAL list. */
! 		_rtld_objlist_remove(&_rtld_list_global, root);
! 
! 		/* Unmap all objects that are no longer referenced. */
! 		linkp = &_rtld_objlist->next;
! 		while ((obj = *linkp) != NULL) {
! 			if (obj->refcount == 0) {
! #ifdef RTLD_DEBUG
! 				dbg(("unloading \"%s\"", obj->path));
! #endif
! 				munmap(obj->mapbase, obj->mapsize);
! 				_rtld_linkmap_delete(obj);
! 				*linkp = obj->next;
! 				_rtld_obj_free(obj);
! 			} else
! 				linkp = &obj->next;
! 		}
! 		_rtld_objtail = linkp;
! 	}
! }
! 
! static void
! _rtld_unref_dag(root)
  	Obj_Entry *root;
  {
  	assert(root->refcount != 0);
***************
*** 472,479 ****
  		const Needed_Entry *needed;
  
  		for (needed = root->needed; needed != NULL;
! 		    needed = needed->next)
! 			_rtld_unref_object_dag(needed->obj);
  	}
  }
  
--- 579,586 ----
  		const Needed_Entry *needed;
  
  		for (needed = root->needed; needed != NULL;
! 		     needed = needed->next)
! 			_rtld_unref_dag(needed->obj);
  	}
  }
  
***************
*** 490,496 ****
  	_rtld_debug_state();
  
  	--root->dl_refcount;
! 	_rtld_unref_object_dag(root);
  	if (root->refcount == 0) {	/* We are finished with some objects. */
  		Obj_Entry      *obj;
  		Obj_Entry     **linkp;
--- 597,603 ----
  	_rtld_debug_state();
  
  	--root->dl_refcount;
! 	_rtld_unref_dag(root);
  	if (root->refcount == 0) {	/* We are finished with some objects. */
  		Obj_Entry      *obj;
  		Obj_Entry     **linkp;
***************
*** 542,574 ****
  	Obj_Entry **old_obj_tail = _rtld_objtail;
  	Obj_Entry *obj = NULL;
  
  	_rtld_debug.r_state = RT_ADD;
  	_rtld_debug_state();
  
  	if (name == NULL) {
  		obj = _rtld_objmain;
  	} else {
  		char *path = _rtld_find_library(name, _rtld_objmain);
  		if (path != NULL)
  			obj = _rtld_load_object(path, true);
  	}
  
  	if (obj != NULL) {
  		++obj->dl_refcount;
  		if (*old_obj_tail != NULL) {	/* We loaded something new. */
  			assert(*old_obj_tail == obj);
  
! 			/* FIXME - Clean up properly after an error. */
! 			if (_rtld_load_needed_objects(obj) == -1) {
! 				--obj->dl_refcount;
! 				obj = NULL;
! 			} else if (_rtld_relocate_objects(obj,
! 			    (mode & 3) == RTLD_NOW, true) == -1) {
! 				--obj->dl_refcount;
  				obj = NULL;
! 			} else {
  				_rtld_call_init_functions(obj);
- 			}
  		}
  	}
  	_rtld_debug.r_state = RT_CONSISTENT;
--- 649,688 ----
  	Obj_Entry **old_obj_tail = _rtld_objtail;
  	Obj_Entry *obj = NULL;
  
+ dbg(("called from dlopen (%s,%x)\n", name,mode));
  	_rtld_debug.r_state = RT_ADD;
  	_rtld_debug_state();
  
  	if (name == NULL) {
  		obj = _rtld_objmain;
+ 		obj->refcount++;
  	} else {
+ #if 0
  		char *path = _rtld_find_library(name, _rtld_objmain);
+ #else
+ 		char *path;
+ dbg(("called from dlopen (%s)\n", name));
+ 		path = _rtld_find_library(name, _rtld_objmain);
+ dbg(("returned from dlopen (%s)\n", path));
+ #endif
  		if (path != NULL)
  			obj = _rtld_load_object(path, true);
  	}
  
  	if (obj != NULL) {
  		++obj->dl_refcount;
+ 		if (mode & RTLD_GLOBAL && _rtld_objlist_find(&_rtld_list_global, obj) == NULL)
+ 			_rtld_objlist_add(&_rtld_list_global, obj);
  		if (*old_obj_tail != NULL) {	/* We loaded something new. */
  			assert(*old_obj_tail == obj);
  
! 			if (_rtld_load_needed_objects(obj) == -1 || (_rtld_init_dag(obj),
! 				 _rtld_relocate_objects(obj, ((mode & 3) == RTLD_NOW), true)) == -1) {
! 				_rtld_unload_object(obj, false);
! 				obj->dl_refcount--;
  				obj = NULL;
! 			} else
  				_rtld_call_init_functions(obj);
  		}
  	}
  	_rtld_debug.r_state = RT_CONSISTENT;
***************
*** 582,604 ****
  	void *handle;
  	const char *name;
  {
! 	const Obj_Entry *obj = _rtld_dlcheck(handle);
! 	const Elf_Sym  *def;
  	const Obj_Entry *defobj;
  
! 	if (obj == NULL)
! 		return NULL;
  
  	/*
!          * FIXME - This isn't correct.  The search should include the whole
!          * DAG rooted at the given object.
!          */
! 	def = _rtld_find_symdef(_rtld_objlist, 0, name, obj, &defobj, false);
! 	if (def != NULL)
! 		return defobj->relocbase + def->st_value;
  
! 	_rtld_error("Undefined symbol \"%s\"", name);
! 	return NULL;
  }
  
  /*
--- 696,810 ----
  	void *handle;
  	const char *name;
  {
! 	const Obj_Entry *obj;
! 	unsigned long hash;
! 	const Elf_Sym *def;
  	const Obj_Entry *defobj;
+ 	
+ 	hash = _rtld_elf_hash(name);
+ 	def = NULL;
+ 	defobj = NULL;
+ 	
+ #if 1
+ 	if (handle == NULL) {
+ #else
+ 		if (handle == NULL || handle == RTLD_NEXT) {
+ #endif
+ 			void *retaddr;
  
! 			retaddr = __builtin_return_address(0); /* __GNUC__ only */
! 			if ((obj = _rtld_obj_from_addr(retaddr)) == NULL) {
! 				_rtld_error("Cannot determine caller's shared object");
! 				return NULL;
! 			}
! 			if (handle == NULL) { /* Just the caller's shared object. */
! 				def = _rtld_symlook_obj(name, hash, obj, true);
! 				defobj = obj;
! 			} else { /* All the shared objects after the caller's */
! 				while ((obj = obj->next) != NULL) {
! 					if ((def = _rtld_symlook_obj(name, hash, obj, true)) != NULL) {
! 						defobj = obj;
! 						break;
! 					}
! 				}
! 			}
! 		} else {
! 			if ((obj = _rtld_dlcheck(handle)) == NULL)
! 				return NULL;
! 			
! 			if (obj->mainprog) {
! 				/* Search main program and all libraries loaded by it. */
! 				curmark++;
! 				def = _rtld_symlook_list(name, hash, &_rtld_list_main, &defobj, true);
! 			} else {
! 				/*
! 				 * XXX - This isn't correct.  The search should include the whole
! 				 * DAG rooted at the given object.
! 				 */
! 				def = _rtld_symlook_obj(name, hash, obj, true);
! 				defobj = obj;
! 			}
! 		}
! 		
! 		if (def != NULL)
! 			return defobj->relocbase + def->st_value;
! 		
! 		_rtld_error("Undefined symbol \"%s\"", name);
! 	return NULL;
! }
  
+ int
+ _rtld_dladdr(addr, info)
+ 	const void *addr;
+ 	Dl_info *info;
+ {
+ 	const Obj_Entry *obj;
+ 	const Elf_Sym *def;
+ 	void *symbol_addr;
+ 	unsigned long symoffset;
+ 	
+ 	obj = _rtld_obj_from_addr(addr);
+ 	if (obj == NULL) {
+ 		_rtld_error("No shared object contains address");
+ 		return 0;
+ 	}
+ 	info->dli_fname = obj->path;
+ 	info->dli_fbase = obj->mapbase;
+ 	info->dli_saddr = (void *)0;
+ 	info->dli_sname = NULL;
+ 	
  	/*
! 	 * Walk the symbol list looking for the symbol whose address is
! 	 * closest to the address sent in.
! 	 */
! 	for (symoffset = 0; symoffset < obj->nchains; symoffset++) {
! 		def = obj->symtab + symoffset;
  
! 		/*
! 		 * For skip the symbol if st_shndx is either Elf_eshn_undefined or
! 		 * Elf_eshn_common.
! 		 */
! 		if (def->st_shndx == Elf_eshn_undefined || def->st_shndx == Elf_eshn_common)
! 			continue;
! 
! 		/*
! 		 * If the symbol is greater than the specified address, or if it
! 		 * is further away from addr than the current nearest symbol,
! 		 * then reject it.
! 		 */
! 		symbol_addr = obj->relocbase + def->st_value;
! 		if (symbol_addr > addr || symbol_addr < info->dli_saddr)
! 			continue;
! 
! 		/* Update our idea of the nearest symbol. */
! 		info->dli_sname = obj->strtab + def->st_name;
! 		info->dli_saddr = symbol_addr;
! 
! 		/* Exact match? */
! 		if (info->dli_saddr == addr)
! 			break;
! 	}
! 	return 1;
  }
  
  /*
***************
*** 673,676 ****
--- 879,949 ----
  	}
  	if ((l->l_prev->l_next = l->l_next) != NULL)
  		l->l_next->l_prev = l->l_prev;
+ }
+ 
+ static Obj_Entry *
+ _rtld_obj_from_addr(const void *addr)
+ {
+ 	unsigned long endhash;
+ 	Obj_Entry *obj;
+ 	
+ 	endhash = _rtld_elf_hash(END_SYM);
+ 	for (obj = _rtld_objlist;  obj != NULL;  obj = obj->next) {
+ 		const Elf_Sym *endsym;
+ 
+ 		if (addr < (void *) obj->mapbase)
+ 			continue;
+ 		if ((endsym = _rtld_symlook_obj(END_SYM, endhash, obj, true)) == NULL)
+ 			continue; /* No "end" symbol?! */
+ 		if (addr < (void *) (obj->relocbase + endsym->st_value))
+ 			return obj;
+ 	}
+ 	return NULL;
+ }
+ 
+ static void
+ _rtld_objlist_add(list, obj)
+ 	Objlist *list;
+ 	Obj_Entry *obj;
+ {
+ 	Objlist_Entry *elm;
+ 
+ 	elm = NEW(Objlist_Entry);
+ 	elm->obj = obj;
+ 	SIMPLEQ_INSERT_TAIL(list, elm, link);
+ }
+ 
+ static Objlist_Entry *
+ _rtld_objlist_find(Objlist *list, const Obj_Entry *obj)
+ {
+ 	Objlist_Entry *elm;
+ 
+ 	for (elm = SIMPLEQ_FIRST(list); elm; elm = SIMPLEQ_NEXT(elm, link)) {
+ 		if (elm->obj == obj)
+ 			return elm;
+ 	}
+ 	return NULL;
+ }
+ 
+ static void
+ _rtld_objlist_remove(list, obj)
+ 	Objlist *list;
+ 	Obj_Entry *obj;
+ {
+ 	Objlist_Entry *elm;
+ 	
+ 	if ((elm = _rtld_objlist_find(list, obj)) != NULL) {
+ 		if ((list)->sqh_first == (elm)) {
+ 			SIMPLEQ_REMOVE_HEAD(list, elm, link);
+ 		}
+ 		else {
+ 			struct Struct_Objlist_Entry *curelm = (list)->sqh_first;
+ 			while (curelm->link.sqe_next != (elm))
+ 				curelm = curelm->link.sqe_next;
+ 			if((curelm->link.sqe_next =
+ 			    curelm->link.sqe_next->link.sqe_next) == NULL)
+ 				(list)->sqh_last = &(curelm)->link.sqe_next;
+ 		}
+ 		free(elm);
+ 	}
  }
diff -cr src/libexec/ld.elf_so/rtld.h src/libexec/ld.newelf_so/rtld.h
*** src/libexec/ld.elf_so/rtld.h	Fri Aug 20 20:10:44 1999
--- src/libexec/ld.newelf_so/rtld.h	Tue Oct 19 07:36:47 1999
***************
*** 34,42 ****
--- 34,44 ----
  #ifndef RTLD_H
  #define RTLD_H
  
+ #include <dlfcn.h>
  #include <stddef.h>
  #include <sys/param.h>
  #include <sys/types.h>
+ #include <sys/queue.h>
  #include <sys/exec_elf.h>
  #include "rtldenv.h"
  #include "link.h"
***************
*** 89,94 ****
--- 91,103 ----
  
  struct Struct_Obj_Entry;
  
+ typedef struct Struct_Objlist_Entry {
+ 	SIMPLEQ_ENTRY(Struct_Objlist_Entry) link;
+ 	struct Struct_Obj_Entry *obj;
+ } Objlist_Entry;
+ 
+ typedef SIMPLEQ_HEAD(Struct_Objlist, Struct_Objlist_Entry) Objlist;
+ 
  typedef struct Struct_Needed_Entry {
  	struct Struct_Needed_Entry *next;
  	struct Struct_Obj_Entry *obj;
***************
*** 178,183 ****
--- 187,200 ----
  	int             printed:1;	/* True if ldd has printed it */
  
  	struct link_map linkmap;	/* for GDB */
+ 
+ 	/* These items are computed by map_object() or by digest_phdr(). */
+ 	const char     *interp;	/* Pathname of the interpreter, if any */
+ 	Objlist         dldags;	/* Object belongs to these dlopened DAGs (%) */
+ 	Objlist         dagmembers;	/* DAG has these members (%) */
+ 	dev_t           dev;		/* Object's filesystem's device */
+ 	ino_t           ino;		/* Object's inode number */
+ 	unsigned long   mark;	/* Set to "curmark" to avoid repeat visits */
  } Obj_Entry;
  
  #if defined(_RTLD_SOURCE)
***************
*** 186,195 ****
--- 203,217 ----
  extern Search_Path *_rtld_default_paths;
  extern Obj_Entry *_rtld_objlist;
  extern Obj_Entry **_rtld_objtail;
+ extern Obj_Entry *_rtld_objmain;
  extern Obj_Entry _rtld_objself;
  extern Search_Path *_rtld_paths;
  extern bool _rtld_trust;
  extern const char *_rtld_error_message;
+ extern unsigned long curmark;
+ extern Objlist _rtld_list_global;
+ extern Objlist _rtld_list_main;
+ extern Elf_Sym _rtld_sym_zero;
  
  /* rtld_start.S */
  void _rtld_bind_start __P((void));
***************
*** 201,206 ****
--- 223,229 ----
  void *_rtld_dlopen __P((const char *, int));
  void *_rtld_dlsym __P((void *, const char *));
  int _rtld_dlclose __P((void *));
+ int _rtld_dladdr __P((const void *, Dl_info *));
  void _rtld_debug_state __P((void));
  void _rtld_linkmap_add __P((Obj_Entry *));
  void _rtld_linkmap_delete __P((Obj_Entry *));
***************
*** 220,230 ****
  
  /* reloc.c */
  int _rtld_do_copy_relocations __P((const Obj_Entry *, bool));
! caddr_t _rtld_bind __P((const Obj_Entry *, Elf_Word));
  int _rtld_relocate_objects __P((Obj_Entry *, bool, bool));
! int _rtld_relocate_nonplt_object __P((const Obj_Entry *,
      const Elf_RelA *, bool));
! int _rtld_relocate_plt_object __P((const Obj_Entry *, const Elf_RelA *,
      caddr_t *, bool, bool));
  
  /* search.c */
--- 243,253 ----
  
  /* reloc.c */
  int _rtld_do_copy_relocations __P((const Obj_Entry *, bool));
! 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));
! int _rtld_relocate_plt_object __P((Obj_Entry *, const Elf_RelA *,
      caddr_t *, bool, bool));
  
  /* search.c */
***************
*** 235,244 ****
  const Elf_Sym *_rtld_symlook_obj __P((const char *, unsigned long,
      const Obj_Entry *, bool));
  const Elf_Sym *_rtld_find_symdef __P((const Obj_Entry *, Elf_Word,
!     const char *, const Obj_Entry *, const Obj_Entry **, bool));
  
  /* map_object.c */
! Obj_Entry *_rtld_map_object __P((const char *, int));
  
  #if defined(__mips__)
  /* mips_reloc.c */
--- 258,271 ----
  const Elf_Sym *_rtld_symlook_obj __P((const char *, unsigned long,
      const Obj_Entry *, bool));
  const Elf_Sym *_rtld_find_symdef __P((const Obj_Entry *, Elf_Word,
!     const char *, Obj_Entry *, const Obj_Entry **, bool));
! const Elf_Sym *_rtld_symlook_list(const char *, unsigned long,
!   Objlist *, const Obj_Entry **, bool in_plt);
  
  /* map_object.c */
! Obj_Entry *_rtld_map_object __P((const char *, int, const struct stat *));
! void _rtld_obj_free(Obj_Entry *);
! Obj_Entry *_rtld_obj_new(void);
  
  #if defined(__mips__)
  /* mips_reloc.c */
diff -cr src/libexec/ld.elf_so/symbol.c src/libexec/ld.newelf_so/symbol.c
*** src/libexec/ld.elf_so/symbol.c	Tue Mar  2 21:15:47 1999
--- src/libexec/ld.newelf_so/symbol.c	Thu Oct 14 03:34:16 1999
***************
*** 73,78 ****
--- 73,110 ----
  	return h;
  }
  
+ const Elf_Sym *
+ _rtld_symlook_list(const char *name, unsigned long hash, Objlist *objlist,
+   const Obj_Entry **defobj_out, bool in_plt)
+ {
+ 	const Elf_Sym *symp;
+ 	const Elf_Sym *def;
+ 	const Obj_Entry *defobj;
+ 	const Objlist_Entry *elm;
+ 	
+ 	def = NULL;
+ 	defobj = NULL;
+ 	for (elm = SIMPLEQ_FIRST(objlist); elm; elm = SIMPLEQ_NEXT(elm, link)) {
+ 		if (elm->obj->mark == curmark)
+ 			continue;
+ 		elm->obj->mark = curmark;
+ 		if ((symp = _rtld_symlook_obj(name, hash, elm->obj, in_plt))
+ 		    != NULL) {
+ 			if ((def == NULL) ||
+ 			    (ELF_SYM_BIND(symp->st_info) != Elf_estb_weak)) {
+ 				def = symp;
+ 				defobj = elm->obj;
+ 				if (ELF_SYM_BIND(def->st_info)
+ 				    != Elf_estb_weak)
+ 					break;
+ 			}
+ 		}
+ 	}
+ 	if (def != NULL)
+ 		*defobj_out = defobj;
+ 	return def;
+ }
+ 
  /*
   * Search the symbol table of a single shared object for a symbol of
   * the given name.  Returns a pointer to the symbol, or NULL if no
***************
*** 128,140 ****
  	const Obj_Entry *obj_list;
  	Elf_Word r_info;
  	const char *name;
! 	const Obj_Entry *refobj;
  	const Obj_Entry **defobj_out;
  	bool in_plt;
  {
  	Elf_Word symnum = ELF_R_SYM(r_info);
  	const Elf_Sym  *ref;
  	const Obj_Entry *obj;
  	unsigned long   hash;
  
  	if (name == NULL) {
--- 160,176 ----
  	const Obj_Entry *obj_list;
  	Elf_Word r_info;
  	const char *name;
! 	Obj_Entry *refobj;
  	const Obj_Entry **defobj_out;
  	bool in_plt;
  {
  	Elf_Word symnum = ELF_R_SYM(r_info);
  	const Elf_Sym  *ref;
+ 	const Elf_Sym  *def;
+ 	const Elf_Sym  *symp;
  	const Obj_Entry *obj;
+ 	const Obj_Entry *defobj;
+ 	const Objlist_Entry *elm;
  	unsigned long   hash;
  
  	if (name == NULL) {
***************
*** 142,178 ****
  		name = refobj->strtab + ref->st_name;
  	}
  	hash = _rtld_elf_hash(name);
! 
  	if (refobj->symbolic) {	/* Look first in the referencing object */
! 		const Elf_Sym *def;
! 
! 		def = _rtld_symlook_obj(name, hash, refobj, in_plt);
! 		if (def != NULL) {
! 			*defobj_out = refobj;
! 			return def;
  		}
  	}
! 	/*
!          * Look in all loaded objects.  Skip the referencing object, if
!          * we have already searched it.
!          */
! 	for (obj = obj_list; obj != NULL; obj = obj->next) {
! 		if (obj != refobj || !refobj->symbolic) {
! 			const Elf_Sym *def;
! 
! 			def = _rtld_symlook_obj(name, hash, obj, in_plt);
! 			if (def != NULL) {
! 				*defobj_out = obj;
! 				return def;
! 			}
  		}
  	}
! 
! 	if (ELF_R_TYPE(r_info) != R_TYPE(NONE)) {
  		_rtld_error(
  	    "%s: Undefined %ssymbol \"%s\" (reloc type = %d, symnum = %d)",
! 		    refobj->path, in_plt ? "PLT " : "", name,
! 		    ELF_R_TYPE(r_info), symnum);
  	}
! 	return NULL;
  }
--- 178,245 ----
  		name = refobj->strtab + ref->st_name;
  	}
  	hash = _rtld_elf_hash(name);
! 	def = NULL;
! 	defobj = NULL;
! 	curmark++;
! 	
  	if (refobj->symbolic) {	/* Look first in the referencing object */
! 		symp = _rtld_symlook_obj(name, hash, refobj, in_plt);
! 		refobj->mark = curmark;
! 		if (symp != NULL) {
! 			def = symp;
! 			defobj = refobj;
  		}
  	}
! 	
! 	/* Search all objects loaded at program start up. */
! 	if (def == NULL || ELF_SYM_BIND(def->st_info) == Elf_estb_weak) {
! 		symp = _rtld_symlook_list(name, hash, &_rtld_list_main, &obj, in_plt);
! 		if (symp != NULL &&
! 		    ((def == NULL) || (ELF_SYM_BIND(symp->st_info) != Elf_estb_weak))) {
! 			def = symp;
! 			defobj = obj;
  		}
  	}
! 	
! 	/* Search all dlopened DAGs containing the referencing object. */
! 	for (elm = SIMPLEQ_FIRST(&refobj->dldags); elm; elm = SIMPLEQ_NEXT(elm, link)) {
! 		if ((def != NULL) && (ELF_SYM_BIND(def->st_info) != Elf_estb_weak))
! 			break;
! 		symp = _rtld_symlook_list(name, hash, &elm->obj->dagmembers, &obj,
! 					  in_plt);
! 		if (symp != NULL &&
! 		    ((def == NULL) || (ELF_SYM_BIND(symp->st_info) != Elf_estb_weak))) {
! 			def = symp;
! 			defobj = obj;
! 		}
! 	}
! 	
! 	/* Search all RTLD_GLOBAL objects. */
! 	if (def == NULL || ELF_SYM_BIND(def->st_info) == Elf_estb_weak) {
! 		symp = _rtld_symlook_list(name, hash, &_rtld_list_global, &obj, in_plt);
! 		if (symp != NULL &&
! 		    (def == NULL || ELF_SYM_BIND(symp->st_info) != Elf_estb_weak)) {
! 			def = symp;
! 			defobj = obj;
! 		}
! 	}
! 	
! 	/*
! 	 * If we found no definition and the reference is weak, treat the
! 	 * symbol as having the value zero.
! 	 */
! 	if (def == NULL && ELF_SYM_BIND(ref->st_info) == Elf_estb_weak) {
! 		def = &_rtld_sym_zero;
! 		defobj = _rtld_objmain;
! 	}
! 	
! 	if (def != NULL)
! 		*defobj_out = defobj;
! 	else if (ELF_R_TYPE(r_info) != R_TYPE(NONE)) {
  		_rtld_error(
  	    "%s: Undefined %ssymbol \"%s\" (reloc type = %d, symnum = %d)",
! 			    refobj->path, in_plt ? "PLT " : "", name,
! 			    ELF_R_TYPE(r_info), symnum);
  	}
! 	return def;
  }
*** src/sys/sys/exec_elf.h.orig	Mon Sep 13 20:31:25 1999
--- src/sys/sys/exec_elf.h	Tue Oct 19 07:33:34 1999
***************
*** 302,307 ****
--- 302,310 ----
  
  #define	ELF_SYM_TYPE(info)	((enum elf_e_symbol_type) ((info) & 0x0F))
  
+ /* Macro for constructing st_info from field values. */
+ #define ELF_SYM_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
+ 
  enum elf_e_symbol_section_index {
  	Elf_eshn_undefined	=0,
  	Elf_eshn_mips_acommon	=0xFF00,


----------------------------------------------------------
		SAITOH Masanobu (msaitoh@spa.is.uec.ac.jp,
		                 msaitoh@netbsd.org)
		University of Electro-Communications