source: trunk/libs/newlib/src/newlib/libc/sys/linux/dl/dl-open.c

Last change on this file was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 13.6 KB
Line 
1/* Load a shared object at runtime, relocate it, and run its initializer.
2   Copyright (C) 1996,1997,1998,1999,2000,2001 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 Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the 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   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with the GNU C Library; if not, write to the Free
17   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18   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 <ldsodefs.h>
30#include <bp-sym.h>
31
32#include <dl-dst.h>
33#include <machine/weakalias.h>
34
35
36extern 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_function;
41
42/* This function is used to unload the cache file if necessary.  */
43extern void _dl_unload_cache (void);
44
45int __libc_argc = 0;
46char **__libc_argv = NULL;
47
48extern char **environ;
49
50extern int _dl_lazy;                    /* Do we do lazy relocations?  */
51
52/* Undefine the following for debugging.  */
53/* #define SCOPE_DEBUG 1 */
54#ifdef SCOPE_DEBUG
55static void show_scope (struct link_map *new);
56#endif
57
58extern size_t _dl_platformlen;
59
60/* We must be carefull not to leave us in an inconsistent state.  Thus we
61   catch any error and re-raise it after cleaning up.  */
62
63struct dl_open_args
64{
65  const char *file;
66  int mode;
67  const void *caller;
68  struct link_map *map;
69};
70
71
72static int
73add_to_global (struct link_map *new)
74{
75  struct link_map **new_global;
76  unsigned int to_add = 0;
77  unsigned int cnt;
78
79  /* Count the objects we have to put in the global scope.  */
80  for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
81    if (new->l_searchlist.r_list[cnt]->l_global == 0)
82      ++to_add;
83
84  /* The symbols of the new objects and its dependencies are to be
85     introduced into the global scope that will be used to resolve
86     references from other dynamically-loaded objects.
87
88     The global scope is the searchlist in the main link map.  We
89     extend this list if necessary.  There is one problem though:
90     since this structure was allocated very early (before the libc
91     is loaded) the memory it uses is allocated by the malloc()-stub
92     in the ld.so.  When we come here these functions are not used
93     anymore.  Instead the malloc() implementation of the libc is
94     used.  But this means the block from the main map cannot be used
95     in an realloc() call.  Therefore we allocate a completely new
96     array the first time we have to add something to the locale scope.  */
97
98  if (_dl_global_scope_alloc == 0)
99    {
100      /* This is the first dynamic object given global scope.  */
101      _dl_global_scope_alloc = _dl_main_searchlist->r_nlist + to_add + 8;
102      new_global = (struct link_map **)
103        malloc (_dl_global_scope_alloc * sizeof (struct link_map *));
104      if (new_global == NULL)
105        {
106          _dl_global_scope_alloc = 0;
107        nomem:
108          _dl_signal_error (ENOMEM, new->l_libname->name, NULL,
109                            N_("cannot extend global scope"));
110          return 1;
111        }
112
113      /* Copy over the old entries.  */
114      memcpy (new_global, _dl_main_searchlist->r_list,
115              (_dl_main_searchlist->r_nlist * sizeof (struct link_map *)));
116
117      _dl_main_searchlist->r_list = new_global;
118    }
119  else if (_dl_main_searchlist->r_nlist + to_add > _dl_global_scope_alloc)
120    {
121      /* We have to extend the existing array of link maps in the
122         main map.  */
123      new_global = (struct link_map **)
124        realloc (_dl_main_searchlist->r_list,
125                 ((_dl_global_scope_alloc + to_add + 8)
126                  * sizeof (struct link_map *)));
127      if (new_global == NULL)
128        goto nomem;
129
130      _dl_global_scope_alloc += to_add + 8;
131      _dl_main_searchlist->r_list = new_global;
132    }
133
134  /* Now add the new entries.  */
135  for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt)
136    {
137      struct link_map *map = new->l_searchlist.r_list[cnt];
138
139      if (map->l_global == 0)
140        {
141          map->l_global = 1;
142          _dl_main_searchlist->r_list[_dl_main_searchlist->r_nlist] = map;
143          ++_dl_main_searchlist->r_nlist;
144        }
145    }
146
147  return 0;
148}
149
150
151static void
152dl_open_worker (void *a)
153{
154  struct dl_open_args *args = a;
155  const char *file = args->file;
156  int mode = args->mode;
157  struct link_map *new, *l;
158  const char *dst;
159  int lazy;
160  unsigned int i;
161
162  /* Maybe we have to expand a DST.  */
163  dst = strchr (file, '$');
164  if (dst != NULL)
165    {
166      const void *caller = args->caller;
167      size_t len = strlen (file);
168      size_t required;
169      struct link_map *call_map;
170      char *new_file;
171
172      /* We have to find out from which object the caller is calling.  */
173      call_map = NULL;
174      for (l = _dl_loaded; l; l = l->l_next)
175        if (caller >= (const void *) l->l_map_start
176            && caller < (const void *) l->l_map_end)
177          {
178            /* There must be exactly one DSO for the range of the virtual
179               memory.  Otherwise something is really broken.  */
180            call_map = l;
181            break;
182          }
183
184      if (call_map == NULL)
185        /* In this case we assume this is the main application.  */
186        call_map = _dl_loaded;
187
188      /* Determine how much space we need.  We have to allocate the
189         memory locally.  */
190      required = DL_DST_REQUIRED (call_map, file, len, _dl_dst_count (dst, 0));
191
192      /* Get space for the new file name.  */
193      new_file = (char *) alloca (required + 1);
194
195      /* Generate the new file name.  */
196      DL_DST_SUBSTITUTE (call_map, file, new_file, 0);
197
198      /* If the substitution failed don't try to load.  */
199      if (*new_file == '\0')
200        _dl_signal_error (0, "dlopen", NULL,
201                          N_("empty dynamic string token substitution"));
202
203      /* Now we have a new file name.  */
204      file = new_file;
205    }
206
207  /* Load the named object.  */
208  args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0,
209                                    mode);
210
211  /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
212     set and the object is not already loaded.  */
213  if (new == NULL)
214    {
215      assert (mode & RTLD_NOLOAD);
216      return;
217    }
218
219  /* It was already open.  */
220  if (new->l_searchlist.r_list != NULL)
221    {
222      /* Let the user know about the opencount.  */
223      if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
224        _dl_debug_printf ("opening file=%s; opencount == %u\n\n",
225                          new->l_name, new->l_opencount);
226
227      /* If the user requested the object to be in the global namespace
228         but it is not so far, add it now.  */
229      if ((mode & RTLD_GLOBAL) && new->l_global == 0)
230        (void) add_to_global (new);
231
232      /* Increment just the reference counter of the object.  */
233      ++new->l_opencount;
234
235      return;
236    }
237
238  /* Load that object's dependencies.  */
239  _dl_map_object_deps (new, NULL, 0, 0);
240
241  /* So far, so good.  Now check the versions.  */
242  for (i = 0; i < new->l_searchlist.r_nlist; ++i)
243    if (new->l_searchlist.r_list[i]->l_versions == NULL)
244      (void) _dl_check_map_versions (new->l_searchlist.r_list[i], 0, 0);
245
246#ifdef SCOPE_DEBUG
247  show_scope (new);
248#endif
249
250  /* Only do lazy relocation if `LD_BIND_NOW' is not set.  */
251  lazy = (mode & RTLD_BINDING_MASK) == RTLD_LAZY && _dl_lazy;
252
253  /* Relocate the objects loaded.  We do this in reverse order so that copy
254     relocs of earlier objects overwrite the data written by later objects.  */
255
256  l = new;
257  while (l->l_next)
258    l = l->l_next;
259  while (1)
260    {
261      if (! l->l_relocated)
262        {
263#if 0
264#ifdef SHARED
265          if (_dl_profile != NULL)
266            {
267              /* If this here is the shared object which we want to profile
268                 make sure the profile is started.  We can find out whether
269                 this is necessary or not by observing the `_dl_profile_map'
270                 variable.  If was NULL but is not NULL afterwars we must
271                 start the profiling.  */
272              struct link_map *old_profile_map = _dl_profile_map;
273
274              _dl_relocate_object (l, l->l_scope, 1, 1);
275
276              if (old_profile_map == NULL && _dl_profile_map != NULL)
277                /* We must prepare the profiling.  */
278                _dl_start_profile (_dl_profile_map, _dl_profile_output);
279            }
280          else
281#endif
282#endif
283            _dl_relocate_object (l, l->l_scope, lazy, 0);
284        }
285
286      if (l == new)
287        break;
288      l = l->l_prev;
289    }
290
291  /* Increment the open count for all dependencies.  If the file is
292     not loaded as a dependency here add the search list of the newly
293     loaded object to the scope.  */
294  for (i = 0; i < new->l_searchlist.r_nlist; ++i)
295    if (++new->l_searchlist.r_list[i]->l_opencount > 1
296        && new->l_searchlist.r_list[i]->l_type == lt_loaded)
297      {
298        struct link_map *imap = new->l_searchlist.r_list[i];
299        struct r_scope_elem **runp = imap->l_scope;
300        size_t cnt = 0;
301
302        while (*runp != NULL)
303          {
304            /* This can happen if imap was just loaded, but during
305               relocation had l_opencount bumped because of relocation
306               dependency.  Avoid duplicates in l_scope.  */
307            if (__builtin_expect (*runp == &new->l_searchlist, 0))
308              break;
309
310            ++cnt;
311            ++runp;
312          }
313
314        if (*runp != NULL)
315          /* Avoid duplicates.  */
316          continue;
317
318        if (__builtin_expect (cnt + 1 >= imap->l_scope_max, 0))
319          {
320            /* The 'r_scope' array is too small.  Allocate a new one
321               dynamically.  */
322            struct r_scope_elem **newp;
323            size_t new_size = imap->l_scope_max * 2;
324
325            if (imap->l_scope == imap->l_scope_mem)
326              {
327                newp = (struct r_scope_elem **)
328                  malloc (new_size * sizeof (struct r_scope_elem *));
329                if (newp == NULL)
330                  _dl_signal_error (ENOMEM, "dlopen", NULL,
331                                    N_("cannot create scope list"));
332                imap->l_scope = memcpy (newp, imap->l_scope,
333                                        cnt * sizeof (imap->l_scope[0]));
334              }
335            else
336              {
337                newp = (struct r_scope_elem **)
338                  realloc (imap->l_scope,
339                           new_size * sizeof (struct r_scope_elem *));
340                if (newp == NULL)
341                  _dl_signal_error (ENOMEM, "dlopen", NULL,
342                                    N_("cannot create scope list"));
343                imap->l_scope = newp;
344              }
345
346            imap->l_scope_max = new_size;
347          }
348
349        imap->l_scope[cnt++] = &new->l_searchlist;
350        imap->l_scope[cnt] = NULL;
351      }
352
353  /* Run the initializer functions of new objects.  */
354  _dl_init (new, __libc_argc, __libc_argv, environ);
355
356  /* Now we can make the new map available in the global scope.  */
357  if (mode & RTLD_GLOBAL)
358    /* Move the object in the global namespace.  */
359    if (add_to_global (new) != 0)
360      /* It failed.  */
361      return;
362
363  /* Mark the object as not deletable if the RTLD_NODELETE flags was
364     passed.  */
365  if (__builtin_expect (mode & RTLD_NODELETE, 0))
366    new->l_flags_1 |= DF_1_NODELETE;
367
368  /* Let the user know about the opencount.  */
369  if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0))
370    _dl_debug_printf ("opening file=%s; opencount == %u\n\n",
371                      new->l_name, new->l_opencount);
372}
373
374
375void *
376internal_function
377_dl_open (const char *file, int mode, const void *caller)
378{
379  struct dl_open_args args;
380  const char *objname;
381  const char *errstring;
382  int errcode;
383
384  if ((mode & RTLD_BINDING_MASK) == 0)
385    /* One of the flags must be set.  */
386    _dl_signal_error (EINVAL, file, NULL, N_("invalid mode for dlopen()"));
387
388  /* Make sure we are alone.  */
389#ifdef HAVE_DD_LOCK
390    __lock_acquire_recursive(_dl_load_lock);
391#endif
392
393  args.file = file;
394  args.mode = mode;
395  args.caller = caller;
396  args.map = NULL;
397  errcode = _dl_catch_error (&objname, &errstring, dl_open_worker, &args);
398
399#ifndef MAP_COPY
400  /* We must munmap() the cache file.  */
401  _dl_unload_cache ();
402#endif
403
404  /* Release the lock.  */
405#ifdef HAVE_DD_LOCK
406    __lock_release_recursive(_dl_load_lock);
407#endif
408
409
410  if (errstring)
411    {
412      /* Some error occurred during loading.  */
413      char *local_errstring;
414      size_t len_errstring;
415
416      /* Remove the object from memory.  It may be in an inconsistent
417         state if relocation failed, for example.  */
418      if (args.map)
419        {
420          unsigned int i;
421
422          /* Increment open counters for all objects since this has
423             not happened yet.  */
424          for (i = 0; i < args.map->l_searchlist.r_nlist; ++i)
425            ++args.map->l_searchlist.r_list[i]->l_opencount;
426
427          _dl_close (args.map);
428        }
429
430      /* Make a local copy of the error string so that we can release the
431         memory allocated for it.  */
432      len_errstring = strlen (errstring) + 1;
433      if (objname == errstring + len_errstring)
434        {
435          size_t total_len = len_errstring + strlen (objname) + 1;
436          local_errstring = alloca (total_len);
437          memcpy (local_errstring, errstring, total_len);
438          objname = local_errstring + len_errstring;
439        }
440      else
441        {
442          local_errstring = alloca (len_errstring);
443          memcpy (local_errstring, errstring, len_errstring);
444        }
445
446      if (errstring != _dl_out_of_memory)
447        free ((char *) errstring);
448
449      /* Reraise the error.  */
450      _dl_signal_error (errcode, objname, NULL, local_errstring);
451    }
452
453#ifndef SHARED
454  DL_STATIC_INIT (args.map);
455#endif
456
457  return args.map;
458}
459
460
461#ifdef SCOPE_DEBUG
462#include <unistd.h>
463
464static void
465show_scope (struct link_map *new)
466{
467  int scope_cnt;
468
469  for (scope_cnt = 0; new->l_scope[scope_cnt] != NULL; ++scope_cnt)
470    {
471      char numbuf[2];
472      unsigned int cnt;
473
474      numbuf[0] = '0' + scope_cnt;
475      numbuf[1] = '\0';
476      _dl_printf ("scope %s:", numbuf);
477
478      for (cnt = 0; cnt < new->l_scope[scope_cnt]->r_nlist; ++cnt)
479        if (*new->l_scope[scope_cnt]->r_list[cnt]->l_name)
480          _dl_printf (" %s", new->l_scope[scope_cnt]->r_list[cnt]->l_name);
481        else
482          _dl_printf (" <main>");
483
484      _dl_printf ("\n");
485    }
486}
487#endif
Note: See TracBrowser for help on using the repository browser.