]>
Commit | Line | Data |
---|---|---|
d66e34cd | 1 | /* Inline functions for dynamic linking. |
d6b5d570 | 2 | Copyright (C) 1995,96,97,98,99,2000,2001,2002 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 | |
41bdb6e2 AJ |
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. | |
afd4eb37 UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
afd4eb37 | 14 | |
41bdb6e2 AJ |
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. */ | |
d66e34cd RM |
19 | |
20 | #include <elf.h> | |
d66e34cd | 21 | #include <dl-machine.h> |
d66e34cd RM |
22 | #include <assert.h> |
23 | ||
f420344c | 24 | #ifndef VERSYMIDX |
b0982c4a | 25 | # define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym)) |
f420344c UD |
26 | #endif |
27 | ||
421f82e5 | 28 | |
d66e34cd RM |
29 | /* Read the dynamic section at DYN and fill in INFO with indices DT_*. */ |
30 | ||
e75154a6 | 31 | static inline void __attribute__ ((unused)) |
fcf70d41 | 32 | elf_get_dynamic_info (struct link_map *l) |
d66e34cd | 33 | { |
fcf70d41 | 34 | ElfW(Dyn) *dyn = l->l_ld; |
fcf70d41 UD |
35 | ElfW(Dyn) **info; |
36 | ||
56c57442 UD |
37 | #ifndef RTLD_BOOTSTRAP |
38 | if (dyn == NULL) | |
b122c703 | 39 | return; |
56c57442 | 40 | #endif |
b122c703 | 41 | |
fcf70d41 UD |
42 | info = l->l_info; |
43 | ||
d66e34cd RM |
44 | while (dyn->d_tag != DT_NULL) |
45 | { | |
a2e1b046 RM |
46 | if (dyn->d_tag < DT_NUM) |
47 | info[dyn->d_tag] = dyn; | |
48 | else if (dyn->d_tag >= DT_LOPROC && | |
b0982c4a | 49 | dyn->d_tag < DT_LOPROC + DT_THISPROCNUM) |
a2e1b046 | 50 | info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn; |
1228ed5c | 51 | else if ((Elf32_Word) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM) |
f420344c | 52 | info[VERSYMIDX (dyn->d_tag)] = dyn; |
df4ef2ab | 53 | else if ((Elf32_Word) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM) |
b0982c4a | 54 | info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM |
1228ed5c | 55 | + DT_VERSIONTAGNUM] = dyn; |
32e6df36 UD |
56 | else if ((Elf32_Word) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM) |
57 | info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM | |
58 | + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn; | |
59 | else if ((Elf32_Word) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM) | |
60 | info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM | |
61 | + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn; | |
a2e1b046 | 62 | else |
38334018 | 63 | assert (! "bad dynamic tag"); |
bd355af0 | 64 | ++dyn; |
d66e34cd | 65 | } |
a42195db | 66 | #ifndef DL_RO_DYN_SECTION |
32e6df36 | 67 | /* Don't adjust .dynamic unnecessarily. */ |
56c57442 | 68 | if (l->l_addr != 0) |
f420344c | 69 | { |
56c57442 UD |
70 | ElfW(Addr) l_addr = l->l_addr; |
71 | ||
32e6df36 UD |
72 | if (info[DT_PLTGOT] != NULL) |
73 | info[DT_PLTGOT]->d_un.d_ptr += l_addr; | |
74 | if (info[DT_STRTAB] != NULL) | |
75 | info[DT_STRTAB]->d_un.d_ptr += l_addr; | |
76 | if (info[DT_SYMTAB] != NULL) | |
77 | info[DT_SYMTAB]->d_un.d_ptr += l_addr; | |
78 | # if ! ELF_MACHINE_NO_RELA | |
79 | if (info[DT_RELA] != NULL) | |
80 | info[DT_RELA]->d_un.d_ptr += l_addr; | |
a42195db UD |
81 | # endif |
82 | # if ! ELF_MACHINE_NO_REL | |
32e6df36 UD |
83 | if (info[DT_REL] != NULL) |
84 | info[DT_REL]->d_un.d_ptr += l_addr; | |
a42195db | 85 | # endif |
32e6df36 UD |
86 | if (info[DT_JMPREL] != NULL) |
87 | info[DT_JMPREL]->d_un.d_ptr += l_addr; | |
88 | if (info[VERSYMIDX (DT_VERSYM)] != NULL) | |
89 | info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr; | |
90 | } | |
f420344c UD |
91 | #endif |
92 | if (info[DT_PLTREL] != NULL) | |
93 | { | |
56c57442 | 94 | #if ELF_MACHINE_NO_RELA |
f420344c | 95 | assert (info[DT_PLTREL]->d_un.d_val == DT_REL); |
56c57442 | 96 | #elif ELF_MACHINE_NO_REL |
f420344c | 97 | assert (info[DT_PLTREL]->d_un.d_val == DT_RELA); |
56c57442 | 98 | #else |
f420344c UD |
99 | assert (info[DT_PLTREL]->d_un.d_val == DT_REL |
100 | || info[DT_PLTREL]->d_un.d_val == DT_RELA); | |
56c57442 | 101 | #endif |
f420344c | 102 | } |
56c57442 | 103 | #if ! ELF_MACHINE_NO_RELA |
32e6df36 UD |
104 | if (info[DT_RELA] != NULL) |
105 | assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela))); | |
106 | # endif | |
107 | # if ! ELF_MACHINE_NO_REL | |
108 | if (info[DT_REL] != NULL) | |
109 | assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel))); | |
56c57442 UD |
110 | #endif |
111 | #ifdef RTLD_BOOTSTRAP | |
112 | /* None of the flags should be set for the dynamic linker itself. */ | |
113 | assert (info[DT_FLAGS] == NULL); | |
114 | #else | |
06535ae9 UD |
115 | if (info[DT_FLAGS] != NULL) |
116 | { | |
117 | /* Flags are used. Translate to the old form where available. | |
118 | Since these l_info entries are only tested for NULL pointers it | |
119 | is ok if they point to the DT_FLAGS entry. */ | |
120 | ElfW(Word) flags = info[DT_FLAGS]->d_un.d_val; | |
121 | if (flags & DF_SYMBOLIC) | |
122 | info[DT_SYMBOLIC] = info[DT_FLAGS]; | |
123 | if (flags & DF_TEXTREL) | |
124 | info[DT_TEXTREL] = info[DT_FLAGS]; | |
125 | if (flags & DF_BIND_NOW) | |
126 | info[DT_BIND_NOW] = info[DT_FLAGS]; | |
127 | } | |
56c57442 | 128 | #endif |
bf8b3e74 UD |
129 | if (info[VERSYMIDX (DT_FLAGS_1)] != NULL) |
130 | l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val; | |
56c57442 UD |
131 | #ifdef RTLD_BOOTSTRAP |
132 | /* The dynamic linker should have none of these set. */ | |
133 | assert (info[DT_RUNPATH] == NULL); | |
134 | assert (info[DT_RPATH] == NULL); | |
135 | #else | |
fcf70d41 UD |
136 | if (info[DT_RUNPATH] != NULL) |
137 | /* If both RUNPATH and RPATH are given, the latter is ignored. */ | |
138 | info[DT_RPATH] = NULL; | |
56c57442 | 139 | #endif |
d66e34cd RM |
140 | } |
141 | ||
f51d1dfd RM |
142 | #ifdef RESOLVE |
143 | ||
421f82e5 RM |
144 | /* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'. |
145 | These functions are almost identical, so we use cpp magic to avoid | |
146 | duplicating their code. It cannot be done in a more general function | |
147 | because we must be able to completely inline. */ | |
148 | ||
f420344c | 149 | /* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its |
ca34d7a7 UD |
150 | range. Note that according to the ELF spec, this is completely legal! |
151 | But conditionally define things so that on machines we know this will | |
152 | not happen we do something more optimal. */ | |
153 | ||
f420344c UD |
154 | # ifdef ELF_MACHINE_PLTREL_OVERLAP |
155 | # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \ | |
ca34d7a7 | 156 | do { \ |
085320f5 | 157 | struct { ElfW(Addr) start, size; int lazy; } ranges[3]; \ |
052b6a6c UD |
158 | int ranges_index; \ |
159 | \ | |
160 | ranges[0].lazy = ranges[2].lazy = 0; \ | |
161 | ranges[1].lazy = 1; \ | |
162 | ranges[0].size = ranges[1].size = ranges[2].size = 0; \ | |
163 | \ | |
ca34d7a7 UD |
164 | if ((map)->l_info[DT_##RELOC]) \ |
165 | { \ | |
a42195db | 166 | ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \ |
052b6a6c | 167 | ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \ |
ca34d7a7 | 168 | } \ |
ca34d7a7 | 169 | \ |
085320f5 | 170 | if ((do_lazy) \ |
052b6a6c | 171 | && (map)->l_info[DT_PLTREL] \ |
f420344c | 172 | && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \ |
052b6a6c | 173 | { \ |
a42195db | 174 | ranges[1].start = D_PTR ((map), l_info[DT_JMPREL]); \ |
052b6a6c UD |
175 | ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \ |
176 | ranges[2].start = ranges[1].start + ranges[1].size; \ | |
177 | ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start; \ | |
178 | ranges[0].size = ranges[1].start - ranges[0].start; \ | |
ca34d7a7 | 179 | } \ |
052b6a6c UD |
180 | \ |
181 | for (ranges_index = 0; ranges_index < 3; ++ranges_index) \ | |
182 | elf_dynamic_do_##reloc ((map), \ | |
183 | ranges[ranges_index].start, \ | |
184 | ranges[ranges_index].size, \ | |
185 | ranges[ranges_index].lazy); \ | |
ca34d7a7 | 186 | } while (0) |
f420344c UD |
187 | # else |
188 | # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \ | |
ca34d7a7 | 189 | do { \ |
085320f5 | 190 | struct { ElfW(Addr) start, size; int lazy; } ranges[2]; \ |
052b6a6c UD |
191 | int ranges_index; \ |
192 | ranges[0].lazy = 0; \ | |
052b6a6c UD |
193 | ranges[0].size = ranges[1].size = 0; \ |
194 | ranges[0].start = 0; \ | |
195 | \ | |
ca34d7a7 UD |
196 | if ((map)->l_info[DT_##RELOC]) \ |
197 | { \ | |
32e6df36 UD |
198 | ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \ |
199 | ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \ | |
ca34d7a7 | 200 | } \ |
f420344c UD |
201 | if ((map)->l_info[DT_PLTREL] \ |
202 | && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \ | |
ca34d7a7 | 203 | { \ |
a42195db | 204 | ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \ |
052b6a6c | 205 | \ |
085320f5 | 206 | if ((do_lazy) \ |
052b6a6c UD |
207 | /* This test does not only detect whether the relocation \ |
208 | sections are in the right order, it also checks whether \ | |
209 | there is a DT_REL/DT_RELA section. */ \ | |
210 | || ranges[0].start + ranges[0].size != start) \ | |
211 | { \ | |
212 | ranges[1].start = start; \ | |
213 | ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \ | |
085320f5 | 214 | ranges[1].lazy = (do_lazy); \ |
052b6a6c UD |
215 | } \ |
216 | else \ | |
217 | /* Combine processing the sections. */ \ | |
218 | ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \ | |
ca34d7a7 | 219 | } \ |
052b6a6c UD |
220 | \ |
221 | for (ranges_index = 0; ranges_index < 2; ++ranges_index) \ | |
222 | elf_dynamic_do_##reloc ((map), \ | |
223 | ranges[ranges_index].start, \ | |
224 | ranges[ranges_index].size, \ | |
225 | ranges[ranges_index].lazy); \ | |
ca34d7a7 | 226 | } while (0) |
f420344c UD |
227 | # endif |
228 | ||
229 | # if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA | |
230 | # define _ELF_CHECK_REL 0 | |
231 | # else | |
232 | # define _ELF_CHECK_REL 1 | |
233 | # endif | |
234 | ||
235 | # if ! ELF_MACHINE_NO_REL | |
236 | # include "do-rel.h" | |
237 | # define ELF_DYNAMIC_DO_REL(map, lazy) \ | |
238 | _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, _ELF_CHECK_REL) | |
239 | # else | |
240 | # define ELF_DYNAMIC_DO_REL(map, lazy) /* Nothing to do. */ | |
241 | # endif | |
242 | ||
243 | # if ! ELF_MACHINE_NO_RELA | |
244 | # define DO_RELA | |
245 | # include "do-rel.h" | |
246 | # define ELF_DYNAMIC_DO_RELA(map, lazy) \ | |
247 | _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, _ELF_CHECK_REL) | |
248 | # else | |
249 | # define ELF_DYNAMIC_DO_RELA(map, lazy) /* Nothing to do. */ | |
250 | # endif | |
421f82e5 RM |
251 | |
252 | /* This can't just be an inline function because GCC is too dumb | |
253 | to inline functions containing inlines themselves. */ | |
f420344c | 254 | # define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \ |
3996f34b | 255 | do { \ |
c0fb8a56 UD |
256 | int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \ |
257 | (consider_profile)); \ | |
3996f34b UD |
258 | ELF_DYNAMIC_DO_REL ((map), edr_lazy); \ |
259 | ELF_DYNAMIC_DO_RELA ((map), edr_lazy); \ | |
0501d603 | 260 | } while (0) |
f51d1dfd RM |
261 | |
262 | #endif |