Update.
[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 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 <dlfcn.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <bits/libc-lock.h>
24 #include <elf/ldsodefs.h>
25
26
27 extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
28                                     void (*dl_main) (const ElfW(Phdr) *phdr,
29                                                      ElfW(Word) phnum,
30                                                      ElfW(Addr) *user_entry));
31 weak_extern (_dl_sysdep_start)
32
33 extern int __libc_multiple_libcs;       /* Defined in init-first.c.  */
34
35 extern int __libc_argc;
36 extern char **__libc_argv;
37
38 extern char **__environ;
39
40 static size_t _dl_global_scope_alloc;
41
42
43 /* During the program run we must not modify the global data of
44    loaded shared object simultanously in two threads.  Therefore we
45    protect `_dl_open' and `_dl_close' in dl-close.c.
46
47    This must be a recursive lock since the initializer function of
48    the loaded object might as well require a call to this function.
49    At this time it is not anymore a problem to modify the tables.  */
50 __libc_lock_define_initialized_recursive (, _dl_load_lock)
51
52
53 struct link_map *
54 internal_function
55 _dl_open (const char *file, int mode)
56 {
57   struct link_map *new, *l;
58   ElfW(Addr) init;
59   struct r_debug *r;
60
61   /* Make sure we are alone.  */
62   __libc_lock_lock (_dl_load_lock);
63
64   /* Load the named object.  */
65   new = _dl_map_object (NULL, file, 0, lt_loaded, 0);
66   if (new->l_searchlist)
67     {
68       /* It was already open.  */
69       __libc_lock_unlock (_dl_load_lock);
70       return new;
71     }
72
73   /* Load that object's dependencies.  */
74   _dl_map_object_deps (new, NULL, 0, 0);
75
76   /* So far, so good.  Now check the versions.  */
77   (void) _dl_check_all_versions (new, 0);
78
79   /* Relocate the objects loaded.  We do this in reverse order so that copy
80      relocs of earlier objects overwrite the data written by later objects.  */
81
82   l = new;
83   while (l->l_next)
84     l = l->l_next;
85   while (1)
86     {
87       if (! l->l_relocated)
88         {
89           /* We use an indirect call call for _dl_relocate_object because
90              we must avoid using the PLT in the call.  If our PLT entry for
91              _dl_relocate_object hasn't been used yet, then the dynamic
92              linker fixup routine will clobber _dl_global_scope during its
93              work.  We must be sure that nothing will require a PLT fixup
94              between when _dl_object_relocation_scope returns and when we
95              enter the dynamic linker's code (_dl_relocate_object).  */
96           __typeof (_dl_relocate_object) *reloc = &_dl_relocate_object;
97
98           /* GCC is very clever.  If we wouldn't add some magic it would
99              simply optimize away our nice little variable `reloc' and we
100              would result in a not working binary.  So let's swing the
101              magic ward.  */
102           asm ("" : "=r" (reloc) : "0" (reloc));
103
104 #ifdef PIC
105           if (_dl_profile != NULL)
106             {
107               /* If this here is the shared object which we want to profile
108                  make sure the profile is started.  We can find out whether
109                  this is necessary or not by observing the `_dl_profile_map'
110                  variable.  If was NULL but is not NULL afterwars we must
111                  start the profiling.  */
112               struct link_map *old_profile_map = _dl_profile_map;
113
114               (*reloc) (l, _dl_object_relocation_scope (l), 1, 1);
115
116               if (old_profile_map == NULL && _dl_profile_map != NULL)
117                 /* We must prepare the profiling.  */
118                 _dl_start_profile (_dl_profile_map, _dl_profile_output);
119             }
120           else
121 #endif
122             (*reloc) (l, _dl_object_relocation_scope (l),
123                       (mode & RTLD_BINDING_MASK) == RTLD_LAZY, 0);
124
125           *_dl_global_scope_end = NULL;
126         }
127
128       if (l == new)
129         break;
130       l = l->l_prev;
131     }
132
133   new->l_global = (mode & RTLD_GLOBAL) ? 1 : 0;
134   if (new->l_global)
135     {
136       /* The symbols of the new object and its dependencies are to be
137          introduced into the global scope that will be used to resolve
138          references from other dynamically-loaded objects.  */
139
140       if (_dl_global_scope_alloc == 0)
141         {
142           /* This is the first dynamic object given global scope.  */
143           _dl_global_scope_alloc = 8;
144           _dl_global_scope = malloc (_dl_global_scope_alloc
145                                      * sizeof (struct link_map *));
146           if (! _dl_global_scope)
147             {
148               _dl_global_scope = _dl_default_scope;
149             nomem:
150               _dl_close (new);
151               _dl_signal_error (ENOMEM, file, "cannot extend global scope");
152             }
153           _dl_global_scope[2] = _dl_default_scope[2];
154           _dl_global_scope[3] = new;
155           _dl_global_scope[4] = NULL;
156           _dl_global_scope[5] = NULL;
157           _dl_global_scope_end = &_dl_global_scope [4];
158         }
159       else
160         {
161           if (_dl_global_scope_alloc <
162               (size_t) (_dl_global_scope_end - _dl_global_scope + 2))
163             {
164               /* Must extend the list.  */
165               struct link_map **new = realloc (_dl_global_scope,
166                                                _dl_global_scope_alloc * 2
167                                                * sizeof (struct link_map *));
168               if (! new)
169                 goto nomem;
170               _dl_global_scope_end = new + (_dl_global_scope_end -
171                                             _dl_global_scope);
172               _dl_global_scope = new;
173               _dl_global_scope_alloc *= 2;
174             }
175
176           /* Append the new object and re-terminate the list.  */
177           *_dl_global_scope_end++ = new;
178           /* We keep the list double-terminated so the last element
179              can be filled in for symbol lookups.  */
180           _dl_global_scope_end[0] = NULL;
181           _dl_global_scope_end[1] = NULL;
182         }
183     }
184
185
186   /* Notify the debugger we have added some objects.  We need to call
187      _dl_debug_initialize in a static program in case dynamic linking has
188      not been used before.  */
189   r = _dl_debug_initialize (0);
190   r->r_state = RT_ADD;
191   _dl_debug_state ();
192
193   /* Run the initializer functions of new objects.  */
194   while (init = _dl_init_next (new))
195     (*(void (*) (int, char **, char **)) init) (__libc_argc, __libc_argv,
196                                                 __environ);
197
198   if (_dl_sysdep_start == NULL)
199     /* We must be the static _dl_open in libc.a.  A static program that
200        has loaded a dynamic object now has competition.  */
201     __libc_multiple_libcs = 1;
202
203   /* Release the lock.  */
204   __libc_lock_unlock (_dl_load_lock);
205
206   return new;
207 }