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 * $FreeBSD$ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/mman.h> 36 #include <sys/sysctl.h> 37 38 #include <errno.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 #include <machine/cpu.h> 44 #include <machine/md_var.h> 45 46 #include "debug.h" 47 #include "rtld.h" 48 49 #if !defined(_CALL_ELF) || _CALL_ELF == 1 50 struct funcdesc { 51 Elf_Addr addr; 52 Elf_Addr toc; 53 Elf_Addr env; 54 }; 55 #endif 56 57 /* 58 * Process the R_PPC_COPY relocations 59 */ 60 int 61 do_copy_relocations(Obj_Entry *dstobj) 62 { 63 const Elf_Rela *relalim; 64 const Elf_Rela *rela; 65 66 /* 67 * COPY relocs are invalid outside of the main program 68 */ 69 assert(dstobj->mainprog); 70 71 relalim = (const Elf_Rela *)((const char *) dstobj->rela + 72 dstobj->relasize); 73 for (rela = dstobj->rela; rela < relalim; rela++) { 74 void *dstaddr; 75 const Elf_Sym *dstsym; 76 const char *name; 77 size_t size; 78 const void *srcaddr; 79 const Elf_Sym *srcsym = NULL; 80 const Obj_Entry *srcobj, *defobj; 81 SymLook req; 82 int res; 83 84 if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { 85 continue; 86 } 87 88 dstaddr = (void *)(dstobj->relocbase + rela->r_offset); 89 dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); 90 name = dstobj->strtab + dstsym->st_name; 91 size = dstsym->st_size; 92 symlook_init(&req, name); 93 req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); 94 req.flags = SYMLOOK_EARLY; 95 96 for (srcobj = globallist_next(dstobj); srcobj != NULL; 97 srcobj = globallist_next(srcobj)) { 98 res = symlook_obj(&req, srcobj); 99 if (res == 0) { 100 srcsym = req.sym_out; 101 defobj = req.defobj_out; 102 break; 103 } 104 } 105 106 if (srcobj == NULL) { 107 _rtld_error("Undefined symbol \"%s\" " 108 " referenced from COPY" 109 " relocation in %s", name, dstobj->path); 110 return (-1); 111 } 112 113 srcaddr = (const void *)(defobj->relocbase+srcsym->st_value); 114 memcpy(dstaddr, srcaddr, size); 115 dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size); 116 } 117 118 return (0); 119 } 120 121 122 /* 123 * Perform early relocation of the run-time linker image 124 */ 125 void 126 reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 127 { 128 const Elf_Rela *rela = NULL, *relalim; 129 Elf_Addr relasz = 0; 130 Elf_Addr *where; 131 132 /* 133 * Extract the rela/relasz values from the dynamic section 134 */ 135 for (; dynp->d_tag != DT_NULL; dynp++) { 136 switch (dynp->d_tag) { 137 case DT_RELA: 138 rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr); 139 break; 140 case DT_RELASZ: 141 relasz = dynp->d_un.d_val; 142 break; 143 } 144 } 145 146 /* 147 * Relocate these values 148 */ 149 relalim = (const Elf_Rela *)((const char *)rela + relasz); 150 for (; rela < relalim; rela++) { 151 where = (Elf_Addr *)(relocbase + rela->r_offset); 152 *where = (Elf_Addr)(relocbase + rela->r_addend); 153 } 154 } 155 156 157 /* 158 * Relocate a non-PLT object with addend. 159 */ 160 static int 161 reloc_nonplt_object(Obj_Entry *obj_rtld __unused, Obj_Entry *obj, 162 const Elf_Rela *rela, SymCache *cache, int flags, RtldLockState *lockstate) 163 { 164 const Elf_Sym *def = NULL; 165 const Obj_Entry *defobj; 166 Elf_Addr *where, symval = 0; 167 168 /* 169 * First, resolve symbol for relocations which 170 * reference symbols. 171 */ 172 switch (ELF_R_TYPE(rela->r_info)) { 173 174 case R_PPC64_UADDR64: /* doubleword64 S + A */ 175 case R_PPC64_ADDR64: 176 case R_PPC_GLOB_DAT: 177 case R_PPC64_DTPMOD64: 178 case R_PPC64_TPREL64: 179 case R_PPC64_DTPREL64: 180 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 181 flags, cache, lockstate); 182 if (def == NULL) { 183 return (-1); 184 } 185 /* 186 * If symbol is IFUNC, only perform relocation 187 * when caller allowed it by passing 188 * SYMLOOK_IFUNC flag. Skip the relocations 189 * otherwise. 190 * 191 * Also error out in case IFUNC relocations 192 * are specified for TLS, which cannot be 193 * usefully interpreted. 194 */ 195 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 196 switch (ELF_R_TYPE(rela->r_info)) { 197 case R_PPC64_UADDR64: 198 case R_PPC64_ADDR64: 199 case R_PPC_GLOB_DAT: 200 if ((flags & SYMLOOK_IFUNC) == 0) { 201 dbg("Non-PLT reference to IFUNC found!"); 202 obj->non_plt_gnu_ifunc = true; 203 return (0); 204 } 205 symval = (Elf_Addr)rtld_resolve_ifunc( 206 defobj, def); 207 break; 208 default: 209 _rtld_error("%s: IFUNC for TLS reloc", 210 obj->path); 211 return (-1); 212 } 213 } else { 214 if ((flags & SYMLOOK_IFUNC) != 0) 215 return (0); 216 symval = (Elf_Addr)defobj->relocbase + 217 def->st_value; 218 } 219 break; 220 default: 221 if ((flags & SYMLOOK_IFUNC) != 0) 222 return (0); 223 } 224 225 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 226 227 switch (ELF_R_TYPE(rela->r_info)) { 228 case R_PPC_NONE: 229 break; 230 case R_PPC64_UADDR64: 231 case R_PPC64_ADDR64: 232 case R_PPC_GLOB_DAT: 233 /* Don't issue write if unnecessary; avoid COW page fault */ 234 if (*where != symval + rela->r_addend) { 235 *where = symval + rela->r_addend; 236 } 237 break; 238 case R_PPC64_DTPMOD64: 239 *where = (Elf_Addr) defobj->tlsindex; 240 break; 241 case R_PPC64_TPREL64: 242 /* 243 * We lazily allocate offsets for static TLS as we 244 * see the first relocation that references the 245 * TLS block. This allows us to support (small 246 * amounts of) static TLS in dynamically loaded 247 * modules. If we run out of space, we generate an 248 * error. 249 */ 250 if (!defobj->tls_static) { 251 if (!allocate_tls_offset( 252 __DECONST(Obj_Entry *, defobj))) { 253 _rtld_error("%s: No space available for static " 254 "Thread Local Storage", obj->path); 255 return (-1); 256 } 257 } 258 259 *(Elf_Addr **)where = *where * sizeof(Elf_Addr) 260 + (Elf_Addr *)(def->st_value + rela->r_addend 261 + defobj->tlsoffset - TLS_TP_OFFSET - TLS_TCB_SIZE); 262 break; 263 case R_PPC64_DTPREL64: 264 *where += (Elf_Addr)(def->st_value + rela->r_addend 265 - TLS_DTV_OFFSET); 266 break; 267 case R_PPC_RELATIVE: /* doubleword64 B + A */ 268 symval = (Elf_Addr)(obj->relocbase + rela->r_addend); 269 270 /* As above, don't issue write unnecessarily */ 271 if (*where != symval) { 272 *where = symval; 273 } 274 break; 275 case R_PPC_COPY: 276 /* 277 * These are deferred until all other relocations 278 * have been done. All we do here is make sure 279 * that the COPY relocation is not in a shared 280 * library. They are allowed only in executable 281 * files. 282 */ 283 if (!obj->mainprog) { 284 _rtld_error("%s: Unexpected R_COPY " 285 " relocation in shared library", 286 obj->path); 287 return (-1); 288 } 289 break; 290 case R_PPC_IRELATIVE: 291 /* 292 * These will be handled by reloc_iresolve(). 293 */ 294 obj->irelative = true; 295 break; 296 case R_PPC_JMP_SLOT: 297 /* 298 * These will be handled by the plt/jmpslot routines 299 */ 300 break; 301 302 default: 303 _rtld_error("%s: Unsupported relocation type %ld" 304 " in non-PLT relocations\n", obj->path, 305 ELF_R_TYPE(rela->r_info)); 306 return (-1); 307 } 308 return (0); 309 } 310 311 312 /* 313 * Process non-PLT relocations 314 */ 315 int 316 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 317 RtldLockState *lockstate) 318 { 319 const Elf_Rela *relalim; 320 const Elf_Rela *rela; 321 const Elf_Phdr *phdr; 322 SymCache *cache; 323 int bytes = obj->dynsymcount * sizeof(SymCache); 324 int r = -1; 325 326 /* 327 * The dynamic loader may be called from a thread, we have 328 * limited amounts of stack available so we cannot use alloca(). 329 */ 330 if (obj != obj_rtld) { 331 cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, 332 -1, 0); 333 if (cache == MAP_FAILED) 334 cache = NULL; 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) 352 munmap(cache, bytes); 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 /* 372 * Initialise a PLT slot to the resolving trampoline 373 */ 374 static int 375 reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) 376 { 377 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 378 long reloff; 379 380 reloff = rela - obj->pltrela; 381 382 dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where, 383 reloff, obj->glink); 384 385 #if !defined(_CALL_ELF) || _CALL_ELF == 1 386 /* Glink code is 3 instructions after the first 32k, 2 before */ 387 *where = (Elf_Addr)obj->glink + 32 + 388 8*((reloff < 0x8000) ? reloff : 0x8000) + 389 12*((reloff < 0x8000) ? 0 : (reloff - 0x8000)); 390 #else 391 /* 64-Bit ELF V2 ABI Specification, sec. 4.2.5.3. */ 392 *where = (Elf_Addr)obj->glink + 4*reloff + 32; 393 #endif 394 395 return (0); 396 } 397 398 /* 399 * Process the PLT relocations. 400 */ 401 int 402 reloc_plt(Obj_Entry *obj, int flags __unused, RtldLockState *lockstate __unused) 403 { 404 const Elf_Rela *relalim; 405 const Elf_Rela *rela; 406 407 if (obj->pltrelasize != 0) { 408 relalim = (const Elf_Rela *)((const char *)obj->pltrela + 409 obj->pltrelasize); 410 for (rela = obj->pltrela; rela < relalim; rela++) { 411 412 #if defined(_CALL_ELF) && _CALL_ELF == 2 413 if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) { 414 dbg("ABI violation - found IRELATIVE in the PLT."); 415 obj->irelative = true; 416 continue; 417 } 418 #endif 419 /* 420 * PowerPC(64) .rela.plt is composed of an array of 421 * R_PPC_JMP_SLOT relocations. Unlike other platforms, 422 * this is the ONLY relocation type that is valid here. 423 */ 424 assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 425 426 if (reloc_plt_object(obj, rela) < 0) { 427 return (-1); 428 } 429 } 430 } 431 432 return (0); 433 } 434 435 /* 436 * LD_BIND_NOW was set - force relocation for all jump slots 437 */ 438 int 439 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 440 { 441 const Obj_Entry *defobj; 442 const Elf_Rela *relalim; 443 const Elf_Rela *rela; 444 const Elf_Sym *def; 445 Elf_Addr *where; 446 Elf_Addr target; 447 448 relalim = (const Elf_Rela *)((const char *)obj->pltrela + 449 obj->pltrelasize); 450 for (rela = obj->pltrela; rela < relalim; rela++) { 451 /* This isn't actually a jump slot, ignore it. */ 452 if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) 453 continue; 454 assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 455 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 456 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 457 SYMLOOK_IN_PLT | flags, NULL, lockstate); 458 if (def == NULL) { 459 dbg("reloc_jmpslots: sym not found"); 460 return (-1); 461 } 462 463 target = (Elf_Addr)(defobj->relocbase + def->st_value); 464 465 if (def == &sym_zero) { 466 /* Zero undefined weak symbols */ 467 #if !defined(_CALL_ELF) || _CALL_ELF == 1 468 bzero(where, sizeof(struct funcdesc)); 469 #else 470 *where = 0; 471 #endif 472 } else { 473 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 474 /* LD_BIND_NOW, ifunc in shared lib.*/ 475 obj->gnu_ifunc = true; 476 continue; 477 } 478 reloc_jmpslot(where, target, defobj, obj, 479 (const Elf_Rel *) rela); 480 } 481 } 482 483 obj->jmpslots_done = true; 484 485 return (0); 486 } 487 488 489 /* 490 * Update the value of a PLT jump slot. 491 */ 492 Elf_Addr 493 reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj __unused, 494 const Obj_Entry *obj __unused, const Elf_Rel *rel __unused) 495 { 496 497 /* 498 * At the PLT entry pointed at by `wherep', construct 499 * a direct transfer to the now fully resolved function 500 * address. 501 */ 502 503 #if !defined(_CALL_ELF) || _CALL_ELF == 1 504 dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)", 505 (void *)wherep, (void *)target, *(Elf_Addr *)target, 506 (Elf_Addr)defobj->relocbase); 507 508 if (ld_bind_not) 509 goto out; 510 511 /* 512 * For the trampoline, the second two elements of the function 513 * descriptor are unused, so we are fine replacing those at any time 514 * with the real ones with no thread safety implications. However, we 515 * need to make sure the main entry point pointer ([0]) is seen to be 516 * modified *after* the second two elements. This can't be done in 517 * general, since there are no barriers in the reading code, but put in 518 * some isyncs to at least make it a little better. 519 */ 520 memcpy(wherep, (void *)target, sizeof(struct funcdesc)); 521 wherep[2] = ((Elf_Addr *)target)[2]; 522 wherep[1] = ((Elf_Addr *)target)[1]; 523 __asm __volatile ("isync" : : : "memory"); 524 wherep[0] = ((Elf_Addr *)target)[0]; 525 __asm __volatile ("isync" : : : "memory"); 526 527 if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) { 528 /* 529 * It is possible (LD_BIND_NOW) that the function 530 * descriptor we are copying has not yet been relocated. 531 * If this happens, fix it. Don't worry about threading in 532 * this case since LD_BIND_NOW makes it irrelevant. 533 */ 534 535 ((struct funcdesc *)(wherep))->addr += 536 (Elf_Addr)defobj->relocbase; 537 ((struct funcdesc *)(wherep))->toc += 538 (Elf_Addr)defobj->relocbase; 539 } 540 #else 541 dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep, 542 (void *)target); 543 544 assert(target >= (Elf_Addr)defobj->relocbase); 545 546 if (ld_bind_not) 547 goto out; 548 549 if (*wherep != target) 550 *wherep = target; 551 552 #endif 553 out: 554 555 return (target); 556 } 557 558 int 559 reloc_iresolve(Obj_Entry *obj, 560 struct Struct_RtldLockState *lockstate) 561 { 562 /* 563 * Since PLT slots on PowerPC64 are always R_PPC_JMP_SLOT, 564 * R_PPC_IRELATIVE is in RELA. 565 */ 566 #if !defined(_CALL_ELF) || _CALL_ELF == 1 567 (void)(obj); 568 (void)(lockstate); 569 /* XXX not implemented */ 570 return (0); 571 #else 572 const Elf_Rela *relalim; 573 const Elf_Rela *rela; 574 Elf_Addr *where, target, *ptr; 575 576 if (!obj->irelative) 577 return (0); 578 579 relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize); 580 for (rela = obj->rela; rela < relalim; rela++) { 581 if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) { 582 ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); 583 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 584 585 lock_release(rtld_bind_lock, lockstate); 586 target = call_ifunc_resolver(ptr); 587 wlock_acquire(rtld_bind_lock, lockstate); 588 589 *where = target; 590 } 591 } 592 /* 593 * XXX Remove me when lld is fixed! 594 * LLD currently makes illegal relocations in the PLT. 595 */ 596 relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); 597 for (rela = obj->pltrela; rela < relalim; rela++) { 598 if (ELF_R_TYPE(rela->r_info) == R_PPC_IRELATIVE) { 599 ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); 600 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 601 602 lock_release(rtld_bind_lock, lockstate); 603 target = call_ifunc_resolver(ptr); 604 wlock_acquire(rtld_bind_lock, lockstate); 605 606 *where = target; 607 } 608 } 609 610 obj->irelative = false; 611 return (0); 612 #endif 613 } 614 615 int 616 reloc_gnu_ifunc(Obj_Entry *obj __unused, int flags __unused, 617 struct Struct_RtldLockState *lockstate __unused) 618 { 619 #if !defined(_CALL_ELF) || _CALL_ELF == 1 620 _rtld_error("reloc_gnu_ifunc(): Not implemented!"); 621 /* XXX not implemented */ 622 return (-1); 623 #else 624 625 const Elf_Rela *relalim; 626 const Elf_Rela *rela; 627 Elf_Addr *where, target; 628 const Elf_Sym *def; 629 const Obj_Entry *defobj; 630 631 if (!obj->gnu_ifunc) 632 return (0); 633 relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); 634 for (rela = obj->pltrela; rela < relalim; rela++) { 635 if (ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT) { 636 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 637 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 638 SYMLOOK_IN_PLT | flags, NULL, lockstate); 639 if (def == NULL) 640 return (-1); 641 if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC) 642 continue; 643 lock_release(rtld_bind_lock, lockstate); 644 target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); 645 wlock_acquire(rtld_bind_lock, lockstate); 646 reloc_jmpslot(where, target, defobj, obj, 647 (const Elf_Rel *)rela); 648 } 649 } 650 obj->gnu_ifunc = false; 651 return (0); 652 #endif 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 void 663 init_pltgot(Obj_Entry *obj) 664 { 665 Elf_Addr *pltcall; 666 667 pltcall = obj->pltgot; 668 669 if (pltcall == NULL) { 670 return; 671 } 672 673 #if defined(_CALL_ELF) && _CALL_ELF == 2 674 pltcall[0] = (Elf_Addr)&_rtld_bind_start; 675 pltcall[1] = (Elf_Addr)obj; 676 #else 677 memcpy(pltcall, _rtld_bind_start, sizeof(struct funcdesc)); 678 pltcall[2] = (Elf_Addr)obj; 679 #endif 680 } 681 682 /* 683 * Actual values are 32 bit. 684 */ 685 u_long cpu_features; 686 u_long cpu_features2; 687 688 void 689 powerpc64_abi_variant_hook(Elf_Auxinfo** aux_info) 690 { 691 /* 692 * Since aux_info[] is easier to work with than aux, go ahead and 693 * initialize cpu_features / cpu_features2. 694 */ 695 cpu_features = -1UL; 696 cpu_features2 = -1UL; 697 if (aux_info[AT_HWCAP] != NULL) 698 cpu_features = (uint32_t)aux_info[AT_HWCAP]->a_un.a_val; 699 if (aux_info[AT_HWCAP2] != NULL) 700 cpu_features2 = (uint32_t)aux_info[AT_HWCAP2]->a_un.a_val; 701 } 702 703 void 704 ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) 705 { 706 707 } 708 709 void 710 allocate_initial_tls(Obj_Entry *list) 711 { 712 713 /* 714 * Fix the size of the static TLS block by using the maximum 715 * offset allocated so far and adding a bit for dynamic modules to 716 * use. 717 */ 718 719 tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; 720 721 _tcb_set(allocate_tls(list, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN)); 722 } 723 724 void* 725 __tls_get_addr(tls_index* ti) 726 { 727 uintptr_t **dtvp; 728 char *p; 729 730 dtvp = &_tcb_get()->tcb_dtv; 731 p = tls_get_addr_common(dtvp, ti->ti_module, ti->ti_offset); 732 733 return (p + TLS_DTV_OFFSET); 734 } 735