1 /* Inline functions for dynamic linking.
2 Copyright (C) 1995-2002, 2003 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
24 auto void __attribute__((always_inline
))
25 elf_machine_rel (struct link_map
*map
, const ElfW(Rel
) *reloc
,
26 const ElfW(Sym
) *sym
, const struct r_found_version
*version
,
27 ElfW(Addr
) *const reloc_addr
);
28 auto void __attribute__((always_inline
))
29 elf_machine_rela (struct link_map
*map
, const ElfW(Rela
) *reloc
,
30 const ElfW(Sym
) *sym
, const struct r_found_version
*version
,
31 ElfW(Addr
) *const reloc_addr
);
32 auto void __attribute__((always_inline
))
33 elf_machine_rel_relative (ElfW(Addr
) l_addr
, const ElfW(Rel
) *reloc
,
34 ElfW(Addr
) *const reloc_addr
);
35 auto void __attribute__((always_inline
))
36 elf_machine_rela_relative (ElfW(Addr
) l_addr
, const ElfW(Rela
) *reloc
,
37 ElfW(Addr
) *const reloc_addr
);
38 # if ELF_MACHINE_NO_RELA || defined ELF_MACHINE_PLT_REL
39 auto void __attribute__((always_inline
))
40 elf_machine_lazy_rel (struct link_map
*map
,
41 ElfW(Addr
) l_addr
, const ElfW(Rel
) *reloc
);
43 auto void __attribute__((always_inline
))
44 elf_machine_lazy_rel (struct link_map
*map
,
45 ElfW(Addr
) l_addr
, const ElfW(Rela
) *reloc
);
49 #include <dl-machine.h>
52 # define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
56 /* Read the dynamic section at DYN and fill in INFO with indices DT_*. */
58 static inline void __attribute__ ((unused
, always_inline
))
59 elf_get_dynamic_info (struct link_map
*l
)
61 ElfW(Dyn
) *dyn
= l
->l_ld
;
64 #ifndef RTLD_BOOTSTRAP
71 while (dyn
->d_tag
!= DT_NULL
)
73 if (dyn
->d_tag
< DT_NUM
)
74 info
[dyn
->d_tag
] = dyn
;
75 else if (dyn
->d_tag
>= DT_LOPROC
&&
76 dyn
->d_tag
< DT_LOPROC
+ DT_THISPROCNUM
)
77 info
[dyn
->d_tag
- DT_LOPROC
+ DT_NUM
] = dyn
;
78 else if ((Elf32_Word
) DT_VERSIONTAGIDX (dyn
->d_tag
) < DT_VERSIONTAGNUM
)
79 info
[VERSYMIDX (dyn
->d_tag
)] = dyn
;
80 else if ((Elf32_Word
) DT_EXTRATAGIDX (dyn
->d_tag
) < DT_EXTRANUM
)
81 info
[DT_EXTRATAGIDX (dyn
->d_tag
) + DT_NUM
+ DT_THISPROCNUM
82 + DT_VERSIONTAGNUM
] = dyn
;
83 else if ((Elf32_Word
) DT_VALTAGIDX (dyn
->d_tag
) < DT_VALNUM
)
84 info
[DT_VALTAGIDX (dyn
->d_tag
) + DT_NUM
+ DT_THISPROCNUM
85 + DT_VERSIONTAGNUM
+ DT_EXTRANUM
] = dyn
;
86 else if ((Elf32_Word
) DT_ADDRTAGIDX (dyn
->d_tag
) < DT_ADDRNUM
)
87 info
[DT_ADDRTAGIDX (dyn
->d_tag
) + DT_NUM
+ DT_THISPROCNUM
88 + DT_VERSIONTAGNUM
+ DT_EXTRANUM
+ DT_VALNUM
] = dyn
;
91 #ifndef DL_RO_DYN_SECTION
92 /* Don't adjust .dynamic unnecessarily. */
95 ElfW(Addr
) l_addr
= l
->l_addr
;
97 if (info
[DT_HASH
] != NULL
)
98 info
[DT_HASH
]->d_un
.d_ptr
+= l_addr
;
99 if (info
[DT_PLTGOT
] != NULL
)
100 info
[DT_PLTGOT
]->d_un
.d_ptr
+= l_addr
;
101 if (info
[DT_STRTAB
] != NULL
)
102 info
[DT_STRTAB
]->d_un
.d_ptr
+= l_addr
;
103 if (info
[DT_SYMTAB
] != NULL
)
104 info
[DT_SYMTAB
]->d_un
.d_ptr
+= l_addr
;
105 # if ! ELF_MACHINE_NO_RELA
106 if (info
[DT_RELA
] != NULL
)
107 info
[DT_RELA
]->d_un
.d_ptr
+= l_addr
;
109 # if ! ELF_MACHINE_NO_REL
110 if (info
[DT_REL
] != NULL
)
111 info
[DT_REL
]->d_un
.d_ptr
+= l_addr
;
113 if (info
[DT_JMPREL
] != NULL
)
114 info
[DT_JMPREL
]->d_un
.d_ptr
+= l_addr
;
115 if (info
[VERSYMIDX (DT_VERSYM
)] != NULL
)
116 info
[VERSYMIDX (DT_VERSYM
)]->d_un
.d_ptr
+= l_addr
;
119 if (info
[DT_PLTREL
] != NULL
)
121 #if ELF_MACHINE_NO_RELA
122 assert (info
[DT_PLTREL
]->d_un
.d_val
== DT_REL
);
123 #elif ELF_MACHINE_NO_REL
124 assert (info
[DT_PLTREL
]->d_un
.d_val
== DT_RELA
);
126 assert (info
[DT_PLTREL
]->d_un
.d_val
== DT_REL
127 || info
[DT_PLTREL
]->d_un
.d_val
== DT_RELA
);
130 #if ! ELF_MACHINE_NO_RELA
131 if (info
[DT_RELA
] != NULL
)
132 assert (info
[DT_RELAENT
]->d_un
.d_val
== sizeof (ElfW(Rela
)));
134 # if ! ELF_MACHINE_NO_REL
135 if (info
[DT_REL
] != NULL
)
136 assert (info
[DT_RELENT
]->d_un
.d_val
== sizeof (ElfW(Rel
)));
138 if (info
[DT_FLAGS
] != NULL
)
140 /* Flags are used. Translate to the old form where available.
141 Since these l_info entries are only tested for NULL pointers it
142 is ok if they point to the DT_FLAGS entry. */
143 l
->l_flags
= info
[DT_FLAGS
]->d_un
.d_val
;
144 #ifdef RTLD_BOOTSTRAP
145 /* These three flags must not be set for ld.so. */
146 assert ((l
->l_flags
& (DF_SYMBOLIC
| DF_TEXTREL
| DF_BIND_NOW
)) == 0);
148 if (l
->l_flags
& DF_SYMBOLIC
)
149 info
[DT_SYMBOLIC
] = info
[DT_FLAGS
];
150 if (l
->l_flags
& DF_TEXTREL
)
151 info
[DT_TEXTREL
] = info
[DT_FLAGS
];
152 if (l
->l_flags
& DF_BIND_NOW
)
153 info
[DT_BIND_NOW
] = info
[DT_FLAGS
];
156 if (info
[VERSYMIDX (DT_FLAGS_1
)] != NULL
)
157 l
->l_flags_1
= info
[VERSYMIDX (DT_FLAGS_1
)]->d_un
.d_val
;
158 #ifdef RTLD_BOOTSTRAP
159 /* The dynamic linker should have none of these set. */
160 assert (info
[DT_RUNPATH
] == NULL
);
161 assert (info
[DT_RPATH
] == NULL
);
163 if (info
[DT_RUNPATH
] != NULL
)
164 /* If both RUNPATH and RPATH are given, the latter is ignored. */
165 info
[DT_RPATH
] = NULL
;
171 # ifdef RTLD_BOOTSTRAP
172 # define ELF_DURING_STARTUP (1)
174 # define ELF_DURING_STARTUP (0)
177 /* Get the definitions of `elf_dynamic_do_rel' and `elf_dynamic_do_rela'.
178 These functions are almost identical, so we use cpp magic to avoid
179 duplicating their code. It cannot be done in a more general function
180 because we must be able to completely inline. */
182 /* On some machines, notably SPARC, DT_REL* includes DT_JMPREL in its
183 range. Note that according to the ELF spec, this is completely legal!
184 But conditionally define things so that on machines we know this will
185 not happen we do something more optimal. */
187 # ifdef ELF_MACHINE_PLTREL_OVERLAP
188 # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
190 struct { ElfW(Addr) start, size; int lazy; } ranges[3]; \
193 ranges[0].lazy = ranges[2].lazy = 0; \
194 ranges[1].lazy = 1; \
195 ranges[0].size = ranges[1].size = ranges[2].size = 0; \
197 if ((map)->l_info[DT_##RELOC]) \
199 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
200 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
204 && (map)->l_info[DT_PLTREL] \
205 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
207 ranges[1].start = D_PTR ((map), l_info[DT_JMPREL]); \
208 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
209 ranges[2].start = ranges[1].start + ranges[1].size; \
210 ranges[2].size = ranges[0].start + ranges[0].size - ranges[2].start; \
211 ranges[0].size = ranges[1].start - ranges[0].start; \
214 for (ranges_index = 0; ranges_index < 3; ++ranges_index) \
215 elf_dynamic_do_##reloc ((map), \
216 ranges[ranges_index].start, \
217 ranges[ranges_index].size, \
218 ranges[ranges_index].lazy); \
221 # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, do_lazy, test_rel) \
223 struct { ElfW(Addr) start, size; int lazy; } ranges[2]; \
224 ranges[0].lazy = 0; \
225 ranges[0].size = ranges[1].size = 0; \
226 ranges[0].start = 0; \
228 if ((map)->l_info[DT_##RELOC]) \
230 ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
231 ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
233 if ((map)->l_info[DT_PLTREL] \
234 && (!test_rel || (map)->l_info[DT_PLTREL]->d_un.d_val == DT_##RELOC)) \
236 ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
238 if (! ELF_DURING_STARTUP \
240 /* This test does not only detect whether the relocation \
241 sections are in the right order, it also checks whether \
242 there is a DT_REL/DT_RELA section. */ \
243 || ranges[0].start + ranges[0].size != start)) \
245 ranges[1].start = start; \
246 ranges[1].size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
247 ranges[1].lazy = (do_lazy); \
251 /* Combine processing the sections. */ \
252 assert (ranges[0].start + ranges[0].size == start); \
253 ranges[0].size += (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
257 if (ELF_DURING_STARTUP) \
258 elf_dynamic_do_##reloc ((map), ranges[0].start, ranges[0].size, 0); \
262 for (ranges_index = 0; ranges_index < 2; ++ranges_index) \
263 elf_dynamic_do_##reloc ((map), \
264 ranges[ranges_index].start, \
265 ranges[ranges_index].size, \
266 ranges[ranges_index].lazy); \
271 # if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
272 # define _ELF_CHECK_REL 0
274 # define _ELF_CHECK_REL 1
277 # if ! ELF_MACHINE_NO_REL
279 # define ELF_DYNAMIC_DO_REL(map, lazy) \
280 _ELF_DYNAMIC_DO_RELOC (REL, rel, map, lazy, _ELF_CHECK_REL)
282 # define ELF_DYNAMIC_DO_REL(map, lazy) /* Nothing to do. */
285 # if ! ELF_MACHINE_NO_RELA
288 # define ELF_DYNAMIC_DO_RELA(map, lazy) \
289 _ELF_DYNAMIC_DO_RELOC (RELA, rela, map, lazy, _ELF_CHECK_REL)
291 # define ELF_DYNAMIC_DO_RELA(map, lazy) /* Nothing to do. */
294 /* This can't just be an inline function because GCC is too dumb
295 to inline functions containing inlines themselves. */
296 # define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile) \
298 int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \
299 (consider_profile)); \
300 ELF_DYNAMIC_DO_REL ((map), edr_lazy); \
301 ELF_DYNAMIC_DO_RELA ((map), edr_lazy); \