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