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