ec563ed8d0e56a9ed0f419858da86413741eb448
[kopensolaris-gnu/glibc.git] / elf / dl-close.c
1 /* Close a shared object opened by `_dl_open'.
2    Copyright (C) 1996, 1997, 1998, 1999, 2000 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 not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.  */
19
20 #include <assert.h>
21 #include <dlfcn.h>
22 #include <libintl.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <bits/libc-lock.h>
26 #include <ldsodefs.h>
27 #include <sys/types.h>
28 #include <sys/mman.h>
29
30
31 /* Type of the constructor functions.  */
32 typedef void (*fini_t) (void);
33
34
35 /* During the program run we must not modify the global data of
36    loaded shared object simultanously in two threads.  Therefore we
37    protect `dlopen' and `dlclose' in dlclose.c.  */
38 __libc_lock_define (extern, _dl_load_lock)
39
40 void
41 internal_function
42 _dl_close (void *_map)
43 {
44   struct link_map **list;
45   struct link_map **rellist;
46   struct link_map *map = _map;
47   unsigned int nsearchlist;
48   unsigned int nrellist;
49   unsigned int i;
50
51   if (map->l_opencount == 0)
52     _dl_signal_error (0, map->l_name, N_("shared object not open"));
53
54   /* Acquire the lock.  */
55   __libc_lock_lock (_dl_load_lock);
56
57   /* Decrement the reference count.  */
58   if (map->l_opencount > 1 || map->l_type != lt_loaded)
59     {
60       /* There are still references to this object.  Do nothing more.  */
61       --map->l_opencount;
62       __libc_lock_unlock (_dl_load_lock);
63       return;
64     }
65
66   list = map->l_searchlist.r_list;
67   nsearchlist = map->l_searchlist.r_nlist;
68
69   rellist = map->l_reldeps;
70   nrellist = map->l_reldepsact;
71
72   /* Call all termination functions at once.  */
73   for (i = 0; i < nsearchlist; ++i)
74     {
75       struct link_map *imap = map->l_initfini[i];
76       if (imap->l_opencount == 1 && imap->l_type == lt_loaded
77           && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY])
78           /* Skip any half-cooked objects that were never initialized.  */
79           && imap->l_init_called)
80         {
81           /* When debugging print a message first.  */
82           if (__builtin_expect (_dl_debug_impcalls, 0))
83             _dl_debug_message (1, "\ncalling fini: ", imap->l_name,
84                                "\n\n", NULL);
85
86           /* Call its termination function.  */
87           if (imap->l_info[DT_FINI_ARRAY] != NULL)
88             {
89               ElfW(Addr) *array =
90                 (ElfW(Addr) *) (imap->l_addr
91                                 + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr);
92               unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val
93                                  / sizeof (ElfW(Addr)));
94               unsigned int cnt;
95
96               for (cnt = 0; cnt < sz; ++cnt)
97                 ((fini_t) (imap->l_addr + array[cnt])) ();
98             }
99
100           /* Next try the old-style destructor.  */
101           if (imap->l_info[DT_FINI] != NULL)
102             (*(void (*) (void)) ((void *) imap->l_addr
103                                  + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
104         }
105     }
106
107   /* Notify the debugger we are about to remove some loaded objects.  */
108   _r_debug.r_state = RT_DELETE;
109   _dl_debug_state ();
110
111   /* The search list contains a counted reference to each object it
112      points to, the 0th elt being MAP itself.  Decrement the reference
113      counts on all the objects MAP depends on.  */
114   for (i = 0; i < nsearchlist; ++i)
115     --list[i]->l_opencount;
116
117   /* Check each element of the search list to see if all references to
118      it are gone.  */
119   for (i = 0; i < nsearchlist; ++i)
120     {
121       struct link_map *imap = list[i];
122       if (imap->l_opencount == 0 && imap->l_type == lt_loaded)
123         {
124           struct libname_list *lnp;
125
126           /* That was the last reference, and this was a dlopen-loaded
127              object.  We can unmap it.  */
128           if (imap->l_global)
129             {
130               /* This object is in the global scope list.  Remove it.  */
131               int cnt = _dl_main_searchlist->r_nlist;
132
133               do
134                 --cnt;
135               while (_dl_main_searchlist->r_list[cnt] != imap);
136
137               /* The object was already correctly registered.  */
138               while (++cnt < _dl_main_searchlist->r_nlist)
139                 _dl_main_searchlist->r_list[cnt - 1]
140                   = _dl_main_searchlist->r_list[cnt];
141
142               --_dl_main_searchlist->r_nlist;
143             }
144
145           /* We can unmap all the maps at once.  We determined the
146              start address and length when we loaded the object and
147              the `munmap' call does the rest.  */
148           __munmap ((void *) imap->l_map_start,
149                     imap->l_map_end - imap->l_map_start);
150
151           /* Finally, unlink the data structure and free it.  */
152 #ifdef SHARED
153           /* We will unlink the first object only if this is a statically
154              linked program.  */
155           assert (imap->l_prev != NULL);
156           imap->l_prev->l_next = imap->l_next;
157 #else
158           if (imap->l_prev != NULL)
159             imap->l_prev->l_next = imap->l_next;
160           else
161             _dl_loaded = imap->l_next;
162 #endif
163           if (imap->l_next)
164             imap->l_next->l_prev = imap->l_prev;
165
166           if (imap->l_versions != NULL)
167             free (imap->l_versions);
168           if (imap->l_origin != NULL && imap->l_origin != (char *) -1)
169             free ((char *) imap->l_origin);
170
171           /* This name always is allocated.  */
172           free (imap->l_name);
173           /* Remove the list with all the names of the shared object.  */
174           lnp = imap->l_libname;
175           do
176             {
177               struct libname_list *this = lnp;
178               lnp = lnp->next;
179               free (this);
180             }
181           while (lnp != NULL);
182
183           /* Remove the searchlists.  */
184           if (imap != map)
185             {
186             if (imap->l_searchlist.r_list != NULL)
187               free (imap->l_searchlist.r_list);
188             else if (imap->l_initfini != NULL)
189               free (imap->l_initfini);
190             }
191
192           if (imap->l_phdr_allocated)
193             free ((void *) imap->l_phdr);
194
195           free (imap);
196         }
197     }
198
199   /* Now we can perhaps also remove the modules for which we had
200      dependencies because of symbol lookup.  */
201   if (rellist != NULL)
202     {
203       while (nrellist-- > 0)
204         _dl_close (rellist[nrellist]);
205
206       free (rellist);
207     }
208
209   free (list);
210
211   if (_dl_global_scope_alloc != 0
212       && _dl_main_searchlist->r_nlist == _dl_initial_searchlist.r_nlist)
213     {
214       /* All object dynamically loaded by the program are unloaded.  Free
215          the memory allocated for the global scope variable.  */
216       struct link_map **old = _dl_main_searchlist->r_list;
217
218       /* Put the old map in.  */
219       _dl_main_searchlist->r_list = _dl_initial_searchlist.r_list;
220       /* Signal that the original map is used.  */
221       _dl_global_scope_alloc = 0;
222
223       /* Now free the old map.  */
224       free (old);
225     }
226
227   /* Notify the debugger those objects are finalized and gone.  */
228   _r_debug.r_state = RT_CONSISTENT;
229   _dl_debug_state ();
230
231   /* Release the lock.  */
232   __libc_lock_unlock (_dl_load_lock);
233 }