summary refs log tree commit diff
path: root/elf/dlclose.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1996-06-04 23:06:02 +0000
committerRoland McGrath <roland@gnu.org>1996-06-04 23:06:02 +0000
commitf68b86cc7bdcee246296d49f3a3318c1b97693f0 (patch)
tree34a9e7bde9fd4f15d76192869b800ff7ff461874 /elf/dlclose.c
parent14d898aef6373abaf64a7b17f32e8ce3f655cdf3 (diff)
downloadglibc-f68b86cc7bdcee246296d49f3a3318c1b97693f0.tar.gz
glibc-f68b86cc7bdcee246296d49f3a3318c1b97693f0.tar.xz
glibc-f68b86cc7bdcee246296d49f3a3318c1b97693f0.zip
Tue Jun 4 18:57:57 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
	* elf/dladdr.c: Remove #include <setjmp.h>, we don't use it.

	* shlib-versions: Set libdl=2.

	* elf/dl-deps.c (_dl_map_object_deps): Use a linked list of alloca'd
 	elements and then scan it to fill the single malloc'd array, instead
 	of using realloc to grow the array in the first pass.  _dl_map_object
	may do some mallocs that break our stream of reallocs, and the minimal
	realloc can't handle that.

	* elf/dl-init.c (_dl_init_next): Take argument, link_map whose
 	searchlist describes the piece of the DT_NEEDED graph to be
 	initialized.
	* elf/link.h: Update prototype.
	* sysdeps/i386/dl-machine.h (RTLD_START): Pass _dl_loaded as argument
	to _dl_init_next.
	* sysdeps/m68k/dl-machine.h: Likewise.
	* elf/dl-deps.c (_dl_open): Pass new object as arg to _dl_init_next.

	* elf/link.h (struct link_map): Add `l_reserved' member, soaking up
	extra bits in last byte.
	* elf/dl-deps.c (_dl_map_object_deps): Use that for mark bit to avoid
	putting dup elts in search list.

	* elf/dlclose.c: Use MAP->l_searchlist to find deps to close.

	* elf/dlsym.c: Don't tweak linked list.  Scope array given to
	_dl_lookup_symbol does the right thing.
Tue Jun  4 02:25:44 1996  Roland McGrath  <roland@delasyd.gnu.ai.mit.edu>
Diffstat (limited to 'elf/dlclose.c')
-rw-r--r--elf/dlclose.c100
1 files changed, 52 insertions, 48 deletions
diff --git a/elf/dlclose.c b/elf/dlclose.c
index 06b2d1bdcd..fbb3ca6fe2 100644
--- a/elf/dlclose.c
+++ b/elf/dlclose.c
@@ -1,5 +1,5 @@
 /* dlclose -- Close a handle opened by `dlopen'.
-Copyright (C) 1995 Free Software Foundation, Inc.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
 This file is part of the GNU C Library.
 
 The GNU C Library is free software; you can redistribute it and/or
@@ -32,64 +32,68 @@ dlclose (void *handle)
   void doit (void)
     {
       struct link_map *map = handle;
+      struct link_map **list;
+      unsigned int i;
 
       if (map->l_opencount == 0)
 	LOSE ("shared object not open");
 
       /* Decrement the reference count.  */
-      --map->l_opencount;
-
-      if (map->l_opencount == 0 && map->l_type == lt_loaded)
+      if (--map->l_opencount > 0 || map->l_type != lt_loaded)
+	/* There are still references to this object.  Do nothing more.  */
+	return;
+
+      list = map->l_searchlist;
+
+      /* The search list contains a counted reference to each object it
+	 points to, the 0th elt being MAP itself.  Decrement the reference
+	 counts on all the objects MAP depends on.  */
+      for (i = 1; i < map->l_nsearchlist; ++i)
+	--list[i]->l_opencount;
+
+      /* Clear the search list so it doesn't get freed while we are still
+         using it.  We have cached it in LIST and will free it when
+         finished.  */
+      map->l_searchlist = NULL;
+
+      /* Check each element of the search list to see if all references to
+         it are gone.  */
+      for (i = 0; i < map->l_nsearchlist; ++i)
 	{
-	  /* That was the last reference, and this was a dlopen-loaded
-	     object.  We can unmap it.  */
-	  const Elf32_Phdr *ph;
-
-	  if (map->l_info[DT_FINI])
-	    /* Call its termination function.  */
-	    (*(void (*) (void)) ((void *) map->l_addr +
-				 map->l_info[DT_FINI]->d_un.d_ptr)) ();
-
-	  if (map->l_info[DT_NEEDED])
+	  struct link_map *map = list[i];
+	  if (map->l_opencount == 0 && map->l_type == lt_loaded)
 	    {
-	      /* Also close all the dependencies.  */
-	      const char *strtab
-		= (void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr;
-	      const Elf32_Dyn *d;
-	      for (d = map->l_ld; d->d_tag != DT_NULL; ++d)
-		if (d->d_tag == DT_NEEDED)
+	      /* That was the last reference, and this was a dlopen-loaded
+		 object.  We can unmap it.  */
+	      const Elf32_Phdr *ph;
+
+	      if (map->l_info[DT_FINI])
+		/* Call its termination function.  */
+		(*(void (*) (void)) ((void *) map->l_addr +
+				     map->l_info[DT_FINI]->d_un.d_ptr)) ();
+
+	      /* Unmap the segments.  */
+	      for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
+		if (ph->p_type == PT_LOAD)
 		  {
-		    /* It must already be open, since this one needed it;
-		       so dlopen will just find us its `struct link_map'
-		       and bump its reference count.  */
-		    struct link_map *o, *dep
-		      = dlopen (strtab + d->d_un.d_val, RTLD_LAZY);
-		    --dep->l_opencount; /* Lose the ref from that dlopen.  */
-		    /* Now we have the handle; we can close it for real.  */
-		    o = map;
-		    map = dep;
-		    doit ();
-		    map = o;
+		    Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1);
+		    Elf32_Addr mapend = ((ph->p_vaddr + ph->p_memsz
+					  + ph->p_align - 1)
+					 & ~(ph->p_align - 1));
+		    munmap ((caddr_t) mapstart, mapend - mapstart);
 		  }
-	    }
 
-	  /* Unmap the segments.  */
-	  for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
-	    if (ph->p_type == PT_LOAD)
-	      {
-		Elf32_Addr mapstart = ph->p_vaddr & ~(ph->p_align - 1);
-		Elf32_Addr mapend = ((ph->p_vaddr + ph->p_memsz
-				      + ph->p_align - 1)
-				     & ~(ph->p_align - 1));
-		munmap ((caddr_t) mapstart, mapend - mapstart);
-	      }
-
-	  /* Finally, unlink the data structure and free it.  */
-	  map->l_prev->l_next = map->l_next;
-	  if (map->l_next)
-	    map->l_next->l_prev = map->l_prev;
-	  free (map);
+	      /* Finally, unlink the data structure and free it.  */
+	      map->l_prev->l_next = map->l_next;
+	      if (map->l_next)
+		map->l_next->l_prev = map->l_prev;
+	      if (map->l_searchlist)
+		free (map->l_searchlist);
+	      free (map);
+	    }
 	}
+
+      free (list);
     }
 
   return _dlerror_run (doit) ? -1 : 0;