]>
Commit | Line | Data |
---|---|---|
266180eb | 1 | /* Load a shared object at runtime, relocate it, and run its initializer. |
c84142e8 | 2 | Copyright (C) 1996, 1997 Free Software Foundation, Inc. |
afd4eb37 UD |
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. */ | |
266180eb RM |
19 | |
20 | #include <link.h> | |
21 | #include <dlfcn.h> | |
ba79d61b RM |
22 | #include <stdlib.h> |
23 | #include <errno.h> | |
24 | ||
39778c6c | 25 | |
11336c16 UD |
26 | extern ElfW(Addr) _dl_sysdep_start (void **start_argptr, |
27 | void (*dl_main) (const ElfW(Phdr) *phdr, | |
28 | ElfW(Word) phnum, | |
29 | ElfW(Addr) *user_entry)); | |
30 | weak_extern (_dl_sysdep_start) | |
39778c6c UD |
31 | |
32 | extern int __libc_multiple_libcs; /* Defined in init-first.c. */ | |
33 | ||
dcf0671d UD |
34 | extern int __libc_argc; |
35 | extern char **__libc_argv; | |
dcf0671d | 36 | |
57ba7bb4 | 37 | extern char **__environ; |
dcf0671d | 38 | |
ba79d61b | 39 | size_t _dl_global_scope_alloc; |
266180eb RM |
40 | |
41 | struct link_map * | |
a23db8e4 | 42 | _dl_open (const char *file, int mode) |
266180eb RM |
43 | { |
44 | struct link_map *new, *l; | |
45 | ElfW(Addr) init; | |
4d6acc61 | 46 | struct r_debug *r; |
ba79d61b | 47 | |
266180eb | 48 | /* Load the named object. */ |
46ec036d | 49 | new = _dl_map_object (NULL, file, lt_loaded, 0); |
ba79d61b RM |
50 | if (new->l_searchlist) |
51 | /* It was already open. */ | |
52 | return new; | |
266180eb RM |
53 | |
54 | /* Load that object's dependencies. */ | |
46ec036d | 55 | _dl_map_object_deps (new, NULL, 0, 0); |
266180eb | 56 | |
c84142e8 UD |
57 | /* So far, so good. Now check the versions. */ |
58 | (void) _dl_check_map_versions (new, 0); | |
ba79d61b RM |
59 | |
60 | /* Relocate the objects loaded. We do this in reverse order so that copy | |
61 | relocs of earlier objects overwrite the data written by later objects. */ | |
62 | ||
63 | l = new; | |
64 | while (l->l_next) | |
65 | l = l->l_next; | |
4d6acc61 | 66 | while (1) |
ba79d61b RM |
67 | { |
68 | if (! l->l_relocated) | |
69 | { | |
c928de79 RM |
70 | /* We use an indirect call call for _dl_relocate_object because |
71 | we must avoid using the PLT in the call. If our PLT entry for | |
72 | _dl_relocate_object hasn't been used yet, then the dynamic | |
73 | linker fixup routine will clobber _dl_global_scope during its | |
74 | work. We must be sure that nothing will require a PLT fixup | |
75 | between when _dl_object_relocation_scope returns and when we | |
76 | enter the dynamic linker's code (_dl_relocate_object). */ | |
77 | __typeof (_dl_relocate_object) *reloc = &_dl_relocate_object; | |
78 | (*reloc) (l, _dl_object_relocation_scope (l), | |
79 | (mode & RTLD_BINDING_MASK) == RTLD_LAZY); | |
ba79d61b RM |
80 | *_dl_global_scope_end = NULL; |
81 | } | |
82 | ||
4d6acc61 RM |
83 | if (l == new) |
84 | break; | |
ba79d61b | 85 | l = l->l_prev; |
4d6acc61 | 86 | } |
ba79d61b RM |
87 | |
88 | new->l_global = (mode & RTLD_GLOBAL); | |
89 | if (new->l_global) | |
90 | { | |
91 | /* The symbols of the new object and its dependencies are to be | |
92 | introduced into the global scope that will be used to resolve | |
93 | references from other dynamically-loaded objects. */ | |
94 | ||
95 | if (_dl_global_scope_alloc == 0) | |
96 | { | |
97 | /* This is the first dynamic object given global scope. */ | |
98 | _dl_global_scope_alloc = 8; | |
99 | _dl_global_scope = malloc (8 * sizeof (struct link_map *)); | |
100 | if (! _dl_global_scope) | |
101 | { | |
102 | _dl_global_scope = _dl_default_scope; | |
103 | nomem: | |
104 | _dl_close (new); | |
105 | _dl_signal_error (ENOMEM, file, "cannot extend global scope"); | |
106 | } | |
107 | _dl_global_scope[2] = _dl_default_scope[2]; | |
108 | _dl_global_scope[3] = new; | |
109 | _dl_global_scope[4] = NULL; | |
110 | _dl_global_scope[5] = NULL; | |
111 | } | |
112 | else | |
113 | { | |
114 | if (_dl_global_scope_alloc < | |
a5113b14 | 115 | (size_t) (_dl_global_scope_end - _dl_global_scope + 2)) |
ba79d61b RM |
116 | { |
117 | /* Must extend the list. */ | |
118 | struct link_map **new = realloc (_dl_global_scope, | |
119 | _dl_global_scope_alloc * 2); | |
120 | if (! new) | |
121 | goto nomem; | |
122 | _dl_global_scope_end = new + (_dl_global_scope_end - | |
123 | _dl_global_scope); | |
124 | _dl_global_scope = new; | |
125 | _dl_global_scope_alloc *= 2; | |
126 | } | |
127 | ||
128 | /* Append the new object and re-terminate the list. */ | |
129 | *_dl_global_scope_end++ = new; | |
130 | /* We keep the list double-terminated so the last element | |
131 | can be filled in for symbol lookups. */ | |
132 | _dl_global_scope_end[0] = NULL; | |
133 | _dl_global_scope_end[1] = NULL; | |
134 | } | |
135 | } | |
266180eb | 136 | |
4d6acc61 RM |
137 | |
138 | /* Notify the debugger we have added some objects. We need to call | |
139 | _dl_debug_initialize in a static program in case dynamic linking has | |
140 | not been used before. */ | |
141 | r = _dl_debug_initialize (0); | |
142 | r->r_state = RT_ADD; | |
143 | _dl_debug_state (); | |
144 | ||
266180eb RM |
145 | /* Run the initializer functions of new objects. */ |
146 | while (init = _dl_init_next (new)) | |
dcf0671d | 147 | (*(void (*) (int, char **, char **)) init) (__libc_argc, __libc_argv, |
57ba7bb4 | 148 | __environ); |
266180eb | 149 | |
11336c16 | 150 | if (_dl_sysdep_start == NULL) |
cccda09f UD |
151 | /* We must be the static _dl_open in libc.a. A static program that |
152 | has loaded a dynamic object now has competition. */ | |
39778c6c UD |
153 | __libc_multiple_libcs = 1; |
154 | ||
266180eb RM |
155 | return new; |
156 | } |