hppa_reloc.c revision 1.47 1 /* $NetBSD: hppa_reloc.c,v 1.47 2020/05/16 16:43:00 skrll 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.47 2020/05/16 16:43:00 skrll 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
424 where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
425
426 unsigned long symnum = ELF_R_SYM(rela->r_info);
427 /* First, handle DIR32 and PLABEL32 without symbol. */
428 if (symnum == 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 if (last_symnum != symnum) {
478 last_symnum = symnum;
479 if (ELF_R_TYPE(rela->r_info) == R_TYPE(DIR32)) {
480 /*
481 * DIR32 relocation against local
482 * symbols are special...
483 */
484 def = obj->symtab + symnum;
485 defobj = obj;
486 if (def->st_name == 0)
487 break;
488 }
489 def = _rtld_find_symdef(symnum, obj, &defobj,
490 false);
491 if (def == NULL)
492 return -1;
493 }
494 break;
495 default:
496 break;
497 }
498
499 switch (ELF_R_TYPE(rela->r_info)) {
500 case R_TYPE(NONE):
501 break;
502
503 case R_TYPE(DIR32):
504 tmp = (Elf_Addr)(defobj->relocbase +
505 def->st_value + rela->r_addend);
506
507 if (load_ptr(where) != tmp)
508 store_ptr(where, tmp);
509 rdbg(("DIR32 %s in %s --> %p in %s",
510 obj->strtab + obj->symtab[symnum].st_name,
511 obj->path, (void *)load_ptr(where),
512 defobj->path));
513 break;
514
515 case R_TYPE(PLABEL32):
516 tmp = _rtld_function_descriptor_alloc(defobj,
517 def, rela->r_addend);
518 if (tmp == (Elf_Addr)-1)
519 return -1;
520
521 if (*where != tmp)
522 *where = tmp;
523 rdbg(("PLABEL32 %s in %s --> %p in %s",
524 obj->strtab + obj->symtab[symnum].st_name,
525 obj->path, (void *)*where, defobj->path));
526 break;
527
528 case R_TYPE(COPY):
529 /*
530 * These are deferred until all other relocations have
531 * been done. All we do here is make sure that the
532 * COPY relocation is not in a shared library. They
533 * are allowed only in executable files.
534 */
535 if (obj->isdynamic) {
536 _rtld_error(
537 "%s: Unexpected R_COPY relocation in shared library",
538 obj->path);
539 return -1;
540 }
541 rdbg(("COPY (avoid in main)"));
542 break;
543
544 case R_TYPE(TLS_TPREL32):
545 if (!defobj->tls_done && _rtld_tls_offset_allocate(obj))
546 return -1;
547
548 *where = (Elf_Addr)(defobj->tlsoffset + def->st_value +
549 rela->r_addend + sizeof(struct tls_tcb));
550
551 rdbg(("TPREL32 %s in %s --> %p in %s",
552 obj->strtab + obj->symtab[symnum].st_name,
553 obj->path, (void *)*where, defobj->path));
554 break;
555
556 case R_TYPE(TLS_DTPMOD32):
557 *where = (Elf_Addr)(defobj->tlsindex);
558
559 rdbg(("TLS_DTPMOD32 %s in %s --> %p",
560 obj->strtab + obj->symtab[symnum].st_name,
561 obj->path, (void *)*where));
562
563 break;
564
565 case R_TYPE(TLS_DTPOFF32):
566 *where = (Elf_Addr)(def->st_value);
567
568 rdbg(("TLS_DTPOFF32 %s in %s --> %p",
569 obj->strtab + obj->symtab[symnum].st_name,
570 obj->path, (void *)*where));
571
572 break;
573
574 default:
575 rdbg(("sym = %lu, type = %lu, offset = %p, "
576 "addend = %p, contents = %p, symbol = %s",
577 symnum, (u_long)ELF_R_TYPE(rela->r_info),
578 (void *)rela->r_offset, (void *)rela->r_addend,
579 (void *)load_ptr(where),
580 obj->strtab + obj->symtab[symnum].st_name));
581 _rtld_error("%s: Unsupported relocation type %ld "
582 "in non-PLT relocations",
583 obj->path, (u_long) ELF_R_TYPE(rela->r_info));
584 return -1;
585 }
586 }
587 return 0;
588 }
589
590 int
591 _rtld_relocate_plt_lazy(Obj_Entry *obj)
592 {
593 const Elf_Rela *rela;
594
595 for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) {
596 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
597 Elf_Addr func_pc, func_sl;
598
599 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(IPLT));
600
601 /*
602 * If this is an IPLT reloc for a static function,
603 * fully resolve the PLT entry now.
604 */
605 if (ELF_R_SYM(rela->r_info) == 0) {
606 func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend);
607 func_sl = (Elf_Addr)(obj->pltgot);
608 }
609
610 /*
611 * Otherwise set up for lazy binding.
612 */
613 else {
614 /*
615 * This function pointer points to the PLT
616 * stub added by the linker, and instead of
617 * a shared linkage value, we stash this
618 * relocation's offset. The PLT stub has
619 * already been set up to transfer to
620 * _rtld_bind_start.
621 */
622 func_pc = ((Elf_Addr)(obj->pltgot)) - 16;
623 func_sl = (Elf_Addr)
624 ((const char *)rela - (const char *)(obj->pltrela));
625 }
626 rdbg(("lazy bind %s(%p) --> old=(%p,%p) new=(%p,%p)",
627 obj->path,
628 (void *)where,
629 (void *)where[0], (void *)where[1],
630 (void *)func_pc, (void *)func_sl));
631
632 /*
633 * Fill this PLT entry and return.
634 */
635 where[0] = func_pc;
636 where[1] = func_sl;
637 }
638 return 0;
639 }
640
641 static inline int
642 _rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela,
643 Elf_Addr *tp)
644 {
645 Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset);
646 const Elf_Sym *def;
647 const Obj_Entry *defobj;
648 Elf_Addr func_pc, func_sl;
649 unsigned long info = rela->r_info;
650
651 assert(ELF_R_TYPE(info) == R_TYPE(IPLT));
652
653 if (ELF_R_SYM(info) == 0) {
654 func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend);
655 func_sl = (Elf_Addr)(obj->pltgot);
656 } else {
657 def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj,
658 tp != NULL);
659 if (__predict_false(def == NULL))
660 return -1;
661 if (__predict_false(def == &_rtld_sym_zero))
662 return 0;
663
664 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
665 if (tp == NULL)
666 return 0;
667 Elf_Addr ptr = _rtld_resolve_ifunc(defobj, def);
668 assert(RTLD_IS_PLABEL(ptr));
669 hppa_plabel *label = RTLD_GET_PLABEL(ptr);
670 func_pc = label->hppa_plabel_pc;
671 func_sl = label->hppa_plabel_sl;
672 } else {
673 func_pc = (Elf_Addr)(defobj->relocbase + def->st_value +
674 rela->r_addend);
675 func_sl = (Elf_Addr)(defobj->pltgot);
676 }
677
678 rdbg(("bind now/fixup in %s --> old=(%p,%p) new=(%p,%p)",
679 defobj->strtab + def->st_name,
680 (void *)where[0], (void *)where[1],
681 (void *)func_pc, (void *)func_sl));
682 }
683 /*
684 * Fill this PLT entry and return.
685 */
686 if (where[0] != func_pc)
687 where[0] = func_pc;
688 if (where[1] != func_sl)
689 where[1] = func_sl;
690
691 if (tp)
692 *tp = (Elf_Addr)where;
693
694 return 0;
695 }
696
697 caddr_t
698 _rtld_bind(const Obj_Entry *obj, Elf_Word reloff)
699 {
700 const Elf_Rela *rela;
701 Elf_Addr new_value = 0; /* XXX gcc */
702 int err;
703
704 rela = (const Elf_Rela *)((const char *)obj->pltrela + reloff);
705
706 assert(ELF_R_SYM(rela->r_info) != 0);
707
708 _rtld_shared_enter();
709 err = _rtld_relocate_plt_object(obj, rela, &new_value);
710 if (err)
711 _rtld_die();
712 _rtld_shared_exit();
713
714 return (caddr_t)new_value;
715 }
716
717 int
718 _rtld_relocate_plt_objects(const Obj_Entry *obj)
719 {
720 const Elf_Rela *rela = obj->pltrela;
721
722 for (; rela < obj->pltrelalim; rela++) {
723 if (_rtld_relocate_plt_object(obj, rela, NULL) < 0)
724 return -1;
725 }
726 return 0;
727 }
728
729 void
730 _rtld_call_function_void(const Obj_Entry *obj, Elf_Addr ptr)
731 {
732 volatile hppa_plabel plabel;
733 void (*f)(void);
734
735 plabel.hppa_plabel_pc = (Elf_Addr)ptr;
736 plabel.hppa_plabel_sl = (Elf_Addr)(obj->pltgot);
737 f = (void (*)(void))RTLD_MAKE_PLABEL(&plabel);
738
739 f();
740 }
741
742 Elf_Addr
743 _rtld_call_function_addr(const Obj_Entry *obj, Elf_Addr ptr)
744 {
745 volatile hppa_plabel plabel;
746 Elf_Addr (*f)(void);
747
748 plabel.hppa_plabel_pc = (Elf_Addr)ptr;
749 plabel.hppa_plabel_sl = (Elf_Addr)(obj->pltgot);
750 f = (Elf_Addr (*)(void))RTLD_MAKE_PLABEL(&plabel);
751
752 return f();
753 }
754