1 /* $NetBSD: ppc_reloc.c,v 1.10 2001/09/10 06:09:41 mycroft Exp $ */ 2 3 /*- 4 * Copyright (C) 1998 Tsubai Masanari 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $FreeBSD$ 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/md_var.h> 42 43 #include "debug.h" 44 #include "rtld.h" 45 46 #define _ppc_ha(x) ((((u_int32_t)(x) & 0x8000) ? \ 47 ((u_int32_t)(x) + 0x10000) : (u_int32_t)(x)) >> 16) 48 #define _ppc_la(x) ((u_int32_t)(x) & 0xffff) 49 50 /* 51 * Process the R_PPC_COPY relocations 52 */ 53 int 54 do_copy_relocations(Obj_Entry *dstobj) 55 { 56 const Elf_Rela *relalim; 57 const Elf_Rela *rela; 58 59 /* 60 * COPY relocs are invalid outside of the main program 61 */ 62 assert(dstobj->mainprog); 63 64 relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela + 65 dstobj->relasize); 66 for (rela = dstobj->rela; rela < relalim; rela++) { 67 void *dstaddr; 68 const Elf_Sym *dstsym; 69 const char *name; 70 unsigned long hash; 71 size_t size; 72 const void *srcaddr; 73 const Elf_Sym *srcsym = NULL; 74 Obj_Entry *srcobj; 75 const Ver_Entry *ve; 76 77 if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { 78 continue; 79 } 80 81 dstaddr = (void *) (dstobj->relocbase + rela->r_offset); 82 dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); 83 name = dstobj->strtab + dstsym->st_name; 84 hash = elf_hash(name); 85 size = dstsym->st_size; 86 ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); 87 88 for (srcobj = dstobj->next; srcobj != NULL; 89 srcobj = srcobj->next) { 90 if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) 91 != NULL) { 92 break; 93 } 94 } 95 96 if (srcobj == NULL) { 97 _rtld_error("Undefined symbol \"%s\" " 98 " referenced from COPY" 99 " relocation in %s", name, dstobj->path); 100 return (-1); 101 } 102 103 srcaddr = (const void *) (srcobj->relocbase+srcsym->st_value); 104 memcpy(dstaddr, srcaddr, size); 105 dbg("copy_reloc: src=%p,dst=%p,size=%d\n",srcaddr,dstaddr,size); 106 } 107 108 return (0); 109 } 110 111 112 /* 113 * Perform early relocation of the run-time linker image 114 */ 115 void 116 reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 117 { 118 const Elf_Rela *rela = 0, *relalim; 119 Elf_Addr relasz = 0; 120 Elf_Addr *where; 121 122 /* 123 * Extract the rela/relasz values from the dynamic section 124 */ 125 for (; dynp->d_tag != DT_NULL; dynp++) { 126 switch (dynp->d_tag) { 127 case DT_RELA: 128 rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr); 129 break; 130 case DT_RELASZ: 131 relasz = dynp->d_un.d_val; 132 break; 133 } 134 } 135 136 /* 137 * Relocate these values 138 */ 139 relalim = (const Elf_Rela *)((caddr_t)rela + relasz); 140 for (; rela < relalim; rela++) { 141 where = (Elf_Addr *)(relocbase + rela->r_offset); 142 *where = (Elf_Addr)(relocbase + rela->r_addend); 143 } 144 } 145 146 147 /* 148 * Relocate a non-PLT object with addend. 149 */ 150 static int 151 reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, 152 SymCache *cache) 153 { 154 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 155 const Elf_Sym *def; 156 const Obj_Entry *defobj; 157 Elf_Addr tmp; 158 159 switch (ELF_R_TYPE(rela->r_info)) { 160 161 case R_PPC_NONE: 162 break; 163 164 case R_PPC_ADDR32: /* word32 S + A */ 165 case R_PPC_GLOB_DAT: /* word32 S + A */ 166 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 167 false, cache); 168 if (def == NULL) { 169 return (-1); 170 } 171 172 tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 173 rela->r_addend); 174 175 /* Don't issue write if unnecessary; avoid COW page fault */ 176 if (*where != tmp) { 177 *where = tmp; 178 } 179 break; 180 181 case R_PPC_RELATIVE: /* word32 B + A */ 182 tmp = (Elf_Addr)(obj->relocbase + rela->r_addend); 183 184 /* As above, don't issue write unnecessarily */ 185 if (*where != tmp) { 186 *where = tmp; 187 } 188 break; 189 190 case R_PPC_COPY: 191 /* 192 * These are deferred until all other relocations 193 * have been done. All we do here is make sure 194 * that the COPY relocation is not in a shared 195 * library. They are allowed only in executable 196 * files. 197 */ 198 if (!obj->mainprog) { 199 _rtld_error("%s: Unexpected R_COPY " 200 " relocation in shared library", 201 obj->path); 202 return (-1); 203 } 204 break; 205 206 case R_PPC_JMP_SLOT: 207 /* 208 * These will be handled by the plt/jmpslot routines 209 */ 210 break; 211 212 case R_PPC_DTPMOD32: 213 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 214 false, cache); 215 216 if (def == NULL) 217 return (-1); 218 219 *where = (Elf_Addr) defobj->tlsindex; 220 221 break; 222 223 case R_PPC_TPREL32: 224 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 225 false, cache); 226 227 if (def == NULL) 228 return (-1); 229 230 /* 231 * We lazily allocate offsets for static TLS as we 232 * see the first relocation that references the 233 * TLS block. This allows us to support (small 234 * amounts of) static TLS in dynamically loaded 235 * modules. If we run out of space, we generate an 236 * error. 237 */ 238 if (!defobj->tls_done) { 239 if (!allocate_tls_offset((Obj_Entry*) defobj)) { 240 _rtld_error("%s: No space available for static " 241 "Thread Local Storage", obj->path); 242 return (-1); 243 } 244 } 245 246 *(Elf_Addr **)where = *where * sizeof(Elf_Addr) 247 + (Elf_Addr *)(def->st_value + rela->r_addend 248 + defobj->tlsoffset - TLS_TP_OFFSET); 249 250 break; 251 252 case R_PPC_DTPREL32: 253 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 254 false, cache); 255 256 if (def == NULL) 257 return (-1); 258 259 *where += (Elf_Addr)(def->st_value + rela->r_addend 260 - TLS_DTV_OFFSET); 261 262 break; 263 264 default: 265 _rtld_error("%s: Unsupported relocation type %d" 266 " in non-PLT relocations\n", obj->path, 267 ELF_R_TYPE(rela->r_info)); 268 return (-1); 269 } 270 return (0); 271 } 272 273 274 /* 275 * Process non-PLT relocations 276 */ 277 int 278 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) 279 { 280 const Elf_Rela *relalim; 281 const Elf_Rela *rela; 282 SymCache *cache; 283 int bytes = obj->nchains * sizeof(SymCache); 284 int r = -1; 285 286 /* 287 * The dynamic loader may be called from a thread, we have 288 * limited amounts of stack available so we cannot use alloca(). 289 */ 290 if (obj != obj_rtld) { 291 cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, 292 -1, 0); 293 if (cache == MAP_FAILED) 294 cache = NULL; 295 } else 296 cache = NULL; 297 298 /* 299 * From the SVR4 PPC ABI: 300 * "The PowerPC family uses only the Elf32_Rela relocation 301 * entries with explicit addends." 302 */ 303 relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); 304 for (rela = obj->rela; rela < relalim; rela++) { 305 if (reloc_nonplt_object(obj_rtld, obj, rela, cache) < 0) 306 goto done; 307 } 308 r = 0; 309 done: 310 if (cache) { 311 munmap(cache, bytes); 312 } 313 return (r); 314 } 315 316 317 /* 318 * Initialise a PLT slot to the resolving trampoline 319 */ 320 static int 321 reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) 322 { 323 Elf_Word *where = (Elf_Word *)(obj->relocbase + rela->r_offset); 324 Elf_Addr *pltresolve; 325 Elf_Addr distance; 326 int reloff; 327 328 reloff = rela - obj->pltrela; 329 330 if ((reloff < 0) || (reloff >= 0x8000)) { 331 return (-1); 332 } 333 334 pltresolve = obj->pltgot + 8; 335 336 distance = (Elf_Addr)pltresolve - (Elf_Addr)(where + 1); 337 338 dbg(" reloc_plt_object: where=%p,pltres=%p,reloff=%x,distance=%x", 339 (void *)where, (void *)pltresolve, reloff, distance); 340 341 /* li r11,reloff */ 342 /* b pltresolve */ 343 where[0] = 0x39600000 | reloff; 344 where[1] = 0x48000000 | (distance & 0x03fffffc); 345 346 /* 347 * The icache will be sync'd in init_pltgot, which is called 348 * after all the slots have been updated 349 */ 350 351 return (0); 352 } 353 354 355 /* 356 * Process the PLT relocations. 357 */ 358 int 359 reloc_plt(Obj_Entry *obj) 360 { 361 const Elf_Rela *relalim; 362 const Elf_Rela *rela; 363 364 if (obj->pltrelasize != 0) { 365 366 relalim = (const Elf_Rela *)((char *)obj->pltrela + 367 obj->pltrelasize); 368 for (rela = obj->pltrela; rela < relalim; rela++) { 369 assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 370 371 if (reloc_plt_object(obj, rela) < 0) { 372 return (-1); 373 } 374 } 375 } 376 377 return (0); 378 } 379 380 381 /* 382 * LD_BIND_NOW was set - force relocation for all jump slots 383 */ 384 int 385 reloc_jmpslots(Obj_Entry *obj) 386 { 387 const Obj_Entry *defobj; 388 const Elf_Rela *relalim; 389 const Elf_Rela *rela; 390 const Elf_Sym *def; 391 Elf_Addr *where; 392 Elf_Addr target; 393 394 relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); 395 for (rela = obj->pltrela; rela < relalim; rela++) { 396 assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 397 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 398 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 399 true, NULL); 400 if (def == NULL) { 401 dbg("reloc_jmpslots: sym not found"); 402 return (-1); 403 } 404 405 target = (Elf_Addr)(defobj->relocbase + def->st_value); 406 407 #if 0 408 /* PG XXX */ 409 dbg("\"%s\" in \"%s\" --> %p in \"%s\"", 410 defobj->strtab + def->st_name, basename(obj->path), 411 (void *)target, basename(defobj->path)); 412 #endif 413 414 reloc_jmpslot(where, target, defobj, obj, 415 (const Elf_Rel *) rela); 416 } 417 418 obj->jmpslots_done = true; 419 420 return (0); 421 } 422 423 424 /* 425 * Update the value of a PLT jump slot. Branch directly to the target if 426 * it is within +/- 32Mb, otherwise go indirectly via the pltcall 427 * trampoline call and jump table. 428 */ 429 Elf_Addr 430 reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, 431 const Obj_Entry *obj, const Elf_Rel *rel) 432 { 433 Elf_Addr offset; 434 const Elf_Rela *rela = (const Elf_Rela *) rel; 435 436 dbg(" reloc_jmpslot: where=%p, target=%p", 437 (void *)wherep, (void *)target); 438 439 /* 440 * At the PLT entry pointed at by `wherep', construct 441 * a direct transfer to the now fully resolved function 442 * address. 443 */ 444 offset = target - (Elf_Addr)wherep; 445 446 if (abs(offset) < 32*1024*1024) { /* inside 32MB? */ 447 /* b value # branch directly */ 448 *wherep = 0x48000000 | (offset & 0x03fffffc); 449 __syncicache(wherep, 4); 450 } else { 451 Elf_Addr *pltcall, *jmptab; 452 int distance; 453 int N = obj->pltrelasize / sizeof(Elf_Rela); 454 int reloff = rela - obj->pltrela; 455 456 if ((reloff < 0) || (reloff >= 0x8000)) { 457 return (-1); 458 } 459 460 pltcall = obj->pltgot; 461 462 dbg(" reloc_jmpslot: indir, reloff=%d, N=%d\n", 463 reloff, N); 464 465 jmptab = obj->pltgot + 18 + N * 2; 466 jmptab[reloff] = target; 467 468 distance = (Elf_Addr)pltcall - (Elf_Addr)(wherep + 1); 469 470 /* li r11,reloff */ 471 /* b pltcall # use indirect pltcall routine */ 472 wherep[0] = 0x39600000 | reloff; 473 wherep[1] = 0x48000000 | (distance & 0x03fffffc); 474 __syncicache(wherep, 8); 475 } 476 477 return (target); 478 } 479 480 481 /* 482 * Setup the plt glue routines. 483 */ 484 #define PLTCALL_SIZE 20 485 #define PLTRESOLVE_SIZE 24 486 487 void 488 init_pltgot(Obj_Entry *obj) 489 { 490 Elf_Word *pltcall, *pltresolve; 491 Elf_Word *jmptab; 492 int N = obj->pltrelasize / sizeof(Elf_Rela); 493 494 pltcall = obj->pltgot; 495 496 if (pltcall == NULL) { 497 return; 498 } 499 500 /* 501 * From the SVR4 PPC ABI: 502 * 503 * 'The first 18 words (72 bytes) of the PLT are reserved for 504 * use by the dynamic linker. 505 * ... 506 * 'If the executable or shared object requires N procedure 507 * linkage table entries, the link editor shall reserve 3*N 508 * words (12*N bytes) following the 18 reserved words. The 509 * first 2*N of these words are the procedure linkage table 510 * entries themselves. The static linker directs calls to bytes 511 * (72 + (i-1)*8), for i between 1 and N inclusive. The remaining 512 * N words (4*N bytes) are reserved for use by the dynamic linker.' 513 */ 514 515 /* 516 * Copy the absolute-call assembler stub into the first part of 517 * the reserved PLT area. 518 */ 519 memcpy(pltcall, _rtld_powerpc_pltcall, PLTCALL_SIZE); 520 521 /* 522 * Determine the address of the jumptable, which is the dyn-linker 523 * reserved area after the call cells. Write the absolute address 524 * of the jumptable into the absolute-call assembler code so it 525 * can determine this address. 526 */ 527 jmptab = pltcall + 18 + N * 2; 528 pltcall[1] |= _ppc_ha(jmptab); /* addis 11,11,jmptab@ha */ 529 pltcall[2] |= _ppc_la(jmptab); /* lwz 11,jmptab@l(11) */ 530 531 /* 532 * Skip down 32 bytes into the initial reserved area and copy 533 * in the standard resolving assembler call. Into this assembler, 534 * insert the absolute address of the _rtld_bind_start routine 535 * and the address of the relocation object. 536 */ 537 pltresolve = obj->pltgot + 8; 538 539 memcpy(pltresolve, _rtld_powerpc_pltresolve, PLTRESOLVE_SIZE); 540 pltresolve[0] |= _ppc_ha(_rtld_bind_start); 541 pltresolve[1] |= _ppc_la(_rtld_bind_start); 542 pltresolve[3] |= _ppc_ha(obj); 543 pltresolve[4] |= _ppc_la(obj); 544 545 /* 546 * Sync the icache for the byte range represented by the 547 * trampoline routines and call slots. 548 */ 549 __syncicache(pltcall, 72 + N * 8); 550 } 551 552 void 553 allocate_initial_tls(Obj_Entry *list) 554 { 555 register Elf_Addr **tp __asm__("r2"); 556 Elf_Addr **_tp; 557 558 /* 559 * Fix the size of the static TLS block by using the maximum 560 * offset allocated so far and adding a bit for dynamic modules to 561 * use. 562 */ 563 564 tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; 565 566 _tp = (Elf_Addr **) ((char *) allocate_tls(list, NULL, TLS_TCB_SIZE, 8) 567 + TLS_TP_OFFSET + TLS_TCB_SIZE); 568 569 /* 570 * XXX gcc seems to ignore 'tp = _tp;' 571 */ 572 573 __asm __volatile("mr %0,%1" : "=r"(tp) : "r"(_tp)); 574 } 575 576 void* 577 __tls_get_addr(tls_index* ti) 578 { 579 register Elf_Addr **tp __asm__("r2"); 580 char *p; 581 582 p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET 583 - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset); 584 585 return (p + TLS_DTV_OFFSET); 586 } 587