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