Update
[glibc.git] / elf / dynamic-link.h
blob63adfcb8024a83fa4609bb6c81798e478ee234f6
1 /* Inline functions for dynamic linking.
2 Copyright (C) 1995-2002, 2003 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
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.
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 Lesser General Public License for more details.
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. */
20 #include <elf.h>
21 #include <assert.h>
23 #ifdef RESOLVE
24 auto void __attribute__((always_inline))
25 elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
26 const ElfW(Sym) *sym, const struct r_found_version *version,
27 ElfW(Addr) *const reloc_addr);
28 auto void __attribute__((always_inline))
29 elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
30 const ElfW(Sym) *sym, const struct r_found_version *version,
31 ElfW(Addr) *const reloc_addr);
32 auto void __attribute__((always_inline))
33 elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
34 ElfW(Addr) *const reloc_addr);
35 auto void __attribute__((always_inline))
36 elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
37 ElfW(Addr) *const reloc_addr);
38 # if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL
39 auto void __attribute__((always_inline))
40 elf_machine_lazy_rel (struct link_map *map,
41 ElfW(Addr) l_addr, const ElfW(Rel) *reloc);
42 # else
43 auto void __attribute__((always_inline))
44 elf_machine_lazy_rel (struct link_map *map,
45 ElfW(Addr) l_addr, const ElfW(Rela) *reloc);
46 # endif
47 #endif
49 #include <dl-machine.h>
51 #ifndef VERSYMIDX
52 # define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
53 #endif
56 /* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
58 static inline void __attribute__ ((unused, always_inline))
59 elf_get_dynamic_info (struct link_map *l)
61 ElfW(Dyn) *dyn = l->l_ld;
62 ElfW(Dyn) **info;
64 #ifndef RTLD_BOOTSTRAP
65 if (dyn == NULL)
66 return;
67 #endif
69 info = l->l_info;
71 while (dyn->d_tag != DT_NULL)
73 if (dyn->d_tag < DT_NUM)
74 info[dyn->d_tag] = dyn;
75 else if (dyn->d_tag >= DT_LOPROC &&
76 dyn->d_tag < DT_LOPROC + DT_THISPROCNUM)
77 info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn;
78 else if ((Elf32_Word) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM)
79 info[VERSYMIDX (dyn->d_tag)] = dyn;
80 else if ((Elf32_Word) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)
81 info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
82 + DT_VERSIONTAGNUM] = dyn;
83 else if ((Elf32_Word) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
84 info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
85 + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn;
86 else if ((Elf32_Word) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
87 info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
88 + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn;
89 ++dyn;
91 #ifndef DL_RO_DYN_SECTION
92 /* Don't adjust .dynamic unnecessarily. */
93 if (l->l_addr != 0)
95 ElfW(Addr) l_addr = l->l_addr;
97 if (info[DT_HASH] != NULL)
98 info[DT_HASH]->d_un.d_ptr += l_addr;
99 if (info[DT_PLTGOT] != NULL)
100 info[DT_PLTGOT]->d_un.d_ptr += l_addr;
101 if (info[DT_STRTAB] != NULL)
102 info[DT_STRTAB]->d_un.d_ptr += l_addr;
103 if (info[DT_SYMTAB] != NULL)
104 info[DT_SYMTAB]->d_un.d_ptr += l_addr;
105 # if ! ELF_MACHINE_NO_RELA
106 if (info[DT_RELA] != NULL)
107 info[DT_RELA]->d_un.d_ptr += l_addr;
108 # endif
109 # if ! ELF_MACHINE_NO_REL
110 if (info[DT_REL] != NULL)
111 info[DT_REL]->d_un.d_ptr += l_addr;
112 # endif
113 if (info[DT_JMPREL] != NULL)
114 info[DT_JMPREL]->d_un.d_ptr += l_addr;
115 if (info[VERSYMIDX (DT_VERSYM)] != NULL)
116 info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr;
118 #endif
119 if (info[DT_PLTREL] != NULL)
121 #if ELF_MACHINE_NO_RELA
122 assert (info[DT_PLTREL]->d_un.d_val == DT_REL);
123 #elif ELF_MACHINE_NO_REL
124 assert (info[DT_PLTREL]->d_un.d_val == DT_RELA);
125 #else
126 assert (info[DT_PLTREL]->d_un.d_val == DT_REL
127 || info[DT_PLTREL]->d_un.d_val == DT_RELA);
128 #endif
130 #if ! ELF_MACHINE_NO_RELA
131 if (info[DT_RELA] != NULL)
132 assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
133 # endif
134 # if ! ELF_MACHINE_NO_REL
135 if (info[DT_REL] != NULL)
136 assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
137 #endif
138 if (info[DT_FLAGS] != NULL)
140 /* Flags are used. Translate to the old form where available.
141 Since these l_info entries are only tested for NULL pointers it
142 is ok if they point to the DT_FLAGS entry. */
143 l->l_flags = info[DT_FLAGS]->d_un.d_val;
144 #ifdef RTLD_BOOTSTRAP
145 /* These three flags must not be set for ld.so. */
146 assert ((l->l_flags & (DF_SYMBOLIC | DF_TEXTREL | DF_BIND_NOW)) == 0);
147 #else
148 if (l->l_flags & DF_SYMBOLIC)
149 info[DT_SYMBOLIC] = info[DT_FLAGS];
150 if (l->l_flags & DF_TEXTREL)
151 info[DT_TEXTREL] = info[DT_FLAGS];
152 if (l->l_flags & DF_BIND_NOW)
153 info[DT_BIND_NOW] = info[DT_FLAGS];
154 #endif
156 if (info[VERSYMIDX (DT_FLAGS_1)] != NULL)
157 l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val;
158 #ifdef RTLD_BOOTSTRAP
159 /* The dynamic linker should have none of these set. */
160 assert (info[DT_RUNPATH] == NULL);
161 assert (info[DT_RPATH] == NULL);
162 #else
163 if (info[DT_RUNPATH] != NULL)
164 /* If both RUNPATH and RPATH are given, the latter is ignored. */
165 info[DT_RPATH] = NULL;
166 #endif
169 #ifdef RESOLVE
171 # ifdef RTLD_BOOTSTRAP
172 # define ELF_DURING_STARTUP (1)
173 # else
174 # define ELF_DURING_STARTUP (0)
175 # endif
177 /* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
178 These functions are almost identical, so we use cpp magic to avoid
179 duplicating their code. It cannot be done in a more general function
180 because we must be able to completely inline. */
182 /* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
183 range. Note that according to the ELF spec, this is completely legal!
184 But conditionally define things so that on machines we know this will
185 not happen we do something more optimal. */
187 # ifdef ELF_MACHINE_PLTREL_OVERLAP
188 # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
189 do { \
190 struct { ElfW(Addr) start, size; int lazy; } ranges[3]; \
191 int ranges_index; \
193 ranges[0].lazy = ranges[2].lazy = 0; \
194 ranges[1].lazy = 1; \
195 ranges[0].size = ranges[1].size = ranges[2].size = 0; \
197 if ((map)->l_info[DT_##RELOC]) \
199 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
200 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
203 if ((do_lazy) \
204 && (map)->l_info[DT_PLTREL] \
205 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
207 ranges[1].start = D_PTR ((map), l_info[DT_JMPREL]); \
208 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
209 ranges[2].start = ranges[1].start + ranges[1].size; \
210 ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start; \
211 ranges[0].size = ranges[1].start - ranges[0].start; \
214 for (ranges_index = 0; ranges_index < 3; ++ranges_index) \
215 elf_dynamic_do_##reloc ((map), \
216 ranges[ranges_index].start, \
217 ranges[ranges_index].size, \
218 ranges[ranges_index].lazy); \
219 } while (0)
220 # else
221 # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
222 do { \
223 struct { ElfW(Addr) start, size; int lazy; } ranges[2]; \
224 ranges[0].lazy = 0; \
225 ranges[0].size = ranges[1].size = 0; \
226 ranges[0].start = 0; \
228 if ((map)->l_info[DT_##RELOC]) \
230 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
231 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
233 if ((map)->l_info[DT_PLTREL] \
234 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
236 ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
238 if (! ELF_DURING_STARTUP \
239 && ((do_lazy) \
240 /* This test does not only detect whether the relocation \
241 sections are in the right order, it also checks whether \
242 there is a DT_REL/DT_RELA section. */ \
243 || ranges[0].start + ranges[0].size != start)) \
245 ranges[1].start = start; \
246 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
247 ranges[1].lazy = (do_lazy); \
249 else \
251 /* Combine processing the sections. */ \
252 assert (ranges[0].start + ranges[0].size == start); \
253 ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
257 if (ELF_DURING_STARTUP) \
258 elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, 0); \
259 else \
261 int ranges_index; \
262 for (ranges_index = 0; ranges_index < 2; ++ranges_index) \
263 elf_dynamic_do_##reloc ((map), \
264 ranges[ranges_index].start, \
265 ranges[ranges_index].size, \
266 ranges[ranges_index].lazy); \
268 } while (0)
269 # endif
271 # if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
272 # define _ELF_CHECK_REL 0
273 # else
274 # define _ELF_CHECK_REL 1
275 # endif
277 # if ! ELF_MACHINE_NO_REL
278 # include "do-rel.h"
279 # define ELF_DYNAMIC_DO_REL(map, lazy) \
280 _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, _ELF_CHECK_REL)
281 # else
282 # define ELF_DYNAMIC_DO_REL(map, lazy) /* Nothing to do. */
283 # endif
285 # if ! ELF_MACHINE_NO_RELA
286 # define DO_RELA
287 # include "do-rel.h"
288 # define ELF_DYNAMIC_DO_RELA(map, lazy) \
289 _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, _ELF_CHECK_REL)
290 # else
291 # define ELF_DYNAMIC_DO_RELA(map, lazy) /* Nothing to do. */
292 # endif
294 /* This can't just be an inline function because GCC is too dumb
295 to inline functions containing inlines themselves. */
296 # define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \
297 do { \
298 int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \
299 (consider_profile)); \
300 ELF_DYNAMIC_DO_REL ((map), edr_lazy); \
301 ELF_DYNAMIC_DO_RELA ((map), edr_lazy); \
302 } while (0)
304 #endif