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