* elf/dl-open.c (_dl_sysdep_start): Wrap weak_extern decl in BP_SYM ().
[platform/upstream/glibc.git] / elf / dl-open.c
1 /* Load a shared object at runtime, relocate it, and run its initializer.
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 <errno.h>
23 #include <libintl.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/mman.h>           /* Check whether MAP_COPY is defined.  */
28 #include <sys/param.h>
29 #include <bits/libc-lock.h>
30 #include <ldsodefs.h>
31 #include <bp-sym.h>
32
33 #include <dl-dst.h>
34
35
36 extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
37                                     void (*dl_main) (const ElfW(Phdr) *phdr,
38                                                      ElfW(Word) phnum,
39                                                      ElfW(Addr) *user_entry));
40 weak_extern (BP_SYM (_dl_sysdep_start))
41
42 /* This function is used to unload the cache file if necessary.  */
43 extern void _dl_unload_cache (void);
44
45 extern int __libc_multiple_libcs;       /* Defined in init-first.c.  */
46
47 extern int __libc_argc;
48 extern char **__libc_argv;
49
50 extern char **__environ;
51
52 extern int _dl_lazy;                    /* Do we do lazy relocations?  */
53
54 /* Undefine the following for debugging.  */
55 /* #define SCOPE_DEBUG 1 */
56 #ifdef SCOPE_DEBUG
57 static void show_scope (struct link_map *new);
58 #endif
59
60 /* During the program run we must not modify the global data of
61    loaded shared object simultanously in two threads.  Therefore we
62    protect `_dl_open' and `_dl_close' in dl-close.c.
63
64    This must be a recursive lock since the initializer function of
65    the loaded object might as well require a call to this function.
66    At this time it is not anymore a problem to modify the tables.  */
67 __libc_lock_define (extern, _dl_load_lock)
68
69 extern size_t _dl_platformlen;
70
71 /* We must be carefull not to leave us in an inconsistent state.  Thus we
72    catch any error and re-raise it after cleaning up.  */
73
74 struct dl_open_args
75 {
76   const char *file;
77   int mode;
78   const void *caller;
79   struct link_map *map;
80 };
81
82 static void
83 dl_open_worker (void *a)
84 {
85   struct dl_open_args *args = a;
86   const char *file = args->file;
87   int mode = args->mode;
88   struct link_map *new, *l;
89   const char *dst;
90   int lazy;
91
92   /* Maybe we have to expand a DST.  */
93   dst = strchr (file, '$');
94   if (dst != NULL)
95     {
96       const void *caller = args->caller;
97       size_t len = strlen (file);
98       size_t required;
99       struct link_map *call_map;
100       char *new_file;
101
102       /* DSTs must not appear in SUID/SGID programs.  */
103       if (__libc_enable_secure)
104         /* This is an error.  */
105         _dl_signal_error (0, "dlopen",
106                           N_("DST not allowed in SUID/SGID programs"));
107
108       /* We have to find out from which object the caller is calling.
109          Find the highest-addressed object that ADDRESS is not below.  */
110       call_map = NULL;
111       for (l = _dl_loaded; l; l = l->l_next)
112         if (l->l_addr != 0 /* Make sure we do not currently set this map up
113                               in this moment.  */
114             && caller >= (const void *) l->l_map_start
115             && caller < (const void *) l->l_map_end)
116           {
117             /* There must be exactly one DSO for the range of the virtual
118                memory.  Otherwise something is really broken.  */
119             call_map = l;
120             break;
121           }
122
123       if (call_map == NULL)
124         /* In this case we assume this is the main application.  */
125         call_map = _dl_loaded;
126
127       /* Determine how much space we need.  We have to allocate the
128          memory locally.  */
129       required = DL_DST_REQUIRED (call_map, file, len, _dl_dst_count (dst, 0));
130
131       /* Get space for the new file name.  */
132       new_file = (char *) alloca (required + 1);
133
134       /* Generate the new file name.  */
135       DL_DST_SUBSTITUTE (call_map, file, new_file, 0);
136
137       /* If the substitution failed don't try to load.  */
138       if (*new_file == '\0')
139         _dl_signal_error (0, "dlopen",
140                           N_("empty dynamic string token substitution"));
141
142       /* Now we have a new file name.  */
143       file = new_file;
144     }
145
146   /* Load the named object.  */
147   args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0);
148   if (new->l_searchlist.r_list)
149     /* It was already open.  */
150     return;
151
152   /* Load that object's dependencies.  */
153   _dl_map_object_deps (new, NULL, 0, 0);
154
155   /* So far, so good.  Now check the versions.  */
156   (void) _dl_check_all_versions (new, 0, 0);
157
158 #ifdef SCOPE_DEBUG
159   show_scope (new);
160 #endif
161
162   /* Only do lazy relocation if `LD_BIND_NOW' is not set.  */
163   lazy = (mode & RTLD_BINDING_MASK) == RTLD_LAZY && _dl_lazy;
164
165   /* Relocate the objects loaded.  We do this in reverse order so that copy
166      relocs of earlier objects overwrite the data written by later objects.  */
167
168   l = new;
169   while (l->l_next)
170     l = l->l_next;
171   while (1)
172     {
173       if (! l->l_relocated)
174         {
175 #ifdef SHARED
176           if (_dl_profile != NULL)
177             {
178               /* If this here is the shared object which we want to profile
179                  make sure the profile is started.  We can find out whether
180                  this is necessary or not by observing the `_dl_profile_map'
181                  variable.  If was NULL but is not NULL afterwars we must
182                  start the profiling.  */
183               struct link_map *old_profile_map = _dl_profile_map;
184
185               _dl_relocate_object (l, l->l_scope, 1, 1);
186
187               if (old_profile_map == NULL && _dl_profile_map != NULL)
188                 /* We must prepare the profiling.  */
189                 _dl_start_profile (_dl_profile_map, _dl_profile_output);
190             }
191           else
192 #endif
193             _dl_relocate_object (l, l->l_scope, lazy, 0);
194         }
195
196       if (l == new)
197         break;
198       l = l->l_prev;
199     }
200
201   /* Run the initializer functions of new objects.  */
202   _dl_init (new, __libc_argc, __libc_argv, __environ);
203
204   /* Now we can make the new map available in the global scope.  */
205   if (mode & RTLD_GLOBAL)
206     {
207       struct link_map **new_global;
208       unsigned int to_add = 0;
209       unsigned int cnt;
210
211       /* Count the objects we have to put in the global scope.  */
212       for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
213         if (new->l_searchlist.r_list[cnt]->l_global == 0)
214           ++to_add;
215
216       /* The symbols of the new objects and its dependencies are to be
217          introduced into the global scope that will be used to resolve
218          references from other dynamically-loaded objects.
219
220          The global scope is the searchlist in the main link map.  We
221          extend this list if necessary.  There is one problem though:
222          since this structure was allocated very early (before the libc
223          is loaded) the memory it uses is allocated by the malloc()-stub
224          in the ld.so.  When we come here these functions are not used
225          anymore.  Instead the malloc() implementation of the libc is
226          used.  But this means the block from the main map cannot be used
227          in an realloc() call.  Therefore we allocate a completely new
228          array the first time we have to add something to the locale scope.  */
229
230       if (_dl_global_scope_alloc == 0)
231         {
232           /* This is the first dynamic object given global scope.  */
233           _dl_global_scope_alloc = _dl_main_searchlist->r_nlist + to_add + 8;
234           new_global = (struct link_map **)
235             malloc (_dl_global_scope_alloc * sizeof (struct link_map *));
236           if (new_global == NULL)
237             {
238               _dl_global_scope_alloc = 0;
239             nomem:
240               _dl_signal_error (ENOMEM, new->l_libname->name,
241                                 N_("cannot extend global scope"));
242               return;
243             }
244
245           /* Copy over the old entries.  */
246           memcpy (new_global, _dl_main_searchlist->r_list,
247                   (_dl_main_searchlist->r_nlist * sizeof (struct link_map *)));
248
249           _dl_main_searchlist->r_list = new_global;
250         }
251       else if (_dl_main_searchlist->r_nlist + to_add > _dl_global_scope_alloc)
252         {
253           /* We have to extend the existing array of link maps in the
254              main map.  */
255           new_global = (struct link_map **)
256             realloc (_dl_main_searchlist->r_list,
257                      ((_dl_global_scope_alloc + to_add + 8)
258                       * sizeof (struct link_map *)));
259           if (new_global == NULL)
260             goto nomem;
261
262           _dl_global_scope_alloc += to_add + 8;
263           _dl_main_searchlist->r_list = new_global;
264         }
265
266       /* Now add the new entries.  */
267       for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
268         {
269           struct link_map *map = new->l_searchlist.r_list[cnt];
270
271           if (map->l_global == 0)
272             {
273               map->l_global = 1;
274               _dl_main_searchlist->r_list[_dl_main_searchlist->r_nlist] = map;
275               ++_dl_main_searchlist->r_nlist;
276             }
277         }
278
279       /* XXX Do we have to add something to r_dupsearchlist???  --drepper */
280     }
281
282   if (_dl_sysdep_start == NULL)
283     /* We must be the static _dl_open in libc.a.  A static program that
284        has loaded a dynamic object now has competition.  */
285     __libc_multiple_libcs = 1;
286 }
287
288
289 void *
290 internal_function
291 _dl_open (const char *file, int mode, const void *caller)
292 {
293   struct dl_open_args args;
294   const char *objname;
295   const char *errstring;
296   int errcode;
297
298   if ((mode & RTLD_BINDING_MASK) == 0)
299     /* One of the flags must be set.  */
300     _dl_signal_error (EINVAL, file, N_("invalid mode for dlopen()"));
301
302   /* Make sure we are alone.  */
303   __libc_lock_lock (_dl_load_lock);
304
305   args.file = file;
306   args.mode = mode;
307   args.caller = caller;
308   args.map = NULL;
309   errcode = _dl_catch_error (&objname, &errstring, dl_open_worker, &args);
310
311 #ifndef MAP_COPY
312   /* We must munmap() the cache file.  */
313   _dl_unload_cache ();
314 #endif
315
316   /* Release the lock.  */
317   __libc_lock_unlock (_dl_load_lock);
318
319   if (errstring)
320     {
321       /* Some error occurred during loading.  */
322       char *local_errstring;
323
324       /* Remove the object from memory.  It may be in an inconsistent
325          state if relocation failed, for example.  */
326       if (args.map)
327         _dl_close (args.map);
328
329       /* Make a local copy of the error string so that we can release the
330          memory allocated for it.  */
331       local_errstring = strdupa (errstring);
332       free ((char *) errstring);
333
334       /* Reraise the error.  */
335       _dl_signal_error (errcode, objname, local_errstring);
336     }
337
338   return args.map;
339 }
340
341
342 #ifdef SCOPE_DEBUG
343 #include <unistd.h>
344
345 static void
346 show_scope (struct link_map *new)
347 {
348   int scope_cnt;
349
350   for (scope_cnt = 0; new->l_scope[scope_cnt] != NULL; ++scope_cnt)
351     {
352       char numbuf[2];
353       unsigned int cnt;
354
355       numbuf[0] = '0' + scope_cnt;
356       numbuf[1] = '\0';
357       _dl_sysdep_message ("scope ", numbuf, ":", NULL);
358
359       for (cnt = 0; cnt < new->l_scope[scope_cnt]->r_nlist; ++cnt)
360         if (*new->l_scope[scope_cnt]->r_list[cnt]->l_name)
361           _dl_sysdep_message (" ",
362                               new->l_scope[scope_cnt]->r_list[cnt]->l_name,
363                               NULL);
364         else
365           _dl_sysdep_message (" <main>", NULL);
366
367       _dl_sysdep_message ("\n", NULL);
368     }
369 }
370 #endif