1 /* $NetBSD: hppa_reloc.c,v 1.45 2017/08/10 19:03:26 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.45 2017/08/10 19:03:26 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(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