]> sourceware.org Git - glibc.git/blame - elf/dynamic-link.h
rtld: Avoid using up static TLS surplus for optimizations [BZ #25051]
[glibc.git] / elf / dynamic-link.h
CommitLineData
d66e34cd 1/* Inline functions for dynamic linking.
d614a753 2 Copyright (C) 1995-2020 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 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://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. */
afcd9480
AM
28#define HAVE_STATIC_TLS(map, sym_map) \
29 (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET \
30 && ((sym_map)->l_tls_offset \
31 != FORCED_DYNAMIC_TLS_OFFSET), 1))
32
c9ff0187
UD
33#define CHECK_STATIC_TLS(map, sym_map) \
34 do { \
afcd9480 35 if (!HAVE_STATIC_TLS (map, sym_map)) \
c9ff0187
UD
36 _dl_allocate_static_tls (sym_map); \
37 } while (0)
38
39#define TRY_STATIC_TLS(map, sym_map) \
40 (__builtin_expect ((sym_map)->l_tls_offset \
41 != FORCED_DYNAMIC_TLS_OFFSET, 1) \
42 && (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \
ffb17e7b 43 || _dl_try_allocate_static_tls (sym_map, true) == 0))
c9ff0187 44
ffb17e7b
SN
45int _dl_try_allocate_static_tls (struct link_map *map, bool optional)
46 attribute_hidden;
c9ff0187 47
d66e34cd 48#include <elf.h>
d66e34cd 49
9dcafc55 50#ifdef RESOLVE_MAP
87d254a7
AO
51/* We pass reloc_addr as a pointer to void, as opposed to a pointer to
52 ElfW(Addr), because not all architectures can assume that the
53 relocated address is properly aligned, whereas the compiler is
54 entitled to assume that a pointer to a type is properly aligned for
55 the type. Even if we cast the pointer back to some other type with
56 less strict alignment requirements, the compiler might still
57 remember that the pointer was originally more aligned, thereby
58 optimizing away alignment tests or using word instructions for
59 copying memory, breaking the very code written to handle the
60 unaligned cases. */
9cfe5381 61# if ! ELF_MACHINE_NO_REL
1b243ca9 62auto inline void __attribute__((always_inline))
567678b6
UD
63elf_machine_rel (struct link_map *map, const ElfW(Rel) *reloc,
64 const ElfW(Sym) *sym, const struct r_found_version *version,
3a62d00d 65 void *const reloc_addr, int skip_ifunc);
1b243ca9 66auto inline void __attribute__((always_inline))
9cfe5381
RM
67elf_machine_rel_relative (ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
68 void *const reloc_addr);
69# endif
70# if ! ELF_MACHINE_NO_RELA
1b243ca9 71auto inline void __attribute__((always_inline))
567678b6
UD
72elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
73 const ElfW(Sym) *sym, const struct r_found_version *version,
3a62d00d 74 void *const reloc_addr, int skip_ifunc);
1b243ca9 75auto inline void __attribute__((always_inline))
567678b6 76elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
87d254a7 77 void *const reloc_addr);
9cfe5381 78# endif
567678b6 79# if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL
1b243ca9 80auto inline void __attribute__((always_inline))
567678b6 81elf_machine_lazy_rel (struct link_map *map,
3a62d00d
AS
82 ElfW(Addr) l_addr, const ElfW(Rel) *reloc,
83 int skip_ifunc);
567678b6 84# else
1b243ca9 85auto inline void __attribute__((always_inline))
567678b6 86elf_machine_lazy_rel (struct link_map *map,
3a62d00d
AS
87 ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
88 int skip_ifunc);
567678b6
UD
89# endif
90#endif
91
92#include <dl-machine.h>
93
9cee5585 94#include "get-dynamic-info.h"
d66e34cd 95
9dcafc55 96#ifdef RESOLVE_MAP
f51d1dfd 97
9d7a3741 98# if defined RTLD_BOOTSTRAP || defined STATIC_PIE_BOOTSTRAP
e0f41886
UD
99# define ELF_DURING_STARTUP (1)
100# else
101# define ELF_DURING_STARTUP (0)
102# endif
103
421f82e5
RM
104/* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
105 These functions are almost identical, so we use cpp magic to avoid
106 duplicating their code. It cannot be done in a more general function
107 because we must be able to completely inline. */
108
f420344c 109/* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
ca34d7a7 110 range. Note that according to the ELF spec, this is completely legal!
ca34d7a7 111
d7dd4413 112 We are guarenteed that we have one of three situations. Either DT_JMPREL
993eb054 113 comes immediately after DT_REL*, or there is overlap and DT_JMPREL
d7dd4413
DM
114 consumes precisely the very end of the DT_REL*, or DT_JMPREL and DT_REL*
115 are completely separate and there is a gap between them. */
993eb054
DM
116
117# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, skip_ifunc, test_rel) \
ca34d7a7 118 do { \
aac13307
UD
119 struct { ElfW(Addr) start, size; \
120 __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
e453f6cd 121 ranges[2] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; \
052b6a6c 122 \
ca34d7a7
UD
123 if ((map)->l_info[DT_##RELOC]) \
124 { \
32e6df36
UD
125 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
126 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
e453f6cd
UD
127 if (map->l_info[VERSYMIDX (DT_##RELOC##COUNT)] != NULL) \
128 ranges[0].nrelative \
585d9c18 129 = map->l_info[VERSYMIDX (DT_##RELOC##COUNT)]->d_un.d_val; \
ca34d7a7 130 } \
f420344c
UD
131 if ((map)->l_info[DT_PLTREL] \
132 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
ca34d7a7 133 { \
a42195db 134 ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
d7dd4413 135 ElfW(Addr) size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
052b6a6c 136 \
d7dd4413
DM
137 if (ranges[0].start + ranges[0].size == (start + size)) \
138 ranges[0].size -= size; \
fa19d5c4
PJ
139 if (ELF_DURING_STARTUP \
140 || (!(do_lazy) \
141 && (ranges[0].start + ranges[0].size) == start)) \
052b6a6c 142 { \
fa19d5c4
PJ
143 /* Combine processing the sections. */ \
144 ranges[0].size += size; \
052b6a6c
UD
145 } \
146 else \
e0f41886 147 { \
fa19d5c4
PJ
148 ranges[1].start = start; \
149 ranges[1].size = size; \
150 ranges[1].lazy = (do_lazy); \
e0f41886 151 } \
ca34d7a7 152 } \
052b6a6c 153 \
e0f41886 154 if (ELF_DURING_STARTUP) \
e453f6cd
UD
155 elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, \
156 ranges[0].nrelative, 0, skip_ifunc); \
e0f41886
UD
157 else \
158 { \
159 int ranges_index; \
160 for (ranges_index = 0; ranges_index < 2; ++ranges_index) \
161 elf_dynamic_do_##reloc ((map), \
162 ranges[ranges_index].start, \
163 ranges[ranges_index].size, \
e453f6cd 164 ranges[ranges_index].nrelative, \
3a62d00d
AS
165 ranges[ranges_index].lazy, \
166 skip_ifunc); \
e0f41886 167 } \
ca34d7a7 168 } while (0)
f420344c
UD
169
170# if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
171# define _ELF_CHECK_REL 0
172# else
173# define _ELF_CHECK_REL 1
174# endif
175
176# if ! ELF_MACHINE_NO_REL
177# include "do-rel.h"
3a62d00d 178# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) \
e453f6cd 179 _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, lazy, skip_ifunc, _ELF_CHECK_REL)
f420344c 180# else
3a62d00d 181# define ELF_DYNAMIC_DO_REL(map, lazy, skip_ifunc) /* Nothing to do. */
f420344c
UD
182# endif
183
184# if ! ELF_MACHINE_NO_RELA
185# define DO_RELA
186# include "do-rel.h"
3a62d00d 187# define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) \
e453f6cd 188 _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, lazy, skip_ifunc, _ELF_CHECK_REL)
f420344c 189# else
3a62d00d 190# define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc) /* Nothing to do. */
f420344c 191# endif
421f82e5
RM
192
193/* This can't just be an inline function because GCC is too dumb
194 to inline functions containing inlines themselves. */
3a62d00d 195# define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile, skip_ifunc) \
3996f34b 196 do { \
c0fb8a56
UD
197 int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \
198 (consider_profile)); \
3a62d00d
AS
199 ELF_DYNAMIC_DO_REL ((map), edr_lazy, skip_ifunc); \
200 ELF_DYNAMIC_DO_RELA ((map), edr_lazy, skip_ifunc); \
0501d603 201 } while (0)
f51d1dfd
RM
202
203#endif
This page took 0.51933 seconds and 5 git commands to generate.