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