]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dynamic-link.h
Optimize libnss_files initialization
[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,
87d254a7 63 void *const reloc_addr);
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,
87d254a7 72 void *const reloc_addr);
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
UD
79elf_machine_lazy_rel (struct link_map *map,
80 ElfW(Addr) l_addr, const ElfW(Rel) *reloc);
81# else
1b243ca9 82auto inline void __attribute__((always_inline))
567678b6
UD
83elf_machine_lazy_rel (struct link_map *map,
84 ElfW(Addr) l_addr, const ElfW(Rela) *reloc);
85# endif
86#endif
87
88#include <dl-machine.h>
89
f420344c 90#ifndef VERSYMIDX
b0982c4a 91# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
f420344c
UD
92#endif
93
421f82e5 94
d66e34cd 95/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
9dcafc55 96#ifndef RESOLVE_MAP
7090d3ca
AJ
97static
98#else
99auto
100#endif
101inline void __attribute__ ((unused, always_inline))
479aa8ec 102elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
d66e34cd 103{
fcf70d41 104 ElfW(Dyn) *dyn = l->l_ld;
fcf70d41 105 ElfW(Dyn) **info;
db07e962
AS
106#if __ELF_NATIVE_CLASS == 32
107 typedef Elf32_Word d_tag_utype;
108#elif __ELF_NATIVE_CLASS == 64
109 typedef Elf64_Xword d_tag_utype;
110#endif
fcf70d41 111
56c57442
UD
112#ifndef RTLD_BOOTSTRAP
113 if (dyn == NULL)
b122c703 114 return;
56c57442 115#endif
b122c703 116
fcf70d41
UD
117 info = l->l_info;
118
d66e34cd
RM
119 while (dyn->d_tag != DT_NULL)
120 {
db07e962 121 if ((d_tag_utype) dyn->d_tag < DT_NUM)
a2e1b046
RM
122 info[dyn->d_tag] = dyn;
123 else if (dyn->d_tag >= DT_LOPROC &&
b0982c4a 124 dyn->d_tag < DT_LOPROC + DT_THISPROCNUM)
a2e1b046 125 info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn;
db07e962 126 else if ((d_tag_utype) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM)
f420344c 127 info[VERSYMIDX (dyn->d_tag)] = dyn;
db07e962 128 else if ((d_tag_utype) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)
b0982c4a 129 info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
1228ed5c 130 + DT_VERSIONTAGNUM] = dyn;
db07e962 131 else if ((d_tag_utype) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
32e6df36
UD
132 info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
133 + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn;
db07e962 134 else if ((d_tag_utype) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
32e6df36
UD
135 info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
136 + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn;
bd355af0 137 ++dyn;
d66e34cd 138 }
479aa8ec
UD
139
140#define DL_RO_DYN_TEMP_CNT 8
141
a42195db 142#ifndef DL_RO_DYN_SECTION
32e6df36 143 /* Don't adjust .dynamic unnecessarily. */
56c57442 144 if (l->l_addr != 0)
f420344c 145 {
56c57442 146 ElfW(Addr) l_addr = l->l_addr;
479aa8ec
UD
147 int cnt = 0;
148
149# define ADJUST_DYN_INFO(tag) \
150 do \
151 if (info[tag] != NULL) \
152 { \
153 if (temp) \
154 { \
155 temp[cnt].d_tag = info[tag]->d_tag; \
156 temp[cnt].d_un.d_ptr = info[tag]->d_un.d_ptr + l_addr; \
157 info[tag] = temp + cnt++; \
158 } \
159 else \
160 info[tag]->d_un.d_ptr += l_addr; \
161 } \
162 while (0)
56c57442 163
479aa8ec
UD
164 ADJUST_DYN_INFO (DT_HASH);
165 ADJUST_DYN_INFO (DT_PLTGOT);
166 ADJUST_DYN_INFO (DT_STRTAB);
167 ADJUST_DYN_INFO (DT_SYMTAB);
32e6df36 168# if ! ELF_MACHINE_NO_RELA
479aa8ec 169 ADJUST_DYN_INFO (DT_RELA);
a42195db
UD
170# endif
171# if ! ELF_MACHINE_NO_REL
479aa8ec 172 ADJUST_DYN_INFO (DT_REL);
a42195db 173# endif
479aa8ec
UD
174 ADJUST_DYN_INFO (DT_JMPREL);
175 ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
871b9158
UD
176 ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
177 + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM);
479aa8ec
UD
178# undef ADJUST_DYN_INFO
179 assert (cnt <= DL_RO_DYN_TEMP_CNT);
32e6df36 180 }
f420344c
UD
181#endif
182 if (info[DT_PLTREL] != NULL)
183 {
56c57442 184#if ELF_MACHINE_NO_RELA
f420344c 185 assert (info[DT_PLTREL]->d_un.d_val == DT_REL);
56c57442 186#elif ELF_MACHINE_NO_REL
f420344c 187 assert (info[DT_PLTREL]->d_un.d_val == DT_RELA);
56c57442 188#else
f420344c
UD
189 assert (info[DT_PLTREL]->d_un.d_val == DT_REL
190 || info[DT_PLTREL]->d_un.d_val == DT_RELA);
56c57442 191#endif
f420344c 192 }
56c57442 193#if ! ELF_MACHINE_NO_RELA
32e6df36
UD
194 if (info[DT_RELA] != NULL)
195 assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
196# endif
197# if ! ELF_MACHINE_NO_REL
198 if (info[DT_REL] != NULL)
199 assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
56c57442 200#endif
445888be 201#ifdef RTLD_BOOTSTRAP
4df8c11d
UD
202 /* Only the bind now flags are allowed. */
203 assert (info[VERSYMIDX (DT_FLAGS_1)] == NULL
31fffa6b 204 || (info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val & ~DF_1_NOW) == 0);
4df8c11d 205 assert (info[DT_FLAGS] == NULL
31fffa6b 206 || (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0);
445888be 207 /* Flags must not be set for ld.so. */
445888be
UD
208 assert (info[DT_RUNPATH] == NULL);
209 assert (info[DT_RPATH] == NULL);
210#else
06535ae9
UD
211 if (info[DT_FLAGS] != NULL)
212 {
213 /* Flags are used. Translate to the old form where available.
214 Since these l_info entries are only tested for NULL pointers it
215 is ok if they point to the DT_FLAGS entry. */
ec70c011 216 l->l_flags = info[DT_FLAGS]->d_un.d_val;
445888be 217
37beecf7 218 if (l->l_flags & DF_SYMBOLIC)
06535ae9 219 info[DT_SYMBOLIC] = info[DT_FLAGS];
37beecf7 220 if (l->l_flags & DF_TEXTREL)
06535ae9 221 info[DT_TEXTREL] = info[DT_FLAGS];
ec70c011 222 if (l->l_flags & DF_BIND_NOW)
06535ae9 223 info[DT_BIND_NOW] = info[DT_FLAGS];
37beecf7 224 }
bf8b3e74 225 if (info[VERSYMIDX (DT_FLAGS_1)] != NULL)
445888be
UD
226 {
227 l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val;
228
229 if (l->l_flags_1 & DF_1_NOW)
230 info[DT_BIND_NOW] = info[VERSYMIDX (DT_FLAGS_1)];
231 }
fcf70d41
UD
232 if (info[DT_RUNPATH] != NULL)
233 /* If both RUNPATH and RPATH are given, the latter is ignored. */
234 info[DT_RPATH] = NULL;
56c57442 235#endif
d66e34cd
RM
236}
237
9dcafc55 238#ifdef RESOLVE_MAP
f51d1dfd 239
e0f41886
UD
240# ifdef RTLD_BOOTSTRAP
241# define ELF_DURING_STARTUP (1)
242# else
243# define ELF_DURING_STARTUP (0)
244# endif
245
421f82e5
RM
246/* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
247 These functions are almost identical, so we use cpp magic to avoid
248 duplicating their code. It cannot be done in a more general function
249 because we must be able to completely inline. */
250
f420344c 251/* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
ca34d7a7
UD
252 range. Note that according to the ELF spec, this is completely legal!
253 But conditionally define things so that on machines we know this will
254 not happen we do something more optimal. */
255
f420344c
UD
256# ifdef ELF_MACHINE_PLTREL_OVERLAP
257# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
ca34d7a7 258 do { \
085320f5 259 struct { ElfW(Addr) start, size; int lazy; } ranges[3]; \
052b6a6c
UD
260 int ranges_index; \
261 \
262 ranges[0].lazy = ranges[2].lazy = 0; \
263 ranges[1].lazy = 1; \
264 ranges[0].size = ranges[1].size = ranges[2].size = 0; \
265 \
ca34d7a7
UD
266 if ((map)->l_info[DT_##RELOC]) \
267 { \
a42195db 268 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
052b6a6c 269 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
ca34d7a7 270 } \
ca34d7a7 271 \
e0f41886 272 if ((do_lazy) \
052b6a6c 273 && (map)->l_info[DT_PLTREL] \
f420344c 274 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
052b6a6c 275 { \
a42195db 276 ranges[1].start = D_PTR ((map), l_info[DT_JMPREL]); \
052b6a6c
UD
277 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
278 ranges[2].start = ranges[1].start + ranges[1].size; \
279 ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start; \
280 ranges[0].size = ranges[1].start - ranges[0].start; \
ca34d7a7 281 } \
052b6a6c
UD
282 \
283 for (ranges_index = 0; ranges_index < 3; ++ranges_index) \
284 elf_dynamic_do_##reloc ((map), \
285 ranges[ranges_index].start, \
286 ranges[ranges_index].size, \
287 ranges[ranges_index].lazy); \
ca34d7a7 288 } while (0)
f420344c
UD
289# else
290# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
ca34d7a7 291 do { \
085320f5 292 struct { ElfW(Addr) start, size; int lazy; } ranges[2]; \
052b6a6c 293 ranges[0].lazy = 0; \
052b6a6c
UD
294 ranges[0].size = ranges[1].size = 0; \
295 ranges[0].start = 0; \
296 \
ca34d7a7
UD
297 if ((map)->l_info[DT_##RELOC]) \
298 { \
32e6df36
UD
299 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
300 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
ca34d7a7 301 } \
f420344c
UD
302 if ((map)->l_info[DT_PLTREL] \
303 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
ca34d7a7 304 { \
a42195db 305 ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
052b6a6c 306 \
e0f41886
UD
307 if (! ELF_DURING_STARTUP \
308 && ((do_lazy) \
309 /* This test does not only detect whether the relocation \
310 sections are in the right order, it also checks whether \
311 there is a DT_REL/DT_RELA section. */ \
312 || ranges[0].start + ranges[0].size != start)) \
052b6a6c
UD
313 { \
314 ranges[1].start = start; \
315 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
085320f5 316 ranges[1].lazy = (do_lazy); \
052b6a6c
UD
317 } \
318 else \
e0f41886
UD
319 { \
320 /* Combine processing the sections. */ \
321 assert (ranges[0].start + ranges[0].size == start); \
322 ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
323 } \
ca34d7a7 324 } \
052b6a6c 325 \
e0f41886
UD
326 if (ELF_DURING_STARTUP) \
327 elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, 0); \
328 else \
329 { \
330 int ranges_index; \
331 for (ranges_index = 0; ranges_index < 2; ++ranges_index) \
332 elf_dynamic_do_##reloc ((map), \
333 ranges[ranges_index].start, \
334 ranges[ranges_index].size, \
335 ranges[ranges_index].lazy); \
336 } \
ca34d7a7 337 } while (0)
f420344c
UD
338# endif
339
340# if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
341# define _ELF_CHECK_REL 0
342# else
343# define _ELF_CHECK_REL 1
344# endif
345
346# if ! ELF_MACHINE_NO_REL
347# include "do-rel.h"
348# define ELF_DYNAMIC_DO_REL(map, lazy) \
349 _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, _ELF_CHECK_REL)
350# else
351# define ELF_DYNAMIC_DO_REL(map, lazy) /* Nothing to do. */
352# endif
353
354# if ! ELF_MACHINE_NO_RELA
355# define DO_RELA
356# include "do-rel.h"
357# define ELF_DYNAMIC_DO_RELA(map, lazy) \
358 _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, _ELF_CHECK_REL)
359# else
360# define ELF_DYNAMIC_DO_RELA(map, lazy) /* Nothing to do. */
361# endif
421f82e5
RM
362
363/* This can't just be an inline function because GCC is too dumb
364 to inline functions containing inlines themselves. */
f420344c 365# define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \
3996f34b 366 do { \
c0fb8a56
UD
367 int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \
368 (consider_profile)); \
3996f34b
UD
369 ELF_DYNAMIC_DO_REL ((map), edr_lazy); \
370 ELF_DYNAMIC_DO_RELA ((map), edr_lazy); \
0501d603 371 } while (0)
f51d1dfd
RM
372
373#endif