]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dynamic-link.h
Use <> for include of kernel-features.h.
[thirdparty/glibc.git] / elf / dynamic-link.h
CommitLineData
d66e34cd 1/* Inline functions for dynamic linking.
31fffa6b 2 Copyright (C) 1995-2005,2006,2008,2011 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 19
c9ff0187
UD
20/* This macro is used as a callback from elf_machine_rel{a,} when a
21 static TLS reloc is about to be performed. Since (in dl-load.c) we
22 permit dynamic loading of objects that might use such relocs, we
23 have to check whether each use is actually doable. If the object
24 whose TLS segment the reference resolves to was allocated space in
25 the static TLS block at startup, then it's ok. Otherwise, we make
26 an attempt to allocate it in surplus space on the fly. If that
27 can't be done, we fall back to the error that DF_STATIC_TLS is
28 intended to produce. */
29#define CHECK_STATIC_TLS(map, sym_map) \
30 do { \
31 if (__builtin_expect ((sym_map)->l_tls_offset == NO_TLS_OFFSET \
32 || ((sym_map)->l_tls_offset \
33 == FORCED_DYNAMIC_TLS_OFFSET), 0)) \
34 _dl_allocate_static_tls (sym_map); \
35 } while (0)
36
37#define TRY_STATIC_TLS(map, sym_map) \
38 (__builtin_expect ((sym_map)->l_tls_offset \
39 != FORCED_DYNAMIC_TLS_OFFSET, 1) \
40 && (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \
41 || _dl_try_allocate_static_tls (sym_map) == 0))
42
43int internal_function _dl_try_allocate_static_tls (struct link_map *map);
44
d66e34cd 45#include <elf.h>
d66e34cd
RM
46#include <assert.h>
47
9dcafc55 48#ifdef RESOLVE_MAP
87d254a7
AO
49/* We pass reloc_addr as a pointer to void, as opposed to a pointer to
50 ElfW(Addr), because not all architectures can assume that the
51 relocated address is properly aligned, whereas the compiler is
52 entitled to assume that a pointer to a type is properly aligned for
53 the type. Even if we cast the pointer back to some other type with
54 less strict alignment requirements, the compiler might still
55 remember that the pointer was originally more aligned, thereby
56 optimizing away alignment tests or using word instructions for
57 copying memory, breaking the very code written to handle the
58 unaligned cases. */
9cfe5381 59# if ! ELF_MACHINE_NO_REL
1b243ca9 60auto inline void __attribute__((always_inline))
567678b6
UD
61elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
62 const ElfW(Sym) *sym, const struct r_found_version *version,
3a62d00d 63 void *const reloc_addr, int skip_ifunc);
1b243ca9 64auto inline void __attribute__((always_inline))
9cfe5381
RM
65elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
66 void *const reloc_addr);
67# endif
68# if ! ELF_MACHINE_NO_RELA
1b243ca9 69auto inline void __attribute__((always_inline))
567678b6
UD
70elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
71 const ElfW(Sym) *sym, const struct r_found_version *version,
3a62d00d 72 void *const reloc_addr, int skip_ifunc);
1b243ca9 73auto inline void __attribute__((always_inline))
567678b6 74elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
87d254a7 75 void *const reloc_addr);
9cfe5381 76# endif
567678b6 77# if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL
1b243ca9 78auto inline void __attribute__((always_inline))
567678b6 79elf_machine_lazy_rel (struct link_map *map,
3a62d00d
AS
80 ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
81 int skip_ifunc);
567678b6 82# else
1b243ca9 83auto inline void __attribute__((always_inline))
567678b6 84elf_machine_lazy_rel (struct link_map *map,
3a62d00d
AS
85 ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
86 int skip_ifunc);
567678b6
UD
87# endif
88#endif
89
90#include <dl-machine.h>
91
f420344c 92#ifndef VERSYMIDX
b0982c4a 93# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
f420344c
UD
94#endif
95
421f82e5 96
d66e34cd 97/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
9dcafc55 98#ifndef RESOLVE_MAP
7090d3ca
AJ
99static
100#else
101auto
102#endif
103inline void __attribute__ ((unused, always_inline))
479aa8ec 104elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
d66e34cd 105{
fcf70d41 106 ElfW(Dyn) *dyn = l->l_ld;
fcf70d41 107 ElfW(Dyn) **info;
db07e962
AS
108#if __ELF_NATIVE_CLASS == 32
109 typedef Elf32_Word d_tag_utype;
110#elif __ELF_NATIVE_CLASS == 64
111 typedef Elf64_Xword d_tag_utype;
112#endif
fcf70d41 113
56c57442
UD
114#ifndef RTLD_BOOTSTRAP
115 if (dyn == NULL)
b122c703 116 return;
56c57442 117#endif
b122c703 118
fcf70d41
UD
119 info = l->l_info;
120
d66e34cd
RM
121 while (dyn->d_tag != DT_NULL)
122 {
db07e962 123 if ((d_tag_utype) dyn->d_tag < DT_NUM)
a2e1b046
RM
124 info[dyn->d_tag] = dyn;
125 else if (dyn->d_tag >= DT_LOPROC &&
b0982c4a 126 dyn->d_tag < DT_LOPROC + DT_THISPROCNUM)
a2e1b046 127 info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn;
db07e962 128 else if ((d_tag_utype) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM)
f420344c 129 info[VERSYMIDX (dyn->d_tag)] = dyn;
db07e962 130 else if ((d_tag_utype) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)
b0982c4a 131 info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
1228ed5c 132 + DT_VERSIONTAGNUM] = dyn;
db07e962 133 else if ((d_tag_utype) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
32e6df36
UD
134 info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
135 + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn;
db07e962 136 else if ((d_tag_utype) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
32e6df36
UD
137 info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
138 + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn;
bd355af0 139 ++dyn;
d66e34cd 140 }
479aa8ec
UD
141
142#define DL_RO_DYN_TEMP_CNT 8
143
a42195db 144#ifndef DL_RO_DYN_SECTION
32e6df36 145 /* Don't adjust .dynamic unnecessarily. */
56c57442 146 if (l->l_addr != 0)
f420344c 147 {
56c57442 148 ElfW(Addr) l_addr = l->l_addr;
479aa8ec
UD
149 int cnt = 0;
150
151# define ADJUST_DYN_INFO(tag) \
152 do \
153 if (info[tag] != NULL) \
154 { \
155 if (temp) \
156 { \
157 temp[cnt].d_tag = info[tag]->d_tag; \
158 temp[cnt].d_un.d_ptr = info[tag]->d_un.d_ptr + l_addr; \
159 info[tag] = temp + cnt++; \
160 } \
161 else \
162 info[tag]->d_un.d_ptr += l_addr; \
163 } \
164 while (0)
56c57442 165
479aa8ec
UD
166 ADJUST_DYN_INFO (DT_HASH);
167 ADJUST_DYN_INFO (DT_PLTGOT);
168 ADJUST_DYN_INFO (DT_STRTAB);
169 ADJUST_DYN_INFO (DT_SYMTAB);
32e6df36 170# if ! ELF_MACHINE_NO_RELA
479aa8ec 171 ADJUST_DYN_INFO (DT_RELA);
a42195db
UD
172# endif
173# if ! ELF_MACHINE_NO_REL
479aa8ec 174 ADJUST_DYN_INFO (DT_REL);
a42195db 175# endif
479aa8ec
UD
176 ADJUST_DYN_INFO (DT_JMPREL);
177 ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
871b9158
UD
178 ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
179 + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM);
479aa8ec
UD
180# undef ADJUST_DYN_INFO
181 assert (cnt <= DL_RO_DYN_TEMP_CNT);
32e6df36 182 }
f420344c
UD
183#endif
184 if (info[DT_PLTREL] != NULL)
185 {
56c57442 186#if ELF_MACHINE_NO_RELA
f420344c 187 assert (info[DT_PLTREL]->d_un.d_val == DT_REL);
56c57442 188#elif ELF_MACHINE_NO_REL
f420344c 189 assert (info[DT_PLTREL]->d_un.d_val == DT_RELA);
56c57442 190#else
f420344c
UD
191 assert (info[DT_PLTREL]->d_un.d_val == DT_REL
192 || info[DT_PLTREL]->d_un.d_val == DT_RELA);
56c57442 193#endif
f420344c 194 }
56c57442 195#if ! ELF_MACHINE_NO_RELA
32e6df36
UD
196 if (info[DT_RELA] != NULL)
197 assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
198# endif
199# if ! ELF_MACHINE_NO_REL
200 if (info[DT_REL] != NULL)
201 assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
56c57442 202#endif
445888be 203#ifdef RTLD_BOOTSTRAP
4df8c11d
UD
204 /* Only the bind now flags are allowed. */
205 assert (info[VERSYMIDX (DT_FLAGS_1)] == NULL
31fffa6b 206 || (info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val & ~DF_1_NOW) == 0);
4df8c11d 207 assert (info[DT_FLAGS] == NULL
31fffa6b 208 || (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0);
445888be 209 /* Flags must not be set for ld.so. */
445888be
UD
210 assert (info[DT_RUNPATH] == NULL);
211 assert (info[DT_RPATH] == NULL);
212#else
06535ae9
UD
213 if (info[DT_FLAGS] != NULL)
214 {
215 /* Flags are used. Translate to the old form where available.
216 Since these l_info entries are only tested for NULL pointers it
217 is ok if they point to the DT_FLAGS entry. */
ec70c011 218 l->l_flags = info[DT_FLAGS]->d_un.d_val;
445888be 219
37beecf7 220 if (l->l_flags & DF_SYMBOLIC)
06535ae9 221 info[DT_SYMBOLIC] = info[DT_FLAGS];
37beecf7 222 if (l->l_flags & DF_TEXTREL)
06535ae9 223 info[DT_TEXTREL] = info[DT_FLAGS];
ec70c011 224 if (l->l_flags & DF_BIND_NOW)
06535ae9 225 info[DT_BIND_NOW] = info[DT_FLAGS];
37beecf7 226 }
bf8b3e74 227 if (info[VERSYMIDX (DT_FLAGS_1)] != NULL)
445888be
UD
228 {
229 l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val;
230
231 if (l->l_flags_1 & DF_1_NOW)
232 info[DT_BIND_NOW] = info[VERSYMIDX (DT_FLAGS_1)];
233 }
fcf70d41
UD
234 if (info[DT_RUNPATH] != NULL)
235 /* If both RUNPATH and RPATH are given, the latter is ignored. */
236 info[DT_RPATH] = NULL;
56c57442 237#endif
d66e34cd
RM
238}
239
9dcafc55 240#ifdef RESOLVE_MAP
f51d1dfd 241
e0f41886
UD
242# ifdef RTLD_BOOTSTRAP
243# define ELF_DURING_STARTUP (1)
244# else
245# define ELF_DURING_STARTUP (0)
246# endif
247
421f82e5
RM
248/* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
249 These functions are almost identical, so we use cpp magic to avoid
250 duplicating their code. It cannot be done in a more general function
251 because we must be able to completely inline. */
252
f420344c 253/* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
ca34d7a7
UD
254 range. Note that according to the ELF spec, this is completely legal!
255 But conditionally define things so that on machines we know this will
256 not happen we do something more optimal. */
257
f420344c 258# ifdef ELF_MACHINE_PLTREL_OVERLAP
3a62d00d 259# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, skip_ifunc, test_rel) \
ca34d7a7 260 do { \
aac13307
UD
261 struct { ElfW(Addr) start, size; \
262 __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
e453f6cd 263 ranges[3]; \
052b6a6c
UD
264 int ranges_index; \
265 \
266 ranges[0].lazy = ranges[2].lazy = 0; \
267 ranges[1].lazy = 1; \
268 ranges[0].size = ranges[1].size = ranges[2].size = 0; \
e453f6cd 269 ranges[0].nrelative = ranges[1].nrelative = ranges[2].nrelative = 0; \
052b6a6c 270 \
ca34d7a7
UD
271 if ((map)->l_info[DT_##RELOC]) \
272 { \
a42195db 273 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
052b6a6c 274 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
e453f6cd
UD
275 if (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)] != NULL) \
276 ranges[0].nrelative \
277 = MIN (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)]->d_un.d_val, \
278 ranges[0].size / sizeof (ElfW(reloc))); \
ca34d7a7 279 } \
ca34d7a7 280 \
e0f41886 281 if ((do_lazy) \
052b6a6c 282 && (map)->l_info[DT_PLTREL] \
f420344c 283 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
052b6a6c 284 { \
a42195db 285 ranges[1].start = D_PTR ((map), l_info[DT_JMPREL]); \
052b6a6c
UD
286 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
287 ranges[2].start = ranges[1].start + ranges[1].size; \
288 ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start; \
289 ranges[0].size = ranges[1].start - ranges[0].start; \
ca34d7a7 290 } \
052b6a6c
UD
291 \
292 for (ranges_index = 0; ranges_index < 3; ++ranges_index) \
293 elf_dynamic_do_##reloc ((map), \
294 ranges[ranges_index].start, \
295 ranges[ranges_index].size, \
e453f6cd 296 ranges[ranges_index].nrelative, \
3a62d00d
AS
297 ranges[ranges_index].lazy, \
298 skip_ifunc); \
ca34d7a7 299 } while (0)
f420344c 300# else
3a62d00d 301# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, skip_ifunc, test_rel) \
ca34d7a7 302 do { \
aac13307
UD
303 struct { ElfW(Addr) start, size; \
304 __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
e453f6cd 305 ranges[2] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; \
052b6a6c 306 \
ca34d7a7
UD
307 if ((map)->l_info[DT_##RELOC]) \
308 { \
32e6df36
UD
309 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
310 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
e453f6cd
UD
311 if (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)] != NULL) \
312 ranges[0].nrelative \
313 = MIN (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)]->d_un.d_val, \
314 ranges[0].size / sizeof (ElfW(reloc))); \
ca34d7a7 315 } \
f420344c
UD
316 if ((map)->l_info[DT_PLTREL] \
317 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
ca34d7a7 318 { \
a42195db 319 ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
052b6a6c 320 \
e0f41886
UD
321 if (! ELF_DURING_STARTUP \
322 && ((do_lazy) \
323 /* This test does not only detect whether the relocation \
324 sections are in the right order, it also checks whether \
325 there is a DT_REL/DT_RELA section. */ \
e453f6cd
UD
326 || __builtin_expect (ranges[0].start + ranges[0].size \
327 != start, 0))) \
052b6a6c
UD
328 { \
329 ranges[1].start = start; \
330 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
085320f5 331 ranges[1].lazy = (do_lazy); \
052b6a6c
UD
332 } \
333 else \
e0f41886
UD
334 { \
335 /* Combine processing the sections. */ \
336 assert (ranges[0].start + ranges[0].size == start); \
337 ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
338 } \
ca34d7a7 339 } \
052b6a6c 340 \
e0f41886 341 if (ELF_DURING_STARTUP) \
e453f6cd
UD
342 elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, \
343 ranges[0].nrelative, 0, skip_ifunc); \
e0f41886
UD
344 else \
345 { \
346 int ranges_index; \
347 for (ranges_index = 0; ranges_index < 2; ++ranges_index) \
348 elf_dynamic_do_##reloc ((map), \
349 ranges[ranges_index].start, \
350 ranges[ranges_index].size, \
e453f6cd 351 ranges[ranges_index].nrelative, \
3a62d00d
AS
352 ranges[ranges_index].lazy, \
353 skip_ifunc); \
e0f41886 354 } \
ca34d7a7 355 } while (0)
f420344c
UD
356# endif
357
358# if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
359# define _ELF_CHECK_REL 0
360# else
361# define _ELF_CHECK_REL 1
362# endif
363
364# if ! ELF_MACHINE_NO_REL
365# include "do-rel.h"
3a62d00d 366# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) \
e453f6cd 367 _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, lazy, skip_ifunc, _ELF_CHECK_REL)
f420344c 368# else
3a62d00d 369# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) /* Nothing to do. */
f420344c
UD
370# endif
371
372# if ! ELF_MACHINE_NO_RELA
373# define DO_RELA
374# include "do-rel.h"
3a62d00d 375# define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) \
e453f6cd 376 _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, lazy, skip_ifunc, _ELF_CHECK_REL)
f420344c 377# else
3a62d00d 378# define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) /* Nothing to do. */
f420344c 379# endif
421f82e5
RM
380
381/* This can't just be an inline function because GCC is too dumb
382 to inline functions containing inlines themselves. */
3a62d00d 383# define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile, skip_ifunc) \
3996f34b 384 do { \
c0fb8a56
UD
385 int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \
386 (consider_profile)); \
3a62d00d
AS
387 ELF_DYNAMIC_DO_REL ((map), edr_lazy, skip_ifunc); \
388 ELF_DYNAMIC_DO_RELA ((map), edr_lazy, skip_ifunc); \
0501d603 389 } while (0)
f51d1dfd
RM
390
391#endif