hppa_reloc.c revision 1.24 1 1.24 skrll /* $NetBSD: hppa_reloc.c,v 1.24 2006/10/17 08:28:06 skrll Exp $ */
2 1.1 fredette
3 1.1 fredette /*-
4 1.21 skrll * Copyright (c) 2002, 2004 The NetBSD Foundation, Inc.
5 1.1 fredette * All rights reserved.
6 1.1 fredette *
7 1.1 fredette * This code is derived from software contributed to The NetBSD Foundation
8 1.21 skrll * by Matt Fredette and Nick Hudson.
9 1.1 fredette *
10 1.1 fredette * Redistribution and use in source and binary forms, with or without
11 1.1 fredette * modification, are permitted provided that the following conditions
12 1.1 fredette * are met:
13 1.1 fredette * 1. Redistributions of source code must retain the above copyright
14 1.1 fredette * notice, this list of conditions and the following disclaimer.
15 1.1 fredette * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 fredette * notice, this list of conditions and the following disclaimer in the
17 1.1 fredette * documentation and/or other materials provided with the distribution.
18 1.1 fredette * 3. All advertising materials mentioning features or use of this software
19 1.1 fredette * must display the following acknowledgement:
20 1.1 fredette * This product includes software developed by the NetBSD
21 1.1 fredette * Foundation, Inc. and its contributors.
22 1.1 fredette * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.1 fredette * contributors may be used to endorse or promote products derived
24 1.1 fredette * from this software without specific prior written permission.
25 1.1 fredette *
26 1.1 fredette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.1 fredette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.1 fredette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.1 fredette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.1 fredette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.1 fredette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.1 fredette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.1 fredette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.1 fredette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.1 fredette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.1 fredette * POSSIBILITY OF SUCH DAMAGE.
37 1.1 fredette */
38 1.1 fredette
39 1.23 skrll #include <sys/cdefs.h>
40 1.23 skrll #ifndef lint
41 1.24 skrll __RCSID("$NetBSD: hppa_reloc.c,v 1.24 2006/10/17 08:28:06 skrll Exp $");
42 1.23 skrll #endif /* not lint */
43 1.23 skrll
44 1.1 fredette #include <stdlib.h>
45 1.1 fredette #include <sys/types.h>
46 1.1 fredette #include <sys/stat.h>
47 1.1 fredette #include <sys/queue.h>
48 1.1 fredette
49 1.24 skrll #include <string.h>
50 1.24 skrll
51 1.1 fredette #include "rtld.h"
52 1.1 fredette #include "debug.h"
53 1.1 fredette
54 1.1 fredette #ifdef RTLD_DEBUG_HPPA
55 1.14 mycroft #define hdbg(x) xprintf x
56 1.1 fredette #else
57 1.1 fredette #define hdbg(x) /* nothing */
58 1.1 fredette #endif
59 1.12 mycroft
60 1.20 skrll caddr_t _rtld_bind(const Obj_Entry *, const Elf_Addr);
61 1.12 mycroft void _rtld_bind_start(void);
62 1.13 mycroft void __rtld_setup_hppa_pltgot(const Obj_Entry *, Elf_Addr *);
63 1.1 fredette
64 1.1 fredette /*
65 1.24 skrll * It is possible for the compiler to emit relocations for unaligned data.
66 1.24 skrll * We handle this situation with these inlines.
67 1.24 skrll */
68 1.24 skrll #define RELOC_ALIGNED_P(x) \
69 1.24 skrll (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0)
70 1.24 skrll
71 1.24 skrll static inline Elf_Addr
72 1.24 skrll load_ptr(void *where)
73 1.24 skrll {
74 1.24 skrll if (__predict_true(RELOC_ALIGNED_P(where)))
75 1.24 skrll return *(Elf_Addr *)where;
76 1.24 skrll else {
77 1.24 skrll Elf_Addr res;
78 1.24 skrll
79 1.24 skrll (void)memcpy(&res, where, sizeof(res));
80 1.24 skrll return res;
81 1.24 skrll }
82 1.24 skrll }
83 1.24 skrll
84 1.24 skrll static inline void
85 1.24 skrll store_ptr(void *where, Elf_Addr val)
86 1.24 skrll {
87 1.24 skrll if (__predict_true(RELOC_ALIGNED_P(where)))
88 1.24 skrll *(Elf_Addr *)where = val;
89 1.24 skrll else
90 1.24 skrll (void)memcpy(where, &val, sizeof(val));
91 1.24 skrll }
92 1.24 skrll
93 1.24 skrll /*
94 1.1 fredette * In the runtime architecture (ABI), PLABEL function
95 1.1 fredette * pointers are distinguished from normal function
96 1.1 fredette * pointers by having the next-least-significant bit
97 1.1 fredette * set. (This bit is referred to as the L field in
98 1.1 fredette * HP documentation). The $$dyncall millicode is
99 1.1 fredette * aware of this.
100 1.1 fredette */
101 1.1 fredette #define RTLD_MAKE_PLABEL(plabel) (((Elf_Addr)(plabel)) | (1 << 1))
102 1.1 fredette #define RTLD_IS_PLABEL(addr) (((Elf_Addr)(addr)) & (1 << 1))
103 1.1 fredette #define RTLD_GET_PLABEL(addr) ((hppa_plabel *) (((Elf_Addr)addr) & ~3))
104 1.1 fredette
105 1.1 fredette /*
106 1.1 fredette * This is the PLABEL structure. The function PC and
107 1.1 fredette * shared linkage members must come first, as they are
108 1.1 fredette * the actual PLABEL.
109 1.1 fredette */
110 1.1 fredette typedef struct _hppa_plabel {
111 1.1 fredette Elf_Addr hppa_plabel_pc;
112 1.1 fredette Elf_Addr hppa_plabel_sl;
113 1.1 fredette SLIST_ENTRY(_hppa_plabel) hppa_plabel_next;
114 1.1 fredette } hppa_plabel;
115 1.1 fredette
116 1.1 fredette /*
117 1.1 fredette * For now allocated PLABEL structures are tracked on a
118 1.1 fredette * singly linked list. This maybe should be revisited.
119 1.1 fredette */
120 1.1 fredette static SLIST_HEAD(hppa_plabel_head, _hppa_plabel) hppa_plabel_list
121 1.1 fredette = SLIST_HEAD_INITIALIZER(hppa_plabel_list);
122 1.1 fredette
123 1.1 fredette /*
124 1.1 fredette * Because I'm hesitant to use NEW while relocating self,
125 1.1 fredette * this is a small pool of preallocated PLABELs.
126 1.1 fredette */
127 1.20 skrll #define HPPA_PLABEL_PRE (12)
128 1.1 fredette static hppa_plabel hppa_plabel_pre[HPPA_PLABEL_PRE];
129 1.1 fredette static int hppa_plabel_pre_next = 0;
130 1.1 fredette
131 1.20 skrll void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr);
132 1.20 skrll int _rtld_relocate_plt_objects(const Obj_Entry *);
133 1.1 fredette /*
134 1.1 fredette * This bootstraps the dynamic linker by relocating its GOT.
135 1.1 fredette * On the hppa, unlike on other architectures, static strings
136 1.1 fredette * are found through the GOT. Static strings are essential
137 1.1 fredette * for RTLD_DEBUG, and I suspect they're used early even when
138 1.1 fredette * !defined(RTLD_DEBUG), making relocating the GOT essential.
139 1.1 fredette *
140 1.1 fredette * It gets worse. Relocating the GOT doesn't mean just walking
141 1.1 fredette * it and adding the relocbase to all of the entries. You must
142 1.1 fredette * find and use the GOT relocations, since those RELA relocations
143 1.1 fredette * have the necessary addends - the GOT comes initialized as
144 1.1 fredette * zeroes.
145 1.1 fredette */
146 1.1 fredette void
147 1.20 skrll _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase)
148 1.1 fredette {
149 1.1 fredette const Elf_Rela *relafirst, *rela, *relalim;
150 1.22 chs Elf_Addr relasz;
151 1.24 skrll void *where;
152 1.20 skrll Elf_Addr *pltgot;
153 1.20 skrll const Elf_Rela *plabel_relocs[HPPA_PLABEL_PRE];
154 1.20 skrll int nplabel_relocs = 0;
155 1.20 skrll int i;
156 1.20 skrll const Elf_Sym *symtab, *sym;
157 1.20 skrll unsigned long symnum;
158 1.20 skrll hppa_plabel *plabel;
159 1.1 fredette
160 1.22 chs /*
161 1.22 chs * Process the DYNAMIC section, looking for the non-PLT relocations.
162 1.1 fredette */
163 1.1 fredette relafirst = NULL;
164 1.22 chs relasz = 0;
165 1.22 chs symtab = NULL;
166 1.22 chs pltgot = NULL;
167 1.1 fredette for (; dynp->d_tag != DT_NULL; ++dynp) {
168 1.1 fredette switch (dynp->d_tag) {
169 1.1 fredette
170 1.1 fredette case DT_RELA:
171 1.1 fredette relafirst = (const Elf_Rela *)
172 1.1 fredette (relocbase + dynp->d_un.d_ptr);
173 1.1 fredette break;
174 1.1 fredette
175 1.1 fredette case DT_RELASZ:
176 1.1 fredette relasz = dynp->d_un.d_val;
177 1.1 fredette break;
178 1.20 skrll
179 1.20 skrll case DT_SYMTAB:
180 1.20 skrll symtab = (const Elf_Sym *)
181 1.20 skrll (relocbase + dynp->d_un.d_ptr);
182 1.20 skrll break;
183 1.20 skrll
184 1.20 skrll case DT_PLTGOT:
185 1.20 skrll pltgot = (Elf_Addr *)
186 1.20 skrll (relocbase + dynp->d_un.d_ptr);
187 1.20 skrll break;
188 1.1 fredette }
189 1.1 fredette }
190 1.1 fredette relalim = (const Elf_Rela *)((caddr_t)relafirst + relasz);
191 1.1 fredette
192 1.18 skrll for (rela = relafirst; rela < relalim; rela++) {
193 1.20 skrll symnum = ELF_R_SYM(rela->r_info);
194 1.24 skrll where = (void *)(relocbase + rela->r_offset);
195 1.20 skrll
196 1.20 skrll switch (ELF_R_TYPE(rela->r_info)) {
197 1.20 skrll case R_TYPE(DIR32):
198 1.20 skrll if (symnum == 0)
199 1.24 skrll store_ptr(where,
200 1.24 skrll relocbase + rela->r_addend);
201 1.20 skrll else {
202 1.20 skrll sym = symtab + symnum;
203 1.24 skrll store_ptr(where,
204 1.24 skrll relocbase + rela->r_addend + sym->st_value);
205 1.20 skrll }
206 1.20 skrll break;
207 1.20 skrll
208 1.20 skrll case R_TYPE(PLABEL32):
209 1.20 skrll /*
210 1.20 skrll * PLABEL32 relocation processing is done in two phases
211 1.20 skrll *
212 1.20 skrll * i) local function relocations (symbol number == 0)
213 1.20 skrll * can be resolved immediately.
214 1.20 skrll *
215 1.20 skrll * ii) external function relocations are deferred until
216 1.20 skrll * we finish all other relocations so that global
217 1.20 skrll * data isn't accessed until all other non-PLT
218 1.20 skrll * relocations have been done.
219 1.20 skrll */
220 1.20 skrll if (symnum == 0)
221 1.20 skrll *((Elf_Addr *)where) =
222 1.20 skrll relocbase + rela->r_addend;
223 1.20 skrll else
224 1.20 skrll plabel_relocs[nplabel_relocs++] = rela;
225 1.20 skrll break;
226 1.20 skrll
227 1.20 skrll default:
228 1.20 skrll break;
229 1.20 skrll }
230 1.1 fredette }
231 1.1 fredette
232 1.20 skrll assert(nplabel_relocs < HPPA_PLABEL_PRE);
233 1.20 skrll for (i = 0; i < nplabel_relocs; i++) {
234 1.20 skrll rela = plabel_relocs[i];
235 1.24 skrll where = (void *)(relocbase + rela->r_offset);
236 1.20 skrll sym = symtab + ELF_R_SYM(rela->r_info);
237 1.20 skrll
238 1.20 skrll plabel = &hppa_plabel_pre[hppa_plabel_pre_next++];
239 1.20 skrll
240 1.20 skrll plabel->hppa_plabel_pc = (Elf_Addr)
241 1.20 skrll (relocbase + sym->st_value + rela->r_addend);
242 1.20 skrll plabel->hppa_plabel_sl = (Elf_Addr)pltgot;
243 1.20 skrll
244 1.20 skrll SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next);
245 1.20 skrll *((Elf_Addr *)where) = (Elf_Addr)(RTLD_MAKE_PLABEL(plabel));
246 1.20 skrll }
247 1.20 skrll
248 1.1 fredette #if defined(RTLD_DEBUG_HPPA)
249 1.18 skrll for (rela = relafirst; rela < relalim; rela++) {
250 1.24 skrll where = (void *)(relocbase + rela->r_offset);
251 1.20 skrll
252 1.20 skrll switch (ELF_R_TYPE(rela->r_info)) {
253 1.20 skrll case R_TYPE(DIR32):
254 1.20 skrll hdbg(("DIR32 rela @%p(%p) -> %p(%p)\n",
255 1.1 fredette (void *)rela->r_offset,
256 1.1 fredette (void *)where,
257 1.1 fredette (void *)rela->r_addend,
258 1.20 skrll (void *)*((Elf_Addr *)where) ));
259 1.20 skrll break;
260 1.20 skrll
261 1.20 skrll case R_TYPE(PLABEL32):
262 1.20 skrll symnum = ELF_R_SYM(rela->r_info);
263 1.20 skrll if (symnum == 0) {
264 1.20 skrll hdbg(("PLABEL rela @%p(%p) -> %p(%p)\n",
265 1.20 skrll (void *)rela->r_offset,
266 1.20 skrll (void *)where,
267 1.20 skrll (void *)rela->r_addend,
268 1.20 skrll (void *)*((Elf_Addr *)where) ));
269 1.20 skrll } else {
270 1.20 skrll sym = symtab + symnum;
271 1.20 skrll
272 1.20 skrll hdbg(("PLABEL32 rela @%p(%p), symnum=%ld(%p) -> %p(%p)\n",
273 1.20 skrll (void *)rela->r_offset,
274 1.20 skrll (void *)where,
275 1.20 skrll symnum,
276 1.20 skrll (void *)sym->st_value,
277 1.20 skrll (void *)rela->r_addend,
278 1.20 skrll (void *)*((Elf_Addr *)where) ));
279 1.20 skrll }
280 1.20 skrll break;
281 1.20 skrll default:
282 1.20 skrll hdbg(("rela XXX reloc\n"));
283 1.20 skrll break;
284 1.20 skrll }
285 1.1 fredette }
286 1.1 fredette #endif /* RTLD_DEBUG_HPPA */
287 1.1 fredette }
288 1.1 fredette
289 1.1 fredette /*
290 1.1 fredette * This allocates a PLABEL. If called with a non-NULL def, the
291 1.1 fredette * plabel is for the function associated with that definition
292 1.1 fredette * in the defining object defobj, plus the given addend. If
293 1.1 fredette * called with a NULL def, the plabel is for the function at
294 1.1 fredette * the (unrelocated) address in addend in the object defobj.
295 1.1 fredette */
296 1.1 fredette Elf_Addr
297 1.1 fredette _rtld_function_descriptor_alloc(const Obj_Entry *defobj, const Elf_Sym *def,
298 1.1 fredette Elf_Addr addend)
299 1.1 fredette {
300 1.1 fredette Elf_Addr func_pc, func_sl;
301 1.1 fredette hppa_plabel *plabel;
302 1.1 fredette
303 1.1 fredette if (def != NULL) {
304 1.1 fredette
305 1.1 fredette /*
306 1.1 fredette * We assume that symbols of type STT_NOTYPE
307 1.1 fredette * are undefined. Return NULL for these.
308 1.1 fredette */
309 1.1 fredette if (ELF_ST_TYPE(def->st_info) == STT_NOTYPE)
310 1.1 fredette return (Elf_Addr)NULL;
311 1.1 fredette
312 1.1 fredette /* Otherwise assert that this symbol must be a function. */
313 1.1 fredette assert(ELF_ST_TYPE(def->st_info) == STT_FUNC);
314 1.1 fredette
315 1.1 fredette func_pc = (Elf_Addr)(defobj->relocbase + def->st_value +
316 1.1 fredette addend);
317 1.1 fredette } else
318 1.1 fredette func_pc = (Elf_Addr)(defobj->relocbase + addend);
319 1.1 fredette
320 1.1 fredette /*
321 1.1 fredette * Search the existing PLABELs for one matching
322 1.1 fredette * this function. If there is one, return it.
323 1.1 fredette */
324 1.20 skrll func_sl = (Elf_Addr)(defobj->pltgot);
325 1.1 fredette SLIST_FOREACH(plabel, &hppa_plabel_list, hppa_plabel_next)
326 1.1 fredette if (plabel->hppa_plabel_pc == func_pc &&
327 1.1 fredette plabel->hppa_plabel_sl == func_sl)
328 1.1 fredette return RTLD_MAKE_PLABEL(plabel);
329 1.1 fredette
330 1.1 fredette /*
331 1.1 fredette * Once we've used up the preallocated set, we start
332 1.1 fredette * using NEW to allocate plabels.
333 1.1 fredette */
334 1.1 fredette if (hppa_plabel_pre_next < HPPA_PLABEL_PRE)
335 1.1 fredette plabel = &hppa_plabel_pre[hppa_plabel_pre_next++];
336 1.1 fredette else {
337 1.1 fredette plabel = NEW(hppa_plabel);
338 1.1 fredette if (plabel == NULL)
339 1.1 fredette return (Elf_Addr)-1;
340 1.1 fredette }
341 1.1 fredette
342 1.1 fredette /* Fill the new entry and insert it on the list. */
343 1.1 fredette plabel->hppa_plabel_pc = func_pc;
344 1.1 fredette plabel->hppa_plabel_sl = func_sl;
345 1.1 fredette SLIST_INSERT_HEAD(&hppa_plabel_list, plabel, hppa_plabel_next);
346 1.1 fredette
347 1.1 fredette return RTLD_MAKE_PLABEL(plabel);
348 1.1 fredette }
349 1.1 fredette
350 1.1 fredette /*
351 1.1 fredette * If a pointer is a PLABEL, this unwraps it.
352 1.1 fredette */
353 1.1 fredette const void *
354 1.1 fredette _rtld_function_descriptor_function(const void *addr)
355 1.1 fredette {
356 1.1 fredette return (RTLD_IS_PLABEL(addr) ?
357 1.1 fredette (const void *) RTLD_GET_PLABEL(addr)->hppa_plabel_pc :
358 1.1 fredette addr);
359 1.1 fredette }
360 1.1 fredette
361 1.2 mycroft /* This sets up an object's GOT. */
362 1.2 mycroft void
363 1.2 mycroft _rtld_setup_pltgot(const Obj_Entry *obj)
364 1.2 mycroft {
365 1.20 skrll __rtld_setup_hppa_pltgot(obj, obj->pltgot);
366 1.4 mycroft }
367 1.4 mycroft
368 1.4 mycroft int
369 1.16 skrll _rtld_relocate_nonplt_objects(const Obj_Entry *obj)
370 1.4 mycroft {
371 1.5 mycroft const Elf_Rela *rela;
372 1.5 mycroft
373 1.5 mycroft for (rela = obj->rela; rela < obj->relalim; rela++) {
374 1.5 mycroft Elf_Addr *where;
375 1.5 mycroft const Elf_Sym *def;
376 1.5 mycroft const Obj_Entry *defobj;
377 1.5 mycroft Elf_Addr tmp;
378 1.6 mycroft unsigned long symnum;
379 1.5 mycroft
380 1.5 mycroft where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
381 1.6 mycroft symnum = ELF_R_SYM(rela->r_info);
382 1.5 mycroft
383 1.5 mycroft switch (ELF_R_TYPE(rela->r_info)) {
384 1.5 mycroft case R_TYPE(NONE):
385 1.5 mycroft break;
386 1.4 mycroft
387 1.5 mycroft case R_TYPE(DIR32):
388 1.6 mycroft if (symnum) {
389 1.5 mycroft /*
390 1.5 mycroft * This is either a DIR32 against a symbol
391 1.5 mycroft * (def->st_name != 0), or against a local
392 1.5 mycroft * section (def->st_name == 0).
393 1.5 mycroft */
394 1.6 mycroft def = obj->symtab + symnum;
395 1.5 mycroft defobj = obj;
396 1.5 mycroft if (def->st_name != 0)
397 1.6 mycroft def = _rtld_find_symdef(symnum, obj,
398 1.6 mycroft &defobj, false);
399 1.5 mycroft if (def == NULL)
400 1.5 mycroft return -1;
401 1.4 mycroft
402 1.5 mycroft tmp = (Elf_Addr)(defobj->relocbase +
403 1.5 mycroft def->st_value + rela->r_addend);
404 1.4 mycroft
405 1.24 skrll if (load_ptr(where) != tmp)
406 1.24 skrll store_ptr(where, tmp);
407 1.14 mycroft rdbg(("DIR32 %s in %s --> %p in %s",
408 1.7 mycroft obj->strtab + obj->symtab[symnum].st_name,
409 1.24 skrll obj->path, (void *)load_ptr(where), defobj->path));
410 1.5 mycroft } else {
411 1.5 mycroft tmp = (Elf_Addr)(obj->relocbase +
412 1.5 mycroft rela->r_addend);
413 1.5 mycroft
414 1.24 skrll if (load_ptr(where) != tmp)
415 1.24 skrll store_ptr(where, tmp);
416 1.20 skrll rdbg(("DIR32 in %s --> %p", obj->path,
417 1.24 skrll (void *)load_ptr(where)));
418 1.5 mycroft }
419 1.5 mycroft break;
420 1.5 mycroft
421 1.5 mycroft case R_TYPE(PLABEL32):
422 1.6 mycroft if (symnum) {
423 1.6 mycroft def = _rtld_find_symdef(symnum, obj, &defobj,
424 1.6 mycroft false);
425 1.5 mycroft if (def == NULL)
426 1.5 mycroft return -1;
427 1.4 mycroft
428 1.19 skrll tmp = _rtld_function_descriptor_alloc(defobj,
429 1.19 skrll def, rela->r_addend);
430 1.5 mycroft if (tmp == (Elf_Addr)-1)
431 1.5 mycroft return -1;
432 1.4 mycroft
433 1.4 mycroft if (*where != tmp)
434 1.4 mycroft *where = tmp;
435 1.14 mycroft rdbg(("PLABEL32 %s in %s --> %p in %s",
436 1.7 mycroft obj->strtab + obj->symtab[symnum].st_name,
437 1.7 mycroft obj->path, (void *)*where, defobj->path));
438 1.5 mycroft } else {
439 1.5 mycroft /*
440 1.5 mycroft * This is a PLABEL for a static function, and
441 1.5 mycroft * the dynamic linker has both allocated a PLT
442 1.5 mycroft * entry for this function and told us where it
443 1.5 mycroft * is. We can safely use the PLT entry as the
444 1.5 mycroft * PLABEL because there should be no other
445 1.5 mycroft * PLABEL reloc referencing this function.
446 1.5 mycroft * This object should also have an IPLT
447 1.5 mycroft * relocation to initialize the PLT entry.
448 1.5 mycroft *
449 1.5 mycroft * The dynamic linker should also have ensured
450 1.5 mycroft * that the addend has the
451 1.5 mycroft * next-least-significant bit set; the
452 1.5 mycroft * $$dyncall millicode uses this to distinguish
453 1.5 mycroft * a PLABEL pointer from a plain function
454 1.5 mycroft * pointer.
455 1.5 mycroft */
456 1.19 skrll tmp = (Elf_Addr)
457 1.19 skrll (obj->relocbase + rela->r_addend);
458 1.5 mycroft
459 1.5 mycroft if (*where != tmp)
460 1.5 mycroft *where = tmp;
461 1.14 mycroft rdbg(("PLABEL32 in %s --> %p", obj->path,
462 1.14 mycroft (void *)*where));
463 1.5 mycroft }
464 1.5 mycroft break;
465 1.4 mycroft
466 1.5 mycroft case R_TYPE(COPY):
467 1.4 mycroft /*
468 1.5 mycroft * These are deferred until all other relocations have
469 1.5 mycroft * been done. All we do here is make sure that the
470 1.5 mycroft * COPY relocation is not in a shared library. They
471 1.5 mycroft * are allowed only in executable files.
472 1.4 mycroft */
473 1.10 mycroft if (obj->isdynamic) {
474 1.5 mycroft _rtld_error(
475 1.5 mycroft "%s: Unexpected R_COPY relocation in shared library",
476 1.5 mycroft obj->path);
477 1.4 mycroft return -1;
478 1.5 mycroft }
479 1.14 mycroft rdbg(("COPY (avoid in main)"));
480 1.5 mycroft break;
481 1.4 mycroft
482 1.5 mycroft default:
483 1.14 mycroft rdbg(("sym = %lu, type = %lu, offset = %p, "
484 1.5 mycroft "addend = %p, contents = %p, symbol = %s",
485 1.6 mycroft symnum, (u_long)ELF_R_TYPE(rela->r_info),
486 1.5 mycroft (void *)rela->r_offset, (void *)rela->r_addend,
487 1.24 skrll (void *)load_ptr(where),
488 1.6 mycroft obj->strtab + obj->symtab[symnum].st_name));
489 1.5 mycroft _rtld_error("%s: Unsupported relocation type %ld "
490 1.5 mycroft "in non-PLT relocations\n",
491 1.5 mycroft obj->path, (u_long) ELF_R_TYPE(rela->r_info));
492 1.4 mycroft return -1;
493 1.4 mycroft }
494 1.8 mycroft }
495 1.8 mycroft return 0;
496 1.8 mycroft }
497 1.8 mycroft
498 1.8 mycroft int
499 1.16 skrll _rtld_relocate_plt_lazy(const Obj_Entry *obj)
500 1.8 mycroft {
501 1.8 mycroft const Elf_Rela *rela;
502 1.8 mycroft
503 1.8 mycroft for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
504 1.8 mycroft Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
505 1.8 mycroft Elf_Addr func_pc, func_sl;
506 1.8 mycroft
507 1.8 mycroft assert(ELF_R_TYPE(rela->r_info) == R_TYPE(IPLT));
508 1.8 mycroft
509 1.8 mycroft /*
510 1.8 mycroft * If this is an IPLT reloc for a static function,
511 1.8 mycroft * fully resolve the PLT entry now.
512 1.8 mycroft */
513 1.8 mycroft if (ELF_R_SYM(rela->r_info) == 0) {
514 1.8 mycroft func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend);
515 1.20 skrll func_sl = (Elf_Addr)(obj->pltgot);
516 1.8 mycroft }
517 1.8 mycroft
518 1.8 mycroft /*
519 1.8 mycroft * Otherwise set up for lazy binding.
520 1.8 mycroft */
521 1.8 mycroft else {
522 1.8 mycroft /*
523 1.8 mycroft * This function pointer points to the PLT
524 1.8 mycroft * stub added by the linker, and instead of
525 1.8 mycroft * a shared linkage value, we stash this
526 1.8 mycroft * relocation's offset. The PLT stub has
527 1.8 mycroft * already been set up to transfer to
528 1.8 mycroft * _rtld_bind_start.
529 1.8 mycroft */
530 1.20 skrll func_pc = ((Elf_Addr)(obj->pltgot)) - 16;
531 1.19 skrll func_sl = (Elf_Addr)
532 1.20 skrll ((caddr_t)rela - (caddr_t)(obj->pltrela));
533 1.8 mycroft }
534 1.20 skrll rdbg(("lazy bind %s(%p) --> old=(%p,%p) new=(%p,%p)",
535 1.20 skrll obj->path,
536 1.20 skrll (void *)where,
537 1.20 skrll (void *)where[0], (void *)where[1],
538 1.20 skrll (void *)func_pc, (void *)func_sl));
539 1.8 mycroft
540 1.8 mycroft /*
541 1.8 mycroft * Fill this PLT entry and return.
542 1.8 mycroft */
543 1.8 mycroft where[0] = func_pc;
544 1.8 mycroft where[1] = func_sl;
545 1.4 mycroft }
546 1.4 mycroft return 0;
547 1.1 fredette }
548 1.20 skrll
549 1.20 skrll caddr_t
550 1.20 skrll _rtld_bind(const Obj_Entry *obj, Elf_Addr reloff)
551 1.20 skrll {
552 1.20 skrll const Elf_Rela *rela = (const Elf_Rela *)((caddr_t)obj->pltrela + reloff);
553 1.20 skrll Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
554 1.20 skrll const Elf_Sym *def;
555 1.20 skrll const Obj_Entry *defobj;
556 1.20 skrll Elf_Addr func_pc, func_sl;
557 1.20 skrll
558 1.20 skrll assert(ELF_R_TYPE(rela->r_info) == R_TYPE(IPLT));
559 1.20 skrll assert(ELF_R_SYM(rela->r_info) != 0);
560 1.20 skrll
561 1.20 skrll def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true);
562 1.20 skrll if (def == NULL)
563 1.20 skrll _rtld_die();
564 1.20 skrll
565 1.20 skrll func_pc = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend);
566 1.20 skrll func_sl = (Elf_Addr)(defobj->pltgot);
567 1.20 skrll
568 1.20 skrll rdbg(("bind now/fixup in %s --> old=(%p,%p) new=(%p,%p)",
569 1.20 skrll defobj->strtab + def->st_name,
570 1.20 skrll (void *)where[0], (void *)where[1],
571 1.20 skrll (void *)func_pc, (void *)func_sl));
572 1.20 skrll /*
573 1.20 skrll * Fill this PLT entry and return.
574 1.20 skrll */
575 1.20 skrll if (where[0] != func_pc)
576 1.20 skrll where[0] = func_pc;
577 1.20 skrll if (where[1] != func_sl)
578 1.20 skrll where[1] = func_sl;
579 1.20 skrll
580 1.20 skrll return (caddr_t)where;
581 1.20 skrll }
582 1.20 skrll
583 1.20 skrll int
584 1.20 skrll _rtld_relocate_plt_objects(const Obj_Entry *obj)
585 1.20 skrll {
586 1.20 skrll const Elf_Rela *rela;
587 1.20 skrll
588 1.20 skrll for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
589 1.20 skrll Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
590 1.20 skrll const Elf_Sym *def;
591 1.20 skrll const Obj_Entry *defobj;
592 1.20 skrll Elf_Addr func_pc, func_sl;
593 1.20 skrll
594 1.20 skrll assert(ELF_R_TYPE(rela->r_info) == R_TYPE(IPLT));
595 1.20 skrll
596 1.20 skrll if (ELF_R_SYM(rela->r_info) == 0) {
597 1.20 skrll func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend);
598 1.20 skrll func_sl = (Elf_Addr)(obj->pltgot);
599 1.20 skrll } else {
600 1.20 skrll def = _rtld_find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
601 1.20 skrll true);
602 1.20 skrll if (def == NULL)
603 1.20 skrll return -1;
604 1.20 skrll func_pc = (Elf_Addr)(defobj->relocbase + def->st_value +
605 1.20 skrll rela->r_addend);
606 1.20 skrll func_sl = (Elf_Addr)(defobj->pltgot);
607 1.20 skrll rdbg(("bind now/fixup in %s --> old=(%p,%p) new=(%p,%p)",
608 1.20 skrll defobj->strtab + def->st_name,
609 1.20 skrll (void *)where[0], (void *)where[1],
610 1.20 skrll (void *)func_pc, (void *)func_sl));
611 1.20 skrll }
612 1.20 skrll
613 1.20 skrll /*
614 1.20 skrll * Fill this PLT entry and return.
615 1.20 skrll */
616 1.20 skrll if (where[0] != func_pc)
617 1.20 skrll where[0] = func_pc;
618 1.20 skrll if (where[1] != func_sl)
619 1.20 skrll where[1] = func_sl;
620 1.20 skrll }
621 1.20 skrll return 0;
622 1.20 skrll }
623