]>
Commit | Line | Data |
---|---|---|
ba79d61b RM |
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> | |
8d6468d0 | 23 | #include <string.h> |
ba79d61b RM |
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 | } |