1/* $NetBSD: hppa_reloc.c,v 1.50 2023/06/04 01:24:57 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.50 2023/06/04 01:24:57 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 52caddr_t _rtld_bind(const Obj_Entry *, const Elf_Addr); 53void _rtld_bind_start(void); 54void __rtld_setup_hppa_pltgot(const Obj_Entry *, Elf_Addr *); 55void _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 64static inline Elf_Addr 65load_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 77static inline void 78store_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 86static __inline void 87fdc(void *addr) 88{ 89 __asm volatile("fdc %%r0(%%sr0, %0)" : : "r" (addr)); 90} 91 92static __inline void 93fic(void *addr) 94{ 95 __asm volatile("fic %%r0(%%sr0,%0)" : : "r" (addr)); 96} 97 98static __inline void 99sync(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 */ 125typedef 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 */ 135static 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) 143static hppa_plabel hppa_plabel_pre[HPPA_PLABEL_PRE]; 144static int hppa_plabel_pre_next = 0; 145 146void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 147int _rtld_relocate_plt_objects(const Obj_Entry *); 148static 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 */ 164void 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 */ 314Elf_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 */ 371const 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. */ 380void 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 413int 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_static && 557 _rtld_tls_offset_allocate(__UNCONST(defobj))) 558 return -1; 559 560 *where = (Elf_Addr)(defobj->tlsoffset + def->st_value + 561 rela->r_addend + sizeof(struct tls_tcb)); 562 563 rdbg(("TPREL32 %s in %s --> %p in %s", 564 obj->strtab + obj->symtab[symnum].st_name, 565 obj->path, (void *)*where, defobj->path)); 566 break; 567 568 case R_TYPE(TLS_DTPMOD32): 569 *where = (Elf_Addr)(defobj->tlsindex); 570 571 rdbg(("TLS_DTPMOD32 %s in %s --> %p", 572 obj->strtab + obj->symtab[symnum].st_name, 573 obj->path, (void *)*where)); 574 575 break; 576 577 case R_TYPE(TLS_DTPOFF32): 578 *where = (Elf_Addr)(def->st_value); 579 580 rdbg(("TLS_DTPOFF32 %s in %s --> %p", 581 obj->strtab + obj->symtab[symnum].st_name, 582 obj->path, (void *)*where)); 583 584 break; 585 586 default: 587 rdbg(("sym = %lu, type = %lu, offset = %p, " 588 "addend = %p, contents = %p, symbol = %s", 589 symnum, (u_long)ELF_R_TYPE(rela->r_info), 590 (void *)rela->r_offset, (void *)rela->r_addend, 591 (void *)load_ptr(where), 592 obj->strtab + obj->symtab[symnum].st_name)); 593 _rtld_error("%s: Unsupported relocation type %ld " 594 "in non-PLT relocations", 595 obj->path, (u_long) ELF_R_TYPE(rela->r_info)); 596 return -1; 597 } 598 } 599 return 0; 600} 601 602int 603_rtld_relocate_plt_lazy(Obj_Entry *obj) 604{ 605 const Elf_Rela *rela; 606 607 for (rela = obj->pltrela; rela < obj->pltrelalim; rela++) { 608 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 609 Elf_Addr func_pc, func_sl; 610 611 assert(ELF_R_TYPE(rela->r_info) == R_TYPE(IPLT)); 612 613 /* 614 * If this is an IPLT reloc for a static function, 615 * fully resolve the PLT entry now. 616 */ 617 if (ELF_R_SYM(rela->r_info) == 0) { 618 func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend); 619 func_sl = (Elf_Addr)(obj->pltgot); 620 } 621 622 /* 623 * Otherwise set up for lazy binding. 624 */ 625 else { 626 /* 627 * This function pointer points to the PLT 628 * stub added by the linker, and instead of 629 * a shared linkage value, we stash this 630 * relocation's offset. The PLT stub has 631 * already been set up to transfer to 632 * _rtld_bind_start. 633 */ 634 func_pc = ((Elf_Addr)(obj->pltgot)) - 16; 635 func_sl = (Elf_Addr) 636 ((const char *)rela - (const char *)(obj->pltrela)); 637 } 638 rdbg(("lazy bind %s(%p) --> old=(%p,%p) new=(%p,%p)", 639 obj->path, 640 (void *)where, 641 (void *)where[0], (void *)where[1], 642 (void *)func_pc, (void *)func_sl)); 643 644 /* 645 * Fill this PLT entry and return. 646 */ 647 where[0] = func_pc; 648 where[1] = func_sl; 649 } 650 return 0; 651} 652 653static inline int 654_rtld_relocate_plt_object(const Obj_Entry *obj, const Elf_Rela *rela, 655 Elf_Addr *tp) 656{ 657 Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); 658 const Elf_Sym *def; 659 const Obj_Entry *defobj; 660 Elf_Addr func_pc, func_sl; 661 unsigned long info = rela->r_info; 662 663 assert(ELF_R_TYPE(info) == R_TYPE(IPLT)); 664 665 if (ELF_R_SYM(info) == 0) { 666 func_pc = (Elf_Addr)(obj->relocbase + rela->r_addend); 667 func_sl = (Elf_Addr)(obj->pltgot); 668 } else { 669 def = _rtld_find_plt_symdef(ELF_R_SYM(info), obj, &defobj, 670 tp != NULL); 671 if (__predict_false(def == NULL)) 672 return -1; 673 if (__predict_false(def == &_rtld_sym_zero)) 674 return 0; 675 676 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 677 if (tp == NULL) 678 return 0; 679 Elf_Addr ptr = _rtld_resolve_ifunc(defobj, def); 680 assert(RTLD_IS_PLABEL(ptr)); 681 hppa_plabel *label = RTLD_GET_PLABEL(ptr); 682 func_pc = label->hppa_plabel_pc; 683 func_sl = label->hppa_plabel_sl; 684 } else { 685 func_pc = (Elf_Addr)(defobj->relocbase + def->st_value + 686 rela->r_addend); 687 func_sl = (Elf_Addr)(defobj->pltgot); 688 } 689 690 rdbg(("bind now/fixup in %s --> old=(%p,%p) new=(%p,%p)", 691 defobj->strtab + def->st_name, 692 (void *)where[0], (void *)where[1], 693 (void *)func_pc, (void *)func_sl)); 694 } 695 /* 696 * Fill this PLT entry and return. 697 */ 698 if (where[0] != func_pc) 699 where[0] = func_pc; 700 if (where[1] != func_sl) 701 where[1] = func_sl; 702 703 if (tp) 704 *tp = (Elf_Addr)where; 705 706 return 0; 707} 708 709caddr_t 710_rtld_bind(const Obj_Entry *obj, Elf_Word reloff) 711{ 712 const Elf_Rela *rela; 713 Elf_Addr new_value = 0; /* XXX gcc */ 714 int err; 715 716 rela = (const Elf_Rela *)((const char *)obj->pltrela + reloff); 717 718 assert(ELF_R_SYM(rela->r_info) != 0); 719 720 _rtld_shared_enter(); 721 err = _rtld_relocate_plt_object(obj, rela, &new_value); 722 if (err) 723 _rtld_die(); 724 _rtld_shared_exit(); 725 726 return (caddr_t)new_value; 727} 728 729int 730_rtld_relocate_plt_objects(const Obj_Entry *obj) 731{ 732 const Elf_Rela *rela = obj->pltrela; 733 734 for (; rela < obj->pltrelalim; rela++) { 735 if (_rtld_relocate_plt_object(obj, rela, NULL) < 0) 736 return -1; 737 } 738 return 0; 739} 740 741Elf_Addr 742_rtld_call_function_addr(const Obj_Entry *obj, Elf_Addr ptr) 743{ 744 volatile hppa_plabel plabel; 745 Elf_Addr (*f)(void); 746 747 plabel.hppa_plabel_pc = (Elf_Addr)ptr; 748 plabel.hppa_plabel_sl = (Elf_Addr)(obj->pltgot); 749 f = (Elf_Addr (*)(void))RTLD_MAKE_PLABEL(&plabel); 750 751 return f(); 752} 753