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