]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/dynamic-link.h
Update.
[thirdparty/glibc.git] / elf / dynamic-link.h
CommitLineData
d66e34cd 1/* Inline functions for dynamic linking.
d6b5d570 2 Copyright (C) 1995,96,97,98,99,2000,2001,2002 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
RM
19
20#include <elf.h>
d66e34cd 21#include <dl-machine.h>
d66e34cd
RM
22#include <assert.h>
23
f420344c 24#ifndef VERSYMIDX
b0982c4a 25# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
f420344c
UD
26#endif
27
421f82e5 28
d66e34cd
RM
29/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
30
e75154a6 31static inline void __attribute__ ((unused))
fcf70d41 32elf_get_dynamic_info (struct link_map *l)
d66e34cd 33{
fcf70d41 34 ElfW(Dyn) *dyn = l->l_ld;
fcf70d41
UD
35 ElfW(Dyn) **info;
36
56c57442
UD
37#ifndef RTLD_BOOTSTRAP
38 if (dyn == NULL)
b122c703 39 return;
56c57442 40#endif
b122c703 41
fcf70d41
UD
42 info = l->l_info;
43
d66e34cd
RM
44 while (dyn->d_tag != DT_NULL)
45 {
a2e1b046
RM
46 if (dyn->d_tag < DT_NUM)
47 info[dyn->d_tag] = dyn;
48 else if (dyn->d_tag >= DT_LOPROC &&
b0982c4a 49 dyn->d_tag < DT_LOPROC + DT_THISPROCNUM)
a2e1b046 50 info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn;
1228ed5c 51 else if ((Elf32_Word) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM)
f420344c 52 info[VERSYMIDX (dyn->d_tag)] = dyn;
df4ef2ab 53 else if ((Elf32_Word) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)
b0982c4a 54 info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
1228ed5c 55 + DT_VERSIONTAGNUM] = dyn;
32e6df36
UD
56 else if ((Elf32_Word) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM)
57 info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
58 + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn;
59 else if ((Elf32_Word) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM)
60 info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
61 + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn;
a2e1b046 62 else
38334018 63 assert (! "bad dynamic tag");
bd355af0 64 ++dyn;
d66e34cd 65 }
a42195db 66#ifndef DL_RO_DYN_SECTION
32e6df36 67 /* Don't adjust .dynamic unnecessarily. */
56c57442 68 if (l->l_addr != 0)
f420344c 69 {
56c57442
UD
70 ElfW(Addr) l_addr = l->l_addr;
71
32e6df36
UD
72 if (info[DT_PLTGOT] != NULL)
73 info[DT_PLTGOT]->d_un.d_ptr += l_addr;
74 if (info[DT_STRTAB] != NULL)
75 info[DT_STRTAB]->d_un.d_ptr += l_addr;
76 if (info[DT_SYMTAB] != NULL)
77 info[DT_SYMTAB]->d_un.d_ptr += l_addr;
78# if ! ELF_MACHINE_NO_RELA
79 if (info[DT_RELA] != NULL)
80 info[DT_RELA]->d_un.d_ptr += l_addr;
a42195db
UD
81# endif
82# if ! ELF_MACHINE_NO_REL
32e6df36
UD
83 if (info[DT_REL] != NULL)
84 info[DT_REL]->d_un.d_ptr += l_addr;
a42195db 85# endif
32e6df36
UD
86 if (info[DT_JMPREL] != NULL)
87 info[DT_JMPREL]->d_un.d_ptr += l_addr;
88 if (info[VERSYMIDX (DT_VERSYM)] != NULL)
89 info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr;
90 }
f420344c
UD
91#endif
92 if (info[DT_PLTREL] != NULL)
93 {
56c57442 94#if ELF_MACHINE_NO_RELA
f420344c 95 assert (info[DT_PLTREL]->d_un.d_val == DT_REL);
56c57442 96#elif ELF_MACHINE_NO_REL
f420344c 97 assert (info[DT_PLTREL]->d_un.d_val == DT_RELA);
56c57442 98#else
f420344c
UD
99 assert (info[DT_PLTREL]->d_un.d_val == DT_REL
100 || info[DT_PLTREL]->d_un.d_val == DT_RELA);
56c57442 101#endif
f420344c 102 }
56c57442 103#if ! ELF_MACHINE_NO_RELA
32e6df36
UD
104 if (info[DT_RELA] != NULL)
105 assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
106# endif
107# if ! ELF_MACHINE_NO_REL
108 if (info[DT_REL] != NULL)
109 assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
56c57442
UD
110#endif
111#ifdef RTLD_BOOTSTRAP
112 /* None of the flags should be set for the dynamic linker itself. */
113 assert (info[DT_FLAGS] == NULL);
114#else
06535ae9
UD
115 if (info[DT_FLAGS] != NULL)
116 {
117 /* Flags are used. Translate to the old form where available.
118 Since these l_info entries are only tested for NULL pointers it
119 is ok if they point to the DT_FLAGS entry. */
120 ElfW(Word) flags = info[DT_FLAGS]->d_un.d_val;
121 if (flags & DF_SYMBOLIC)
122 info[DT_SYMBOLIC] = info[DT_FLAGS];
123 if (flags & DF_TEXTREL)
124 info[DT_TEXTREL] = info[DT_FLAGS];
125 if (flags & DF_BIND_NOW)
126 info[DT_BIND_NOW] = info[DT_FLAGS];
127 }
56c57442 128#endif
bf8b3e74
UD
129 if (info[VERSYMIDX (DT_FLAGS_1)] != NULL)
130 l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val;
56c57442
UD
131#ifdef RTLD_BOOTSTRAP
132 /* The dynamic linker should have none of these set. */
133 assert (info[DT_RUNPATH] == NULL);
134 assert (info[DT_RPATH] == NULL);
135#else
fcf70d41
UD
136 if (info[DT_RUNPATH] != NULL)
137 /* If both RUNPATH and RPATH are given, the latter is ignored. */
138 info[DT_RPATH] = NULL;
56c57442 139#endif
d66e34cd
RM
140}
141
f51d1dfd
RM
142#ifdef RESOLVE
143
421f82e5
RM
144/* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
145 These functions are almost identical, so we use cpp magic to avoid
146 duplicating their code. It cannot be done in a more general function
147 because we must be able to completely inline. */
148
f420344c 149/* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
ca34d7a7
UD
150 range. Note that according to the ELF spec, this is completely legal!
151 But conditionally define things so that on machines we know this will
152 not happen we do something more optimal. */
153
f420344c
UD
154# ifdef ELF_MACHINE_PLTREL_OVERLAP
155# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
ca34d7a7 156 do { \
085320f5 157 struct { ElfW(Addr) start, size; int lazy; } ranges[3]; \
052b6a6c
UD
158 int ranges_index; \
159 \
160 ranges[0].lazy = ranges[2].lazy = 0; \
161 ranges[1].lazy = 1; \
162 ranges[0].size = ranges[1].size = ranges[2].size = 0; \
163 \
ca34d7a7
UD
164 if ((map)->l_info[DT_##RELOC]) \
165 { \
a42195db 166 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
052b6a6c 167 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
ca34d7a7 168 } \
ca34d7a7 169 \
085320f5 170 if ((do_lazy) \
052b6a6c 171 && (map)->l_info[DT_PLTREL] \
f420344c 172 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
052b6a6c 173 { \
a42195db 174 ranges[1].start = D_PTR ((map), l_info[DT_JMPREL]); \
052b6a6c
UD
175 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
176 ranges[2].start = ranges[1].start + ranges[1].size; \
177 ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start; \
178 ranges[0].size = ranges[1].start - ranges[0].start; \
ca34d7a7 179 } \
052b6a6c
UD
180 \
181 for (ranges_index = 0; ranges_index < 3; ++ranges_index) \
182 elf_dynamic_do_##reloc ((map), \
183 ranges[ranges_index].start, \
184 ranges[ranges_index].size, \
185 ranges[ranges_index].lazy); \
ca34d7a7 186 } while (0)
f420344c
UD
187# else
188# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
ca34d7a7 189 do { \
085320f5 190 struct { ElfW(Addr) start, size; int lazy; } ranges[2]; \
052b6a6c
UD
191 int ranges_index; \
192 ranges[0].lazy = 0; \
052b6a6c
UD
193 ranges[0].size = ranges[1].size = 0; \
194 ranges[0].start = 0; \
195 \
ca34d7a7
UD
196 if ((map)->l_info[DT_##RELOC]) \
197 { \
32e6df36
UD
198 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
199 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
ca34d7a7 200 } \
f420344c
UD
201 if ((map)->l_info[DT_PLTREL] \
202 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
ca34d7a7 203 { \
a42195db 204 ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
052b6a6c 205 \
085320f5 206 if ((do_lazy) \
052b6a6c
UD
207 /* This test does not only detect whether the relocation \
208 sections are in the right order, it also checks whether \
209 there is a DT_REL/DT_RELA section. */ \
210 || ranges[0].start + ranges[0].size != start) \
211 { \
212 ranges[1].start = start; \
213 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
085320f5 214 ranges[1].lazy = (do_lazy); \
052b6a6c
UD
215 } \
216 else \
217 /* Combine processing the sections. */ \
218 ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
ca34d7a7 219 } \
052b6a6c
UD
220 \
221 for (ranges_index = 0; ranges_index < 2; ++ranges_index) \
222 elf_dynamic_do_##reloc ((map), \
223 ranges[ranges_index].start, \
224 ranges[ranges_index].size, \
225 ranges[ranges_index].lazy); \
ca34d7a7 226 } while (0)
f420344c
UD
227# endif
228
229# if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
230# define _ELF_CHECK_REL 0
231# else
232# define _ELF_CHECK_REL 1
233# endif
234
235# if ! ELF_MACHINE_NO_REL
236# include "do-rel.h"
237# define ELF_DYNAMIC_DO_REL(map, lazy) \
238 _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, _ELF_CHECK_REL)
239# else
240# define ELF_DYNAMIC_DO_REL(map, lazy) /* Nothing to do. */
241# endif
242
243# if ! ELF_MACHINE_NO_RELA
244# define DO_RELA
245# include "do-rel.h"
246# define ELF_DYNAMIC_DO_RELA(map, lazy) \
247 _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, _ELF_CHECK_REL)
248# else
249# define ELF_DYNAMIC_DO_RELA(map, lazy) /* Nothing to do. */
250# endif
421f82e5
RM
251
252/* This can't just be an inline function because GCC is too dumb
253 to inline functions containing inlines themselves. */
f420344c 254# define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \
3996f34b 255 do { \
c0fb8a56
UD
256 int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \
257 (consider_profile)); \
3996f34b
UD
258 ELF_DYNAMIC_DO_REL ((map), edr_lazy); \
259 ELF_DYNAMIC_DO_RELA ((map), edr_lazy); \
0501d603 260 } while (0)
f51d1dfd
RM
261
262#endif