70d7ab40834397d8ebfd9174c4322c9251291cbf
[kopensolaris-gnu/glibc.git] / elf / dl-close.c
1 /* _dl_close -- Close a shared object opened by `_dl_open'.
2 Copyright (C) 1996 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB.  If
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA.  */
19
20 #include <link.h>
21 #include <dlfcn.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/mman.h>
26
27
28 #define LOSE(s) _dl_signal_error (0, map->l_name, s)
29
30 void
31 _dl_close (struct link_map *map)
32 {
33   struct link_map **list;
34   unsigned int i;
35
36   if (map->l_opencount == 0)
37     LOSE ("shared object not open");
38
39   /* Decrement the reference count.  */
40   if (--map->l_opencount > 0 || map->l_type != lt_loaded)
41     /* There are still references to this object.  Do nothing more.  */
42     return;
43
44   list = map->l_searchlist;
45
46   /* The search list contains a counted reference to each object it
47      points to, the 0th elt being MAP itself.  Decrement the reference
48      counts on all the objects MAP depends on.  */
49   for (i = 1; i < map->l_nsearchlist; ++i)
50     --list[i]->l_opencount;
51
52   /* Clear the search list so it doesn't get freed while we are still
53      using it.  We have cached it in LIST and will free it when
54      finished.  */
55   map->l_searchlist = NULL;
56
57   /* Check each element of the search list to see if all references to
58      it are gone.  */
59   for (i = 0; i < map->l_nsearchlist; ++i)
60     {
61       struct link_map *map = list[i];
62       if (map->l_opencount == 0 && map->l_type == lt_loaded)
63         {
64           /* That was the last reference, and this was a dlopen-loaded
65              object.  We can unmap it.  */
66           const ElfW(Phdr) *ph;
67
68           if (map->l_info[DT_FINI])
69             /* Call its termination function.  */
70             (*(void (*) (void)) ((void *) map->l_addr +
71                                  map->l_info[DT_FINI]->d_un.d_ptr)) ();
72
73           if (map->l_global)
74             {
75               /* This object is in the global scope list.  Remove it.  */
76               struct link_map **tail = _dl_global_scope_end;
77               do
78                 --tail;
79               while (*tail != map);
80               --_dl_global_scope_end;
81               memcpy (tail, tail + 1, _dl_global_scope_end - tail);
82               _dl_global_scope_end[0] = NULL;
83               _dl_global_scope_end[1] = NULL;
84             }
85
86           /* Unmap the segments.  */
87           for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
88             if (ph->p_type == PT_LOAD)
89               {
90                 ElfW(Addr) mapstart = ph->p_vaddr & ~(ph->p_align - 1);
91                 ElfW(Addr) mapend = ((ph->p_vaddr + ph->p_memsz
92                                       + ph->p_align - 1)
93                                      & ~(ph->p_align - 1));
94                 __munmap ((caddr_t) mapstart, mapend - mapstart);
95               }
96
97           /* Finally, unlink the data structure and free it.  */
98           map->l_prev->l_next = map->l_next;
99           if (map->l_next)
100             map->l_next->l_prev = map->l_prev;
101           if (map->l_searchlist)
102             free (map->l_searchlist);
103           free (map);
104         }
105     }
106
107   free (list);
108 }