Update.
[glibc.git] / elf / dynamic-link.h
blobf4bbcb5cfd5e343a923519402b50b1a093db9014
1 /* Inline functions for dynamic linking.
2 Copyright (C) 1995,96,97,98,99,2000,2001,2002 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
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.
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
13 Lesser General Public License for more details.
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. */
20 #include <elf.h>
21 #include <dl-machine.h>
22 #include <assert.h>
24 #ifndef VERSYMIDX
25 # define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
26 #endif
29 /* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
31 static inline void __attribute__ ((unused))
32 elf_get_dynamic_info (struct link_map *l)
34 ElfW(Dyn) *dyn = l->l_ld;
35 ElfW(Dyn) **info;
37 #ifndef RTLD_BOOTSTRAP
38 if (dyn == NULL)
39 return;
40 #endif
42 info = l->l_info;
44 while (dyn->d_tag != DT_NULL)
46 if (dyn->d_tag < DT_NUM)
47 info[dyn->d_tag] = dyn;
48 else if (dyn->d_tag >= DT_LOPROC &&
49 dyn->d_tag < DT_LOPROC + DT_THISPROCNUM)
50 info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn;
51 else if ((Elf32_Word) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM)
52 info[VERSYMIDX (dyn->d_tag)] = dyn;
53 else if ((Elf32_Word) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM)
54 info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM
55 + DT_VERSIONTAGNUM] = dyn;
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;
62 else
63 assert (! "bad dynamic tag");
64 ++dyn;
66 #ifndef DL_RO_DYN_SECTION
67 /* Don't adjust .dynamic unnecessarily. */
68 if (l->l_addr != 0)
70 ElfW(Addr) l_addr = l->l_addr;
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;
81 # endif
82 # if ! ELF_MACHINE_NO_REL
83 if (info[DT_REL] != NULL)
84 info[DT_REL]->d_un.d_ptr += l_addr;
85 # endif
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;
91 #endif
92 if (info[DT_PLTREL] != NULL)
94 #if ELF_MACHINE_NO_RELA
95 assert (info[DT_PLTREL]->d_un.d_val == DT_REL);
96 #elif ELF_MACHINE_NO_REL
97 assert (info[DT_PLTREL]->d_un.d_val == DT_RELA);
98 #else
99 assert (info[DT_PLTREL]->d_un.d_val == DT_REL
100 || info[DT_PLTREL]->d_un.d_val == DT_RELA);
101 #endif
103 #if ! ELF_MACHINE_NO_RELA
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)));
110 #endif
111 if (info[DT_FLAGS] != NULL)
113 /* Flags are used. Translate to the old form where available.
114 Since these l_info entries are only tested for NULL pointers it
115 is ok if they point to the DT_FLAGS entry. */
116 l->l_flags = info[DT_FLAGS]->d_un.d_val;
117 #ifdef RTLD_BOOTSTRAP
118 /* These three flags must not be set for ld.so. */
119 assert ((l->l_flags & (DF_SYMBOLIC | DF_TEXTREL | DF_BIND_NOW)) == 0);
120 #else
121 if (l->l_flags & DF_SYMBOLIC)
122 info[DT_SYMBOLIC] = info[DT_FLAGS];
123 if (l->l_flags & DF_TEXTREL)
124 info[DT_TEXTREL] = info[DT_FLAGS];
125 if (l->l_flags & DF_BIND_NOW)
126 info[DT_BIND_NOW] = info[DT_FLAGS];
127 #endif
129 if (info[VERSYMIDX (DT_FLAGS_1)] != NULL)
130 l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val;
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
136 if (info[DT_RUNPATH] != NULL)
137 /* If both RUNPATH and RPATH are given, the latter is ignored. */
138 info[DT_RPATH] = NULL;
139 #endif
142 #ifdef RESOLVE
144 # ifdef RTLD_BOOTSTRAP
145 # define ELF_DURING_STARTUP (1)
146 # else
147 # define ELF_DURING_STARTUP (0)
148 # endif
150 /* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
151 These functions are almost identical, so we use cpp magic to avoid
152 duplicating their code. It cannot be done in a more general function
153 because we must be able to completely inline. */
155 /* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
156 range. Note that according to the ELF spec, this is completely legal!
157 But conditionally define things so that on machines we know this will
158 not happen we do something more optimal. */
160 # ifdef ELF_MACHINE_PLTREL_OVERLAP
161 # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
162 do { \
163 struct { ElfW(Addr) start, size; int lazy; } ranges[3]; \
164 int ranges_index; \
166 ranges[0].lazy = ranges[2].lazy = 0; \
167 ranges[1].lazy = 1; \
168 ranges[0].size = ranges[1].size = ranges[2].size = 0; \
170 if ((map)->l_info[DT_##RELOC]) \
172 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
173 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
176 if ((do_lazy) \
177 && (map)->l_info[DT_PLTREL] \
178 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
180 ranges[1].start = D_PTR ((map), l_info[DT_JMPREL]); \
181 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
182 ranges[2].start = ranges[1].start + ranges[1].size; \
183 ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start; \
184 ranges[0].size = ranges[1].start - ranges[0].start; \
187 for (ranges_index = 0; ranges_index < 3; ++ranges_index) \
188 elf_dynamic_do_##reloc ((map), \
189 ranges[ranges_index].start, \
190 ranges[ranges_index].size, \
191 ranges[ranges_index].lazy); \
192 } while (0)
193 # else
194 # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
195 do { \
196 struct { ElfW(Addr) start, size; int lazy; } ranges[2]; \
197 ranges[0].lazy = 0; \
198 ranges[0].size = ranges[1].size = 0; \
199 ranges[0].start = 0; \
201 if ((map)->l_info[DT_##RELOC]) \
203 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
204 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
206 if ((map)->l_info[DT_PLTREL] \
207 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
209 ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
211 if (! ELF_DURING_STARTUP \
212 && ((do_lazy) \
213 /* This test does not only detect whether the relocation \
214 sections are in the right order, it also checks whether \
215 there is a DT_REL/DT_RELA section. */ \
216 || ranges[0].start + ranges[0].size != start)) \
218 ranges[1].start = start; \
219 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
220 ranges[1].lazy = (do_lazy); \
222 else \
224 /* Combine processing the sections. */ \
225 assert (ranges[0].start + ranges[0].size == start); \
226 ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
230 if (ELF_DURING_STARTUP) \
231 elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, 0); \
232 else \
234 int ranges_index; \
235 for (ranges_index = 0; ranges_index < 2; ++ranges_index) \
236 elf_dynamic_do_##reloc ((map), \
237 ranges[ranges_index].start, \
238 ranges[ranges_index].size, \
239 ranges[ranges_index].lazy); \
241 } while (0)
242 # endif
244 # if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
245 # define _ELF_CHECK_REL 0
246 # else
247 # define _ELF_CHECK_REL 1
248 # endif
250 # if ! ELF_MACHINE_NO_REL
251 # include "do-rel.h"
252 # define ELF_DYNAMIC_DO_REL(map, lazy) \
253 _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, _ELF_CHECK_REL)
254 # else
255 # define ELF_DYNAMIC_DO_REL(map, lazy) /* Nothing to do. */
256 # endif
258 # if ! ELF_MACHINE_NO_RELA
259 # define DO_RELA
260 # include "do-rel.h"
261 # define ELF_DYNAMIC_DO_RELA(map, lazy) \
262 _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, _ELF_CHECK_REL)
263 # else
264 # define ELF_DYNAMIC_DO_RELA(map, lazy) /* Nothing to do. */
265 # endif
267 /* This can't just be an inline function because GCC is too dumb
268 to inline functions containing inlines themselves. */
269 # define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \
270 do { \
271 int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \
272 (consider_profile)); \
273 ELF_DYNAMIC_DO_REL ((map), edr_lazy); \
274 ELF_DYNAMIC_DO_RELA ((map), edr_lazy); \
275 } while (0)
277 #endif