* csu/elf-init.c (__libc_csu_fini): Don't do anything here.
[jlayton/glibc.git] / elf / dl-libc.c
1 /* Handle loading and unloading shared objects for internal libc purposes.
2    Copyright (C) 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Zack Weinberg <zack@rabi.columbia.edu>, 1999.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include <dlfcn.h>
22 #include <stdlib.h>
23 #include <ldsodefs.h>
24
25 extern int __libc_argc attribute_hidden;
26 extern char **__libc_argv attribute_hidden;
27
28 extern char **__environ;
29
30 /* The purpose of this file is to provide wrappers around the dynamic
31    linker error mechanism (similar to dlopen() et al in libdl) which
32    are usable from within libc.  Generally we want to throw away the
33    string that dlerror() would return and just pass back a null pointer
34    for errors.  This also lets the rest of libc not know about the error
35    handling mechanism.
36
37    Much of this code came from gconv_dl.c with slight modifications. */
38
39 static int
40 internal_function
41 dlerror_run (void (*operate) (void *), void *args)
42 {
43   const char *objname;
44   const char *last_errstring = NULL;
45   int result;
46
47   (void) GLRO(dl_catch_error) (&objname, &last_errstring, operate, args);
48
49   result = last_errstring != NULL;
50   if (result && last_errstring != _dl_out_of_memory)
51     free ((char *) last_errstring);
52
53   return result;
54 }
55
56 /* These functions are called by dlerror_run... */
57
58 struct do_dlopen_args
59 {
60   /* Argument to do_dlopen.  */
61   const char *name;
62   /* Opening mode.  */
63   int mode;
64
65   /* Return from do_dlopen.  */
66   struct link_map *map;
67 };
68
69 struct do_dlsym_args
70 {
71   /* Arguments to do_dlsym.  */
72   struct link_map *map;
73   const char *name;
74
75   /* Return values of do_dlsym.  */
76   lookup_t loadbase;
77   const ElfW(Sym) *ref;
78 };
79
80 static void
81 do_dlopen (void *ptr)
82 {
83   struct do_dlopen_args *args = (struct do_dlopen_args *) ptr;
84   /* Open and relocate the shared object.  */
85   args->map = GLRO(dl_open) (args->name, args->mode, NULL, __LM_ID_CALLER,
86                              __libc_argc, __libc_argv, __environ);
87 }
88
89 static void
90 do_dlsym (void *ptr)
91 {
92   struct do_dlsym_args *args = (struct do_dlsym_args *) ptr;
93   args->ref = NULL;
94   args->loadbase = GLRO(dl_lookup_symbol_x) (args->name, args->map, &args->ref,
95                                              args->map->l_local_scope, NULL, 0,
96                                              DL_LOOKUP_RETURN_NEWEST, NULL);
97 }
98
99 static void
100 do_dlclose (void *ptr)
101 {
102   GLRO(dl_close) ((struct link_map *) ptr);
103 }
104
105 /* This code is to support __libc_dlopen from __libc_dlopen'ed shared
106    libraries.  We need to ensure the statically linked __libc_dlopen
107    etc. functions are used instead of the dynamically loaded.  */
108 struct dl_open_hook
109 {
110   void *(*dlopen_mode) (const char *name, int mode);
111   void *(*dlsym) (void *map, const char *name);
112   int (*dlclose) (void *map);
113 };
114
115 #ifdef SHARED
116 extern struct dl_open_hook *_dl_open_hook;
117 libc_hidden_proto (_dl_open_hook);
118 struct dl_open_hook *_dl_open_hook __attribute__ ((nocommon));
119 libc_hidden_data_def (_dl_open_hook);
120 #else
121 static void
122 do_dlsym_private (void *ptr)
123 {
124   lookup_t l;
125   struct r_found_version vers;
126   vers.name = "GLIBC_PRIVATE";
127   vers.hidden = 1;
128   /* vers.hash = _dl_elf_hash (vers.name);  */
129   vers.hash = 0x0963cf85;
130   vers.filename = NULL;
131
132   struct do_dlsym_args *args = (struct do_dlsym_args *) ptr;
133   args->ref = NULL;
134   l = GLRO(dl_lookup_symbol_x) (args->name, args->map, &args->ref,
135                                 args->map->l_scope, &vers, 0, 0, NULL);
136   args->loadbase = l;
137 }
138
139 static struct dl_open_hook _dl_open_hook =
140   {
141     .dlopen_mode = __libc_dlopen_mode,
142     .dlsym = __libc_dlsym,
143     .dlclose = __libc_dlclose
144   };
145 #endif
146
147 /* ... and these functions call dlerror_run. */
148
149 void *
150 __libc_dlopen_mode (const char *name, int mode)
151 {
152   struct do_dlopen_args args;
153   args.name = name;
154   args.mode = mode;
155
156 #ifdef SHARED
157   if (__builtin_expect (_dl_open_hook != NULL, 0))
158     return _dl_open_hook->dlopen_mode (name, mode);
159   return (dlerror_run (do_dlopen, &args) ? NULL : (void *) args.map);
160 #else
161   if (dlerror_run (do_dlopen, &args))
162     return NULL;
163
164   __libc_register_dl_open_hook (args.map);
165   __libc_register_dlfcn_hook (args.map);
166   return (void *) args.map;
167 #endif
168 }
169 libc_hidden_def (__libc_dlopen_mode)
170
171 #ifndef SHARED
172 void *
173 __libc_dlsym_private (struct link_map *map, const char *name)
174 {
175   struct do_dlsym_args sargs;
176   sargs.map = map;
177   sargs.name = name;
178
179   if (! dlerror_run (do_dlsym_private, &sargs))
180     return DL_SYMBOL_ADDRESS (sargs.loadbase, sargs.ref);
181   return NULL;
182 }
183
184 void
185 __libc_register_dl_open_hook (struct link_map *map)
186 {
187   struct dl_open_hook **hook;
188
189   hook = (struct dl_open_hook **) __libc_dlsym_private (map, "_dl_open_hook");
190   if (hook != NULL)
191     *hook = &_dl_open_hook;
192 }
193 #endif
194
195 void *
196 __libc_dlsym (void *map, const char *name)
197 {
198   struct do_dlsym_args args;
199   args.map = map;
200   args.name = name;
201
202 #ifdef SHARED
203   if (__builtin_expect (_dl_open_hook != NULL, 0))
204     return _dl_open_hook->dlsym (map, name);
205 #endif
206   return (dlerror_run (do_dlsym, &args) ? NULL
207           : (void *) (DL_SYMBOL_ADDRESS (args.loadbase, args.ref)));
208 }
209 libc_hidden_def (__libc_dlsym)
210
211 int
212 __libc_dlclose (void *map)
213 {
214 #ifdef SHARED
215   if (__builtin_expect (_dl_open_hook != NULL, 0))
216     return _dl_open_hook->dlclose (map);
217 #endif
218   return dlerror_run (do_dlclose, map);
219 }
220 libc_hidden_def (__libc_dlclose)
221
222
223 libc_freeres_fn (free_mem)
224 {
225   struct link_map *l;
226   struct r_search_path_elem *d;
227
228   /* Remove all search directories.  */
229   d = GL(dl_all_dirs);
230   while (d != GLRO(dl_init_all_dirs))
231     {
232       struct r_search_path_elem *old = d;
233       d = d->next;
234       free (old);
235     }
236
237   /* Remove all additional names added to the objects.  */
238   for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
239     for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
240       {
241         struct libname_list *lnp = l->l_libname->next;
242
243         l->l_libname->next = NULL;
244
245         while (lnp != NULL)
246           {
247             struct libname_list *old = lnp;
248             lnp = lnp->next;
249             if (! old->dont_free)
250             free (old);
251           }
252       }
253 }