OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [newlib-1.17.0/] [newlib/] [libc/] [sys/] [linux/] [dl/] [dl-open.c] - Blame information for rev 816

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 148 jeremybenn
/* 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
 
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_function;
41
 
42
/* This function is used to unload the cache file if necessary.  */
43
extern void _dl_unload_cache (void);
44
 
45
int __libc_argc = 0;
46
char **__libc_argv = NULL;
47
 
48
extern char **environ;
49
 
50
extern int _dl_lazy;                    /* Do we do lazy relocations?  */
51
 
52
/* Undefine the following for debugging.  */
53
/* #define SCOPE_DEBUG 1 */
54
#ifdef SCOPE_DEBUG
55
static void show_scope (struct link_map *new);
56
#endif
57
 
58
extern 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
 
63
struct dl_open_args
64
{
65
  const char *file;
66
  int mode;
67
  const void *caller;
68
  struct link_map *map;
69
};
70
 
71
 
72
static int
73
add_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
 
151
static void
152
dl_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
 
375
void *
376
internal_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
 
464
static void
465
show_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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.