058c3e5a394a757b529f4c4d02b58169f7969776
[kopensolaris-gnu/glibc.git] / elf / dl-open.c
1 /* Load a shared object at runtime, relocate it, and run its initializer.
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>
23 #include <errno.h>
24
25 size_t _dl_global_scope_alloc;
26
27 struct link_map *
28 _dl_open (const char *file, int mode)
29 {
30   struct link_map *new, *l;
31   ElfW(Addr) init;
32   struct r_debug *r;
33
34
35   /* Load the named object.  */
36   new = _dl_map_object (NULL, file, lt_loaded);
37   if (new->l_searchlist)
38     /* It was already open.  */
39     return new;
40
41   /* Load that object's dependencies.  */
42   _dl_map_object_deps (new, NULL, 0);
43
44
45   /* Relocate the objects loaded.  We do this in reverse order so that copy
46      relocs of earlier objects overwrite the data written by later objects.  */
47
48   l = new;
49   while (l->l_next)
50     l = l->l_next;
51   while (1)
52     {
53       if (! l->l_relocated)
54         {
55           _dl_relocate_object (l, _dl_object_relocation_scope (l),
56                                (mode & RTLD_BINDING_MASK) == RTLD_LAZY);
57           *_dl_global_scope_end = NULL;
58         }
59
60       if (l == new)
61         break;
62       l = l->l_prev;
63     }
64
65   new->l_global = (mode & RTLD_GLOBAL);
66   if (new->l_global)
67     {
68       /* The symbols of the new object and its dependencies are to be
69          introduced into the global scope that will be used to resolve
70          references from other dynamically-loaded objects.  */
71
72       if (_dl_global_scope_alloc == 0)
73         {
74           /* This is the first dynamic object given global scope.  */
75           _dl_global_scope_alloc = 8;
76           _dl_global_scope = malloc (8 * sizeof (struct link_map *));
77           if (! _dl_global_scope)
78             {
79               _dl_global_scope = _dl_default_scope;
80             nomem:
81               _dl_close (new);
82               _dl_signal_error (ENOMEM, file, "cannot extend global scope");
83             }
84           _dl_global_scope[2] = _dl_default_scope[2];
85           _dl_global_scope[3] = new;
86           _dl_global_scope[4] = NULL;
87           _dl_global_scope[5] = NULL;
88         }
89       else
90         {
91           if (_dl_global_scope_alloc <
92               _dl_global_scope_end - _dl_global_scope + 2)
93             {
94               /* Must extend the list.  */
95               struct link_map **new = realloc (_dl_global_scope,
96                                                _dl_global_scope_alloc * 2);
97               if (! new)
98                 goto nomem;
99               _dl_global_scope_end = new + (_dl_global_scope_end -
100                                             _dl_global_scope);
101               _dl_global_scope = new;
102               _dl_global_scope_alloc *= 2;
103             }
104
105           /* Append the new object and re-terminate the list.  */
106           *_dl_global_scope_end++ = new;
107           /* We keep the list double-terminated so the last element
108              can be filled in for symbol lookups.  */
109           _dl_global_scope_end[0] = NULL;
110           _dl_global_scope_end[1] = NULL;
111         }
112     }
113
114
115   /* Notify the debugger we have added some objects.  We need to call
116      _dl_debug_initialize in a static program in case dynamic linking has
117      not been used before.  */
118   r = _dl_debug_initialize (0);
119   r->r_state = RT_ADD;
120   _dl_debug_state ();
121
122   /* Run the initializer functions of new objects.  */
123   while (init = _dl_init_next (new))
124     (*(void (*) (void)) init) ();
125
126   return new;
127 }