1 /* $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (C) 1998 Tsubai Masanari 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/mman.h> 34 35 #include <errno.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 #include <machine/cpu.h> 41 #include <machine/atomic.h> 42 #include <machine/md_var.h> 43 44 #include "debug.h" 45 #include "rtld.h" 46 47 #define _ppc_ha(x) ((((u_int32_t)(x) & 0x8000) ? \ 48 ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16) 49 #define _ppc_la(x) ((u_int32_t)(x) & 0xffff) 50 51 #define min(a,b) (((a) < (b)) ? (a) : (b)) 52 #define max(a,b) (((a) > (b)) ? (a) : (b)) 53 54 #define PLT_EXTENDED_BEGIN (1 << 13) 55 #define JMPTAB_BASE(N) (18 + N*2 + ((N > PLT_EXTENDED_BEGIN) ? \ 56 (N - PLT_EXTENDED_BEGIN)*2 : 0)) 57 58 void _rtld_bind_secureplt_start(void); 59 60 /* 61 * Process the R_PPC_COPY relocations 62 */ 63 int 64 do_copy_relocations(Obj_Entry *dstobj) 65 { 66 const Elf_Rela *relalim; 67 const Elf_Rela *rela; 68 69 /* 70 * COPY relocs are invalid outside of the main program 71 */ 72 assert(dstobj->mainprog); 73 74 relalim = (const Elf_Rela *)((const char *) dstobj->rela + 75 dstobj->relasize); 76 for (rela = dstobj->rela; rela < relalim; rela++) { 77 void *dstaddr; 78 const Elf_Sym *dstsym; 79 const char *name; 80 size_t size; 81 const void *srcaddr; 82 const Elf_Sym *srcsym = NULL; 83 const Obj_Entry *srcobj, *defobj; 84 SymLook req; 85 int res; 86 87 if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { 88 continue; 89 } 90 91 dstaddr = (void *)(dstobj->relocbase + rela->r_offset); 92 dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); 93 name = dstobj->strtab + dstsym->st_name; 94 size = dstsym->st_size; 95 symlook_init(&req, name); 96 req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); 97 req.flags = SYMLOOK_EARLY; 98 99 for (srcobj = globallist_next(dstobj); srcobj != NULL; 100 srcobj = globallist_next(srcobj)) { 101 res = symlook_obj(&req, srcobj); 102 if (res == 0) { 103 srcsym = req.sym_out; 104 defobj = req.defobj_out; 105 break; 106 } 107 } 108 109 if (srcobj == NULL) { 110 _rtld_error("Undefined symbol \"%s\" " 111 " referenced from COPY" 112 " relocation in %s", name, dstobj->path); 113 return (-1); 114 } 115 116 srcaddr = (const void *)(defobj->relocbase+srcsym->st_value); 117 memcpy(dstaddr, srcaddr, size); 118 dbg("copy_reloc: src=%p,dst=%p,size=%d\n",srcaddr,dstaddr,size); 119 } 120 121 return (0); 122 } 123 124 125 /* 126 * Perform early relocation of the run-time linker image 127 */ 128 void 129 reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 130 { 131 const Elf_Rela *rela = NULL, *relalim; 132 Elf_Addr relasz = 0; 133 Elf_Addr *where; 134 135 /* 136 * Extract the rela/relasz values from the dynamic section 137 */ 138 for (; dynp->d_tag != DT_NULL; dynp++) { 139 switch (dynp->d_tag) { 140 case DT_RELA: 141 rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr); 142 break; 143 case DT_RELASZ: 144 relasz = dynp->d_un.d_val; 145 break; 146 } 147 } 148 149 /* 150 * Relocate these values 151 */ 152 relalim = (const Elf_Rela *)((const char *)rela + relasz); 153 for (; rela < relalim; rela++) { 154 where = (Elf_Addr *)(relocbase + rela->r_offset); 155 *where = (Elf_Addr)(relocbase + rela->r_addend); 156 } 157 } 158 159 160 /* 161 * Relocate a non-PLT object with addend. 162 */ 163 static int 164 reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, 165 const Elf_Rela *rela, SymCache *cache, int flags, RtldLockState *lockstate) 166 { 167 const Elf_Sym *def = NULL; 168 const Obj_Entry *defobj; 169 Elf_Addr *where, symval = 0; 170 171 /* 172 * First, resolve symbol for relocations which 173 * reference symbols. 174 */ 175 switch (ELF_R_TYPE(rela->r_info)) { 176 177 case R_PPC_UADDR32: /* word32 S + A */ 178 case R_PPC_ADDR32: 179 case R_PPC_GLOB_DAT: /* word32 S + A */ 180 case R_PPC_DTPMOD32: 181 case R_PPC_TPREL32: 182 case R_PPC_DTPREL32: 183 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 184 flags, cache, lockstate); 185 if (def == NULL) { 186 return (-1); 187 } 188 189 /* 190 * If symbol is IFUNC, only perform relocation 191 * when caller allowed it by passing 192 * SYMLOOK_IFUNC flag. Skip the relocations 193 * otherwise. 194 * 195 * Also error out in case IFUNC relocations 196 * are specified for TLS, which cannot be 197 * usefully interpreted. 198 */ 199 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 200 switch (ELF_R_TYPE(rela->r_info)) { 201 case R_PPC_UADDR32: 202 case R_PPC_ADDR32: 203 case R_PPC_GLOB_DAT: 204 if ((flags & SYMLOOK_IFUNC) == 0) { 205 dbg("Non-PLT reference to IFUNC found!"); 206 obj->non_plt_gnu_ifunc = true; 207 return (0); 208 } 209 symval = (Elf_Addr)rtld_resolve_ifunc( 210 defobj, def); 211 break; 212 default: 213 _rtld_error("%s: IFUNC for TLS reloc", 214 obj->path); 215 return (-1); 216 } 217 } else { 218 if ((flags & SYMLOOK_IFUNC) != 0) 219 return (0); 220 symval = (Elf_Addr)defobj->relocbase + 221 def->st_value; 222 } 223 break; 224 default: 225 if ((flags & SYMLOOK_IFUNC) != 0) 226 return (0); 227 } 228 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 229 230 switch (ELF_R_TYPE(rela->r_info)) { 231 case R_PPC_NONE: 232 break; 233 case R_PPC_UADDR32: 234 case R_PPC_ADDR32: 235 case R_PPC_GLOB_DAT: 236 /* Don't issue write if unnecessary; avoid COW page fault */ 237 if (*where != symval + rela->r_addend) { 238 *where = symval + rela->r_addend; 239 } 240 break; 241 case R_PPC_DTPMOD32: 242 *where = (Elf_Addr) defobj->tlsindex; 243 break; 244 case R_PPC_TPREL32: 245 /* 246 * We lazily allocate offsets for static TLS as we 247 * see the first relocation that references the 248 * TLS block. This allows us to support (small 249 * amounts of) static TLS in dynamically loaded 250 * modules. If we run out of space, we generate an 251 * error. 252 */ 253 if (!defobj->tls_static) { 254 if (!allocate_tls_offset( 255 __DECONST(Obj_Entry *, defobj))) { 256 _rtld_error("%s: No space available for static " 257 "Thread Local Storage", obj->path); 258 return (-1); 259 } 260 } 261 262 *(Elf_Addr **)where = *where * sizeof(Elf_Addr) 263 + (Elf_Addr *)(def->st_value + rela->r_addend 264 + defobj->tlsoffset - TLS_TP_OFFSET - TLS_TCB_SIZE); 265 break; 266 case R_PPC_DTPREL32: 267 *where += (Elf_Addr)(def->st_value + rela->r_addend 268 - TLS_DTV_OFFSET); 269 break; 270 case R_PPC_RELATIVE: /* word32 B + A */ 271 symval = (Elf_Addr)(obj->relocbase + rela->r_addend); 272 273 /* As above, don't issue write unnecessarily */ 274 if (*where != symval) { 275 *where = symval; 276 } 277 break; 278 case R_PPC_COPY: 279 /* 280 * These are deferred until all other relocations 281 * have been done. All we do here is make sure 282 * that the COPY relocation is not in a shared 283 * library. They are allowed only in executable 284 * files. 285 */ 286 if (!obj->mainprog) { 287 _rtld_error("%s: Unexpected R_COPY " 288 " relocation in shared library", 289 obj->path); 290 return (-1); 291 } 292 break; 293 case R_PPC_IRELATIVE: 294 /* 295 * These will be handled by reloc_iresolve(). 296 */ 297 obj->irelative = true; 298 break; 299 case R_PPC_JMP_SLOT: 300 /* 301 * These will be handled by the plt/jmpslot routines 302 */ 303 break; 304 305 default: 306 _rtld_error("%s: Unsupported relocation type %d" 307 " in non-PLT relocations\n", obj->path, 308 ELF_R_TYPE(rela->r_info)); 309 return (-1); 310 } 311 return (0); 312 } 313 314 315 /* 316 * Process non-PLT relocations 317 */ 318 int 319 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 320 RtldLockState *lockstate) 321 { 322 const Elf_Rela *relalim; 323 const Elf_Rela *rela; 324 const Elf_Phdr *phdr; 325 SymCache *cache; 326 int r = -1; 327 328 /* 329 * The dynamic loader may be called from a thread, we have 330 * limited amounts of stack available so we cannot use alloca(). 331 */ 332 if (obj != obj_rtld) { 333 cache = calloc(obj->dynsymcount, sizeof(SymCache)); 334 /* No need to check for NULL here */ 335 } else 336 cache = NULL; 337 338 /* 339 * From the SVR4 PPC ABI: 340 * "The PowerPC family uses only the Elf32_Rela relocation 341 * entries with explicit addends." 342 */ 343 relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize); 344 for (rela = obj->rela; rela < relalim; rela++) { 345 if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags, 346 lockstate) < 0) 347 goto done; 348 } 349 r = 0; 350 done: 351 if (cache != NULL) 352 free(cache); 353 354 /* 355 * Synchronize icache for executable segments in case we made 356 * any changes. 357 */ 358 for (phdr = obj->phdr; 359 (const char *)phdr < (const char *)obj->phdr + obj->phsize; 360 phdr++) { 361 if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_X) != 0) { 362 __syncicache(obj->relocbase + phdr->p_vaddr, 363 phdr->p_memsz); 364 } 365 } 366 367 return (r); 368 } 369 370 /* 371 * Initialise a PLT slot to the resolving trampoline 372 */ 373 static int 374 reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) 375 { 376 Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); 377 Elf_Addr *pltresolve, *pltlongresolve, *jmptab; 378 Elf_Addr distance; 379 int N = obj->pltrelasize / sizeof(Elf_Rela); 380 int reloff; 381 382 reloff = rela - obj->pltrela; 383 384 if (reloff < 0) 385 return (-1); 386 387 if (obj->gotptr != NULL) { 388 *where += (Elf_Addr)obj->relocbase; 389 return (0); 390 } 391 392 pltlongresolve = obj->pltgot + 5; 393 pltresolve = pltlongresolve + 5; 394 395 distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1); 396 397 dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x", 398 (void *)where, (void *)pltresolve, reloff, distance); 399 400 if (reloff < PLT_EXTENDED_BEGIN) { 401 /* li r11,reloff */ 402 /* b pltresolve */ 403 where[0] = 0x39600000 | reloff; 404 where[1] = 0x48000000 | (distance & 0x03fffffc); 405 } else { 406 jmptab = obj->pltgot + JMPTAB_BASE(N); 407 jmptab[reloff] = (u_int)pltlongresolve; 408 409 /* lis r11,jmptab[reloff]@ha */ 410 /* lwzu r12,jmptab[reloff]@l(r11) */ 411 /* mtctr r12 */ 412 /* bctr */ 413 where[0] = 0x3d600000 | _ppc_ha(&jmptab[reloff]); 414 where[1] = 0x858b0000 | _ppc_la(&jmptab[reloff]); 415 where[2] = 0x7d8903a6; 416 where[3] = 0x4e800420; 417 } 418 419 420 /* 421 * The icache will be sync'd in reloc_plt, which is called 422 * after all the slots have been updated 423 */ 424 425 return (0); 426 } 427 428 /* 429 * Process the PLT relocations. 430 */ 431 int 432 reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused) 433 { 434 const Elf_Rela *relalim; 435 const Elf_Rela *rela; 436 int N = obj->pltrelasize / sizeof(Elf_Rela); 437 438 if (obj->pltrelasize != 0) { 439 440 relalim = (const Elf_Rela *)((const char *)obj->pltrela + 441 obj->pltrelasize); 442 for (rela = obj->pltrela; rela < relalim; rela++) { 443 if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) { 444 dbg("ABI violation - found IRELATIVE in the PLT."); 445 obj->irelative = true; 446 continue; 447 } 448 449 /* 450 * PowerPC(64) .rela.plt is composed of an array of 451 * R_PPC_JMP_SLOT relocations. Unlike other platforms, 452 * this is the ONLY relocation type that is valid here. 453 */ 454 assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 455 456 if (reloc_plt_object(obj, rela) < 0) { 457 return (-1); 458 } 459 } 460 } 461 462 /* 463 * Sync the icache for the byte range represented by the 464 * trampoline routines and call slots. 465 */ 466 if (obj->pltgot != NULL && obj->gotptr == NULL) 467 __syncicache(obj->pltgot, JMPTAB_BASE(N)*4); 468 469 return (0); 470 } 471 472 /* 473 * LD_BIND_NOW was set - force relocation for all jump slots 474 */ 475 int 476 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 477 { 478 const Obj_Entry *defobj; 479 const Elf_Rela *relalim; 480 const Elf_Rela *rela; 481 const Elf_Sym *def; 482 Elf_Addr *where; 483 Elf_Addr target; 484 485 relalim = (const Elf_Rela *)((const char *)obj->pltrela + 486 obj->pltrelasize); 487 for (rela = obj->pltrela; rela < relalim; rela++) { 488 /* This isn't actually a jump slot, ignore it. */ 489 if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) 490 continue; 491 assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 492 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 493 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 494 SYMLOOK_IN_PLT | flags, NULL, lockstate); 495 if (def == NULL) { 496 dbg("reloc_jmpslots: sym not found"); 497 return (-1); 498 } 499 500 target = (Elf_Addr)(defobj->relocbase + def->st_value); 501 502 if (def == &sym_zero) { 503 /* Zero undefined weak symbols */ 504 *where = 0; 505 } else { 506 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 507 /* LD_BIND_NOW, ifunc in shared lib.*/ 508 obj->gnu_ifunc = true; 509 continue; 510 } 511 reloc_jmpslot(where, target, defobj, obj, 512 (const Elf_Rel *) rela); 513 } 514 } 515 516 obj->jmpslots_done = true; 517 518 return (0); 519 } 520 521 522 /* 523 * Update the value of a PLT jump slot. 524 */ 525 Elf_Addr 526 reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, 527 const Obj_Entry *defobj __unused, const Obj_Entry *obj, const Elf_Rel *rel) 528 { 529 Elf_Addr offset; 530 const Elf_Rela *rela = (const Elf_Rela *) rel; 531 532 dbg(" reloc_jmpslot: where=%p, target=%p", 533 (void *)wherep, (void *)target); 534 535 if (ld_bind_not) 536 goto out; 537 538 539 /* 540 * Process Secure-PLT. 541 */ 542 if (obj->gotptr != NULL) { 543 assert(wherep >= (Elf_Word *)obj->pltgot); 544 assert(wherep < 545 (Elf_Word *)obj->pltgot + obj->pltrelasize); 546 if (*wherep != target) 547 *wherep = target; 548 goto out; 549 } 550 551 /* 552 * BSS-PLT optimization: 553 * Branch directly to the target if it is within +/- 32Mb, 554 * otherwise go indirectly via the pltcall trampoline call and 555 * jump table. 556 */ 557 offset = target - (Elf_Addr)wherep; 558 if (abs((int)offset) < 32*1024*1024) { /* inside 32MB? */ 559 /* 560 * At the PLT entry pointed at by `wherep', construct 561 * a direct transfer to the now fully resolved function 562 * address. 563 */ 564 /* b value # branch directly */ 565 *wherep = 0x48000000 | (offset & 0x03fffffc); 566 __syncicache(wherep, 4); 567 } else { 568 Elf_Addr *pltcall, *jmptab; 569 int distance; 570 int N = obj->pltrelasize / sizeof(Elf_Rela); 571 int reloff = rela - obj->pltrela; 572 573 if (reloff < 0) 574 return (-1); 575 576 pltcall = obj->pltgot; 577 578 dbg(" reloc_jmpslot: indir, reloff=%x, N=%x\n", 579 reloff, N); 580 581 jmptab = obj->pltgot + JMPTAB_BASE(N); 582 jmptab[reloff] = target; 583 mb(); /* Order jmptab update before next changes */ 584 585 if (reloff < PLT_EXTENDED_BEGIN) { 586 /* for extended PLT entries, we keep the old code */ 587 588 distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1); 589 590 /* li r11,reloff */ 591 /* b pltcall # use indirect pltcall routine */ 592 593 /* first instruction same as before */ 594 wherep[1] = 0x48000000 | (distance & 0x03fffffc); 595 __syncicache(wherep, 8); 596 } 597 } 598 599 out: 600 return (target); 601 } 602 603 int 604 reloc_iresolve(Obj_Entry *obj, 605 struct Struct_RtldLockState *lockstate) 606 { 607 /* 608 * Since PLT slots on PowerPC are always R_PPC_JMP_SLOT, 609 * R_PPC_IRELATIVE is in RELA. 610 */ 611 const Elf_Rela *relalim; 612 const Elf_Rela *rela; 613 Elf_Addr *where, target, *ptr; 614 615 if (!obj->irelative) 616 return (0); 617 618 relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize); 619 for (rela = obj->rela; rela < relalim; rela++) { 620 if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) { 621 ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); 622 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 623 624 lock_release(rtld_bind_lock, lockstate); 625 target = call_ifunc_resolver(ptr); 626 wlock_acquire(rtld_bind_lock, lockstate); 627 628 *where = target; 629 } 630 } 631 /* 632 * XXX Remove me when lld is fixed! 633 * LLD currently makes illegal relocations in the PLT. 634 */ 635 relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); 636 for (rela = obj->pltrela; rela < relalim; rela++) { 637 if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) { 638 ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); 639 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 640 641 lock_release(rtld_bind_lock, lockstate); 642 target = call_ifunc_resolver(ptr); 643 wlock_acquire(rtld_bind_lock, lockstate); 644 645 *where = target; 646 } 647 } 648 649 obj->irelative = false; 650 return (0); 651 } 652 653 int 654 reloc_iresolve_nonplt(Obj_Entry *obj __unused, 655 struct Struct_RtldLockState *lockstate __unused) 656 { 657 return (0); 658 } 659 660 int 661 reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused, 662 struct Struct_RtldLockState *lockstate __unused) 663 { 664 const Elf_Rela *relalim; 665 const Elf_Rela *rela; 666 Elf_Addr *where, target; 667 const Elf_Sym *def; 668 const Obj_Entry *defobj; 669 670 if (!obj->gnu_ifunc) 671 return (0); 672 relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); 673 for (rela = obj->pltrela; rela < relalim; rela++) { 674 if (ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT) { 675 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 676 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 677 SYMLOOK_IN_PLT | flags, NULL, lockstate); 678 if (def == NULL) 679 return (-1); 680 if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC) 681 continue; 682 lock_release(rtld_bind_lock, lockstate); 683 target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); 684 wlock_acquire(rtld_bind_lock, lockstate); 685 reloc_jmpslot(where, target, defobj, obj, 686 (const Elf_Rel *)rela); 687 } 688 } 689 obj->gnu_ifunc = false; 690 return (0); 691 } 692 693 /* 694 * Setup the plt glue routines. 695 */ 696 #define PLTCALL_SIZE 20 697 #define PLTLONGRESOLVE_SIZE 20 698 #define PLTRESOLVE_SIZE 24 699 700 void 701 init_pltgot(Obj_Entry *obj) 702 { 703 Elf_Word *pltcall, *pltresolve, *pltlongresolve; 704 Elf_Word *jmptab; 705 int N = obj->pltrelasize / sizeof(Elf_Rela); 706 707 pltcall = obj->pltgot; 708 709 if (pltcall == NULL) { 710 return; 711 } 712 713 /* Handle Secure-PLT first, if applicable. */ 714 if (obj->gotptr != NULL) { 715 obj->gotptr[1] = (Elf_Addr)_rtld_bind_secureplt_start; 716 obj->gotptr[2] = (Elf_Addr)obj; 717 dbg("obj %s secure-plt gotptr=%p start=%p obj=%p", 718 obj->path, obj->gotptr, 719 (void *)obj->gotptr[1], (void *)obj->gotptr[2]); 720 return; 721 } 722 723 /* 724 * From the SVR4 PPC ABI: 725 * 726 * 'The first 18 words (72 bytes) of the PLT are reserved for 727 * use by the dynamic linker. 728 * ... 729 * 'If the executable or shared object requires N procedure 730 * linkage table entries, the link editor shall reserve 3*N 731 * words (12*N bytes) following the 18 reserved words. The 732 * first 2*N of these words are the procedure linkage table 733 * entries themselves. The static linker directs calls to bytes 734 * (72 + (i-1)*8), for i between 1 and N inclusive. The remaining 735 * N words (4*N bytes) are reserved for use by the dynamic linker.' 736 */ 737 738 /* 739 * Copy the absolute-call assembler stub into the first part of 740 * the reserved PLT area. 741 */ 742 memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE); 743 744 /* 745 * Determine the address of the jumptable, which is the dyn-linker 746 * reserved area after the call cells. Write the absolute address 747 * of the jumptable into the absolute-call assembler code so it 748 * can determine this address. 749 */ 750 jmptab = obj->pltgot + JMPTAB_BASE(N); 751 pltcall[1] |= _ppc_ha(jmptab); /* addis 11,11,jmptab@ha */ 752 pltcall[2] |= _ppc_la(jmptab); /* lwz 11,jmptab@l(11) */ 753 754 /* 755 * Skip down 20 bytes into the initial reserved area and copy 756 * in the standard resolving assembler call. Into this assembler, 757 * insert the absolute address of the _rtld_bind_start routine 758 * and the address of the relocation object. 759 * 760 * We place pltlongresolve first, so it can fix up its arguments 761 * and then fall through to the regular PLT resolver. 762 */ 763 pltlongresolve = obj->pltgot + 5; 764 765 memcpy(pltlongresolve, _rtld_powerpc_pltlongresolve, 766 PLTLONGRESOLVE_SIZE); 767 pltlongresolve[0] |= _ppc_ha(jmptab); /* lis 12,jmptab@ha */ 768 pltlongresolve[1] |= _ppc_la(jmptab); /* addi 12,12,jmptab@l */ 769 770 pltresolve = pltlongresolve + PLTLONGRESOLVE_SIZE/sizeof(uint32_t); 771 memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE); 772 pltresolve[0] |= _ppc_ha(_rtld_bind_start); 773 pltresolve[1] |= _ppc_la(_rtld_bind_start); 774 pltresolve[3] |= _ppc_ha(obj); 775 pltresolve[4] |= _ppc_la(obj); 776 777 /* 778 * The icache will be sync'd in reloc_plt, which is called 779 * after all the slots have been updated 780 */ 781 } 782 783 /* 784 * 32 bit cpu feature flag fields. 785 */ 786 u_long cpu_features; 787 u_long cpu_features2; 788 789 void 790 powerpc_abi_variant_hook(Elf_Auxinfo** aux_info) 791 { 792 /* 793 * Since aux_info[] is easier to work with than aux, go ahead and 794 * initialize cpu_features / cpu_features2. 795 */ 796 cpu_features = -1UL; 797 cpu_features2 = -1UL; 798 if (aux_info[AT_HWCAP] != NULL) 799 cpu_features = aux_info[AT_HWCAP]->a_un.a_val; 800 if (aux_info[AT_HWCAP2] != NULL) 801 cpu_features2 = aux_info[AT_HWCAP2]->a_un.a_val; 802 } 803 804 void 805 ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) 806 { 807 808 } 809 810 void 811 allocate_initial_tls(Obj_Entry *list) 812 { 813 814 /* 815 * Fix the size of the static TLS block by using the maximum 816 * offset allocated so far and adding a bit for dynamic modules to 817 * use. 818 */ 819 820 tls_static_space = tls_last_offset + tls_last_size + 821 ld_static_tls_extra; 822 823 _tcb_set(allocate_tls(list, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN)); 824 } 825 826 void* 827 __tls_get_addr(tls_index* ti) 828 { 829 uintptr_t **dtvp; 830 char *p; 831 832 dtvp = &_tcb_get()->tcb_dtv; 833 p = tls_get_addr_common(dtvp, ti->ti_module, ti->ti_offset); 834 835 return (p + TLS_DTV_OFFSET); 836 } 837