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