]>
Commit | Line | Data |
---|---|---|
38334018 | 1 | /* On-demand PLT fixup for shared objects. |
ea7eb7e3 | 2 | Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc. |
afd4eb37 | 3 | This file is part of the GNU C Library. |
d66e34cd | 4 | |
afd4eb37 UD |
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. | |
d66e34cd | 9 | |
afd4eb37 UD |
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. | |
d66e34cd | 14 | |
afd4eb37 UD |
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. */ | |
d66e34cd | 19 | |
3db52d94 | 20 | #include <unistd.h> |
a853022c | 21 | #include <elf/ldsodefs.h> |
d66e34cd | 22 | |
ba79d61b RM |
23 | |
24 | /* The global scope we will use for symbol lookups. | |
25 | This will be modified by _dl_open if RTLD_GLOBAL is used. */ | |
26 | struct link_map **_dl_global_scope = _dl_default_scope; | |
27 | struct link_map **_dl_global_scope_end = &_dl_default_scope[3]; | |
28 | ||
29 | ||
30 | /* Hack _dl_global_scope[0] and [1] as necessary, and return a pointer into | |
31 | _dl_global_scope that should be passed to _dl_lookup_symbol for symbol | |
32 | references made in the object L's relocations. */ | |
33 | inline struct link_map ** | |
d0fc4041 | 34 | internal_function |
ba79d61b RM |
35 | _dl_object_relocation_scope (struct link_map *l) |
36 | { | |
37 | if (l->l_info[DT_SYMBOLIC]) | |
38 | { | |
39 | /* This object's global references are to be resolved first | |
40 | in the object itself, and only secondarily in more global | |
41 | scopes. */ | |
42 | ||
43 | if (! l->l_searchlist) | |
44 | /* We must construct the searchlist for this object. */ | |
46ec036d | 45 | _dl_map_object_deps (l, NULL, 0, 0); |
ba79d61b RM |
46 | |
47 | /* The primary scope is this object itself and its | |
48 | dependencies. */ | |
49 | _dl_global_scope[0] = l; | |
50 | ||
51 | /* Secondary is the dependency tree that reached L; the object | |
52 | requested directly by the user is at the root of that tree. */ | |
53 | while (l->l_loader) | |
54 | l = l->l_loader; | |
55 | _dl_global_scope[1] = l; | |
56 | ||
57 | /* Finally, the global scope follows. */ | |
58 | ||
59 | return _dl_global_scope; | |
60 | } | |
61 | else | |
62 | { | |
63 | /* Use first the global scope, and then the scope of the root of the | |
64 | dependency tree that first caused this object to be loaded. */ | |
65 | while (l->l_loader) | |
66 | l = l->l_loader; | |
67 | *_dl_global_scope_end = l; | |
68 | return &_dl_global_scope[2]; | |
69 | } | |
70 | } | |
71 | \f | |
f51d1dfd RM |
72 | #include "dynamic-link.h" |
73 | ||
a2b08ee5 UD |
74 | #if !defined ELF_MACHINE_NO_RELA || ELF_MACHINE_NO_REL |
75 | # define PLTREL ElfW(Rela) | |
38334018 | 76 | #else |
a2b08ee5 | 77 | # define PLTREL ElfW(Rel) |
38334018 | 78 | #endif |
38334018 | 79 | |
c84142e8 UD |
80 | #ifndef VERSYMIDX |
81 | # define VERSYMIDX(sym) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (sym)) | |
82 | #endif | |
83 | ||
38334018 RM |
84 | |
85 | /* This function is called through a special trampoline from the PLT the | |
86 | first time each PLT entry is called. We must perform the relocation | |
87 | specified in the PLT of the given shared object, and return the resolved | |
88 | function address to the trampoline, which will restart the original call | |
89 | to that address. Future calls will bounce directly from the PLT to the | |
90 | function. */ | |
91 | ||
a2b08ee5 | 92 | static ElfW(Addr) __attribute__ ((unused)) |
01f3e03b RM |
93 | fixup ( |
94 | #ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS | |
95 | ELF_MACHINE_RUNTIME_FIXUP_ARGS, | |
96 | #endif | |
266180eb | 97 | struct link_map *l, ElfW(Word) reloc_offset) |
d66e34cd | 98 | { |
266180eb RM |
99 | const ElfW(Sym) *const symtab |
100 | = (const ElfW(Sym) *) (l->l_addr + l->l_info[DT_SYMTAB]->d_un.d_ptr); | |
a1a9d215 RM |
101 | const char *strtab = |
102 | (const char *) (l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr); | |
d66e34cd | 103 | |
38334018 | 104 | const PLTREL *const reloc |
a1a9d215 RM |
105 | = (const void *) (l->l_addr + l->l_info[DT_JMPREL]->d_un.d_ptr + |
106 | reloc_offset); | |
a2b08ee5 UD |
107 | const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; |
108 | void *const rel_addr = (void *)(l->l_addr + reloc->r_offset); | |
109 | ElfW(Addr) value; | |
d66e34cd | 110 | |
ba79d61b RM |
111 | /* Set up the scope to find symbols referenced by this object. */ |
112 | struct link_map **scope = _dl_object_relocation_scope (l); | |
113 | ||
a2b08ee5 UD |
114 | /* Sanity check that we're really looking at a PLT relocation. */ |
115 | assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT); | |
f51d1dfd | 116 | |
a2b08ee5 UD |
117 | /* Look up the target symbol. */ |
118 | switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) | |
119 | { | |
120 | default: | |
c84142e8 | 121 | { |
a2b08ee5 UD |
122 | const ElfW(Half) *vernum = (const ElfW(Half) *) |
123 | (l->l_addr + l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr); | |
124 | ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)]; | |
125 | const struct r_found_version *version = &l->l_versions[ndx]; | |
126 | ||
127 | if (version->hash != 0) | |
128 | { | |
129 | value = _dl_lookup_versioned_symbol(strtab + sym->st_name, | |
130 | &sym, scope, l->l_name, | |
4194bc66 | 131 | version, DL_LOOKUP_NOPLT); |
a2b08ee5 UD |
132 | break; |
133 | } | |
c84142e8 | 134 | } |
a2b08ee5 UD |
135 | case 0: |
136 | value = _dl_lookup_symbol (strtab + sym->st_name, &sym, scope, | |
4194bc66 | 137 | l->l_name, DL_LOOKUP_NOPLT); |
a2b08ee5 UD |
138 | } |
139 | ||
140 | /* Currently value contains the base load address of the object | |
141 | that defines sym. Now add in the symbol offset. */ | |
142 | value = (sym ? value + sym->st_value : 0); | |
143 | ||
dfd2257a UD |
144 | /* And now perhaps the relocation addend. */ |
145 | value = elf_machine_plt_value (l, reloc, value); | |
650425ce | 146 | |
a2b08ee5 UD |
147 | /* Finally, fix up the plt itself. */ |
148 | elf_machine_fixup_plt (l, reloc, rel_addr, value); | |
d66e34cd | 149 | |
ba79d61b RM |
150 | *_dl_global_scope_end = NULL; |
151 | ||
a2b08ee5 | 152 | return value; |
38334018 | 153 | } |
d66e34cd | 154 | |
d66e34cd | 155 | |
3996f34b | 156 | #ifndef PROF |
8f2ece69 | 157 | |
a2b08ee5 | 158 | static ElfW(Addr) __attribute__ ((unused)) |
3996f34b UD |
159 | profile_fixup ( |
160 | #ifdef ELF_MACHINE_RUNTIME_FIXUP_ARGS | |
161 | ELF_MACHINE_RUNTIME_FIXUP_ARGS, | |
162 | #endif | |
163 | struct link_map *l, ElfW(Word) reloc_offset, ElfW(Addr) retaddr) | |
164 | { | |
165 | void (*mcount_fct) (ElfW(Addr), ElfW(Addr)) = _dl_mcount; | |
ea7eb7e3 | 166 | ElfW(Addr) *resultp; |
a2b08ee5 | 167 | ElfW(Addr) value; |
3996f34b | 168 | |
ea7eb7e3 UD |
169 | /* This is the address in the array where we store the result of previous |
170 | relocations. */ | |
171 | resultp = &l->l_reloc_result[reloc_offset / sizeof (PLTREL)]; | |
3996f34b | 172 | |
ea7eb7e3 UD |
173 | value = *resultp; |
174 | if (value == 0) | |
a2b08ee5 | 175 | { |
ea7eb7e3 UD |
176 | /* This is the first time we have to relocate this object. */ |
177 | const ElfW(Sym) *const symtab | |
178 | = (const ElfW(Sym) *) (l->l_addr + l->l_info[DT_SYMTAB]->d_un.d_ptr); | |
179 | const char *strtab = | |
180 | (const char *) (l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr); | |
181 | ||
182 | const PLTREL *const reloc | |
183 | = (const void *) (l->l_addr + l->l_info[DT_JMPREL]->d_un.d_ptr + | |
184 | reloc_offset); | |
185 | const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)]; | |
186 | ||
187 | /* Set up the scope to find symbols referenced by this object. */ | |
188 | struct link_map **scope = _dl_object_relocation_scope (l); | |
189 | ||
190 | /* Sanity check that we're really looking at a PLT relocation. */ | |
191 | assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT); | |
192 | ||
193 | /* Look up the target symbol. */ | |
194 | switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL) | |
195 | { | |
196 | default: | |
a2b08ee5 | 197 | { |
ea7eb7e3 UD |
198 | const ElfW(Half) *vernum = (const ElfW(Half) *) |
199 | (l->l_addr + l->l_info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr); | |
200 | ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)]; | |
201 | const struct r_found_version *version = &l->l_versions[ndx]; | |
202 | ||
203 | if (version->hash != 0) | |
204 | { | |
205 | value = _dl_lookup_versioned_symbol(strtab + sym->st_name, | |
206 | &sym, scope, l->l_name, | |
207 | version, | |
4194bc66 | 208 | DL_LOOKUP_NOPLT); |
ea7eb7e3 UD |
209 | break; |
210 | } | |
a2b08ee5 | 211 | } |
ea7eb7e3 UD |
212 | case 0: |
213 | value = _dl_lookup_symbol (strtab + sym->st_name, &sym, scope, | |
4194bc66 | 214 | l->l_name, DL_LOOKUP_NOPLT); |
ea7eb7e3 | 215 | } |
a2b08ee5 | 216 | |
ea7eb7e3 UD |
217 | /* Currently value contains the base load address of the object |
218 | that defines sym. Now add in the symbol offset. */ | |
219 | value = (sym ? value + sym->st_value : 0); | |
650425ce | 220 | |
ea7eb7e3 UD |
221 | /* And now perhaps the relocation addend. */ |
222 | value = elf_machine_plt_value (l, reloc, value); | |
223 | ||
224 | *_dl_global_scope_end = NULL; | |
225 | ||
226 | /* Store the result for later runs. */ | |
227 | *resultp = value; | |
228 | } | |
3996f34b | 229 | |
a2b08ee5 | 230 | (*mcount_fct) (retaddr, value); |
3996f34b | 231 | |
a2b08ee5 | 232 | return value; |
3996f34b | 233 | } |
a2b08ee5 UD |
234 | |
235 | #endif /* PROF */ | |
3996f34b UD |
236 | |
237 | ||
38334018 RM |
238 | /* This macro is defined in dl-machine.h to define the entry point called |
239 | by the PLT. The `fixup' function above does the real work, but a little | |
240 | more twiddling is needed to get the stack right and jump to the address | |
241 | finally resolved. */ | |
d66e34cd | 242 | |
38334018 | 243 | ELF_MACHINE_RUNTIME_TRAMPOLINE |