Update.
[glibc.git] / elf / dynamic-link.h
blobd322c1231faa19900cf1f5e078d93d4203b8ce7a
1 /* Inline functions for dynamic linking.
2 Copyright (C) 1995, 1996, 1997, 1998, 1999 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 Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 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 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 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_PROCNUM + DT_VERSIONTAGIDX (sym))
26 #endif
29 /* Global read-only variable defined in rtld.c which is nonzero if we
30 shall give more warning messages. */
31 extern int _dl_verbose __attribute__ ((unused));
34 /* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
36 static inline void __attribute__ ((unused))
37 elf_get_dynamic_info (ElfW(Dyn) *dyn, ElfW(Addr) l_addr,
38 ElfW(Dyn) *info[DT_NUM + DT_PROCNUM + DT_VERSIONTAGNUM
39 + DT_EXTRANUM])
41 if (! dyn)
42 return;
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_PROCNUM)
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_PROCNUM
55 + DT_VERSIONTAGNUM] = dyn;
56 else
57 assert (! "bad dynamic tag");
58 ++dyn;
61 if (info[DT_PLTGOT] != NULL)
62 info[DT_PLTGOT]->d_un.d_ptr += l_addr;
63 if (info[DT_STRTAB] != NULL)
64 info[DT_STRTAB]->d_un.d_ptr += l_addr;
65 if (info[DT_SYMTAB] != NULL)
66 info[DT_SYMTAB]->d_un.d_ptr += l_addr;
67 #if ! ELF_MACHINE_NO_RELA
68 if (info[DT_RELA] != NULL)
70 assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela)));
71 info[DT_RELA]->d_un.d_ptr += l_addr;
73 #endif
74 #if ! ELF_MACHINE_NO_REL
75 if (info[DT_REL] != NULL)
77 assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel)));
78 info[DT_REL]->d_un.d_ptr += l_addr;
80 #endif
81 if (info[DT_PLTREL] != NULL)
83 #if ELF_MACHINE_NO_RELA
84 assert (info[DT_PLTREL]->d_un.d_val == DT_REL);
85 #elif ELF_MACHINE_NO_REL
86 assert (info[DT_PLTREL]->d_un.d_val == DT_RELA);
87 #else
88 assert (info[DT_PLTREL]->d_un.d_val == DT_REL
89 || info[DT_PLTREL]->d_un.d_val == DT_RELA);
90 #endif
92 if (info[DT_JMPREL] != NULL)
93 info[DT_JMPREL]->d_un.d_ptr += l_addr;
94 if (info[VERSYMIDX (DT_VERSYM)] != NULL)
95 info[VERSYMIDX (DT_VERSYM)]->d_un.d_ptr += l_addr;
98 #ifdef RESOLVE
100 /* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
101 These functions are almost identical, so we use cpp magic to avoid
102 duplicating their code. It cannot be done in a more general function
103 because we must be able to completely inline. */
105 /* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
106 range. Note that according to the ELF spec, this is completely legal!
107 But conditionally define things so that on machines we know this will
108 not happen we do something more optimal. */
110 # ifdef ELF_MACHINE_PLTREL_OVERLAP
111 # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
112 do { \
113 struct { ElfW(Addr) start, size; int lazy; } ranges[3]; \
114 int ranges_index; \
116 ranges[0].lazy = ranges[2].lazy = 0; \
117 ranges[1].lazy = 1; \
118 ranges[0].size = ranges[1].size = ranges[2].size = 0; \
120 if ((map)->l_info[DT_##RELOC]) \
122 ranges[0].start = (map)->l_info[DT_##RELOC]->d_un.d_ptr; \
123 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
126 if ((do_lazy) \
127 && (map)->l_info[DT_PLTREL] \
128 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
130 ranges[1].start = (map)->l_info[DT_JMPREL]->d_un.d_ptr; \
131 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
132 ranges[2].start = ranges[1].start + ranges[1].size; \
133 ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start; \
134 ranges[0].size = ranges[1].start - ranges[0].start; \
137 for (ranges_index = 0; ranges_index < 3; ++ranges_index) \
138 elf_dynamic_do_##reloc ((map), \
139 ranges[ranges_index].start, \
140 ranges[ranges_index].size, \
141 ranges[ranges_index].lazy); \
142 } while (0)
143 # else
144 # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
145 do { \
146 struct { ElfW(Addr) start, size; int lazy; } ranges[2]; \
147 int ranges_index; \
148 ranges[0].lazy = 0; \
149 ranges[0].size = ranges[1].size = 0; \
150 ranges[0].start = 0; \
152 if ((map)->l_info[DT_##RELOC]) \
154 ranges[0].start = (map)->l_info[DT_##RELOC]->d_un.d_ptr; \
155 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
157 if ((map)->l_info[DT_PLTREL] \
158 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
160 ElfW(Addr) start = (map)->l_info[DT_JMPREL]->d_un.d_ptr; \
162 if ((do_lazy) \
163 /* This test does not only detect whether the relocation \
164 sections are in the right order, it also checks whether \
165 there is a DT_REL/DT_RELA section. */ \
166 || ranges[0].start + ranges[0].size != start) \
168 ranges[1].start = start; \
169 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
170 ranges[1].lazy = (do_lazy); \
172 else \
173 /* Combine processing the sections. */ \
174 ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
177 for (ranges_index = 0; ranges_index < 2; ++ranges_index) \
178 elf_dynamic_do_##reloc ((map), \
179 ranges[ranges_index].start, \
180 ranges[ranges_index].size, \
181 ranges[ranges_index].lazy); \
182 } while (0)
183 # endif
185 # if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
186 # define _ELF_CHECK_REL 0
187 # else
188 # define _ELF_CHECK_REL 1
189 # endif
191 # if ! ELF_MACHINE_NO_REL
192 # include "do-rel.h"
193 # define ELF_DYNAMIC_DO_REL(map, lazy) \
194 _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, _ELF_CHECK_REL)
195 # else
196 # define ELF_DYNAMIC_DO_REL(map, lazy) /* Nothing to do. */
197 # endif
199 # if ! ELF_MACHINE_NO_RELA
200 # define DO_RELA
201 # include "do-rel.h"
202 # define ELF_DYNAMIC_DO_RELA(map, lazy) \
203 _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, _ELF_CHECK_REL)
204 # else
205 # define ELF_DYNAMIC_DO_RELA(map, lazy) /* Nothing to do. */
206 # endif
208 /* This can't just be an inline function because GCC is too dumb
209 to inline functions containing inlines themselves. */
210 # define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \
211 do { \
212 int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \
213 (consider_profile)); \
214 ELF_DYNAMIC_DO_REL ((map), edr_lazy); \
215 ELF_DYNAMIC_DO_RELA ((map), edr_lazy); \
216 } while (0)
218 #endif