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 #if !defined(_CALL_ELF) || _CALL_ELF == 1 47 struct funcdesc { 48 Elf_Addr addr; 49 Elf_Addr toc; 50 Elf_Addr env; 51 }; 52 #endif 53 54 /* 55 * Process the R_PPC_COPY relocations 56 */ 57 int 58 do_copy_relocations(Obj_Entry *dstobj) 59 { 60 const Elf_Rela *relalim; 61 const Elf_Rela *rela; 62 63 /* 64 * COPY relocs are invalid outside of the main program 65 */ 66 assert(dstobj->mainprog); 67 68 relalim = (const Elf_Rela *) ((caddr_t) dstobj->rela + 69 dstobj->relasize); 70 for (rela = dstobj->rela; rela < relalim; rela++) { 71 void *dstaddr; 72 const Elf_Sym *dstsym; 73 const char *name; 74 size_t size; 75 const void *srcaddr; 76 const Elf_Sym *srcsym = NULL; 77 const Obj_Entry *srcobj, *defobj; 78 SymLook req; 79 int res; 80 81 if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) { 82 continue; 83 } 84 85 dstaddr = (void *) (dstobj->relocbase + rela->r_offset); 86 dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); 87 name = dstobj->strtab + dstsym->st_name; 88 size = dstsym->st_size; 89 symlook_init(&req, name); 90 req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); 91 req.flags = SYMLOOK_EARLY; 92 93 for (srcobj = globallist_next(dstobj); srcobj != NULL; 94 srcobj = globallist_next(srcobj)) { 95 res = symlook_obj(&req, srcobj); 96 if (res == 0) { 97 srcsym = req.sym_out; 98 defobj = req.defobj_out; 99 break; 100 } 101 } 102 103 if (srcobj == NULL) { 104 _rtld_error("Undefined symbol \"%s\" " 105 " referenced from COPY" 106 " relocation in %s", name, dstobj->path); 107 return (-1); 108 } 109 110 srcaddr = (const void *) (defobj->relocbase+srcsym->st_value); 111 memcpy(dstaddr, srcaddr, size); 112 dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size); 113 } 114 115 return (0); 116 } 117 118 119 /* 120 * Perform early relocation of the run-time linker image 121 */ 122 void 123 reloc_non_plt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 124 { 125 const Elf_Rela *rela = 0, *relalim; 126 Elf_Addr relasz = 0; 127 Elf_Addr *where; 128 129 /* 130 * Extract the rela/relasz values from the dynamic section 131 */ 132 for (; dynp->d_tag != DT_NULL; dynp++) { 133 switch (dynp->d_tag) { 134 case DT_RELA: 135 rela = (const Elf_Rela *)(relocbase+dynp->d_un.d_ptr); 136 break; 137 case DT_RELASZ: 138 relasz = dynp->d_un.d_val; 139 break; 140 } 141 } 142 143 /* 144 * Relocate these values 145 */ 146 relalim = (const Elf_Rela *)((caddr_t)rela + relasz); 147 for (; rela < relalim; rela++) { 148 where = (Elf_Addr *)(relocbase + rela->r_offset); 149 *where = (Elf_Addr)(relocbase + rela->r_addend); 150 } 151 } 152 153 154 /* 155 * Relocate a non-PLT object with addend. 156 */ 157 static int 158 reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, 159 SymCache *cache, int flags, RtldLockState *lockstate) 160 { 161 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 162 const Elf_Sym *def; 163 const Obj_Entry *defobj; 164 Elf_Addr tmp; 165 166 switch (ELF_R_TYPE(rela->r_info)) { 167 168 case R_PPC_NONE: 169 break; 170 171 case R_PPC64_UADDR64: /* doubleword64 S + A */ 172 case R_PPC64_ADDR64: 173 case R_PPC_GLOB_DAT: 174 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 175 flags, cache, lockstate); 176 if (def == NULL) { 177 return (-1); 178 } 179 180 tmp = (Elf_Addr)(defobj->relocbase + def->st_value + 181 rela->r_addend); 182 183 /* Don't issue write if unnecessary; avoid COW page fault */ 184 if (*where != tmp) { 185 *where = tmp; 186 } 187 break; 188 189 case R_PPC_RELATIVE: /* doubleword64 B + A */ 190 tmp = (Elf_Addr)(obj->relocbase + rela->r_addend); 191 192 /* As above, don't issue write unnecessarily */ 193 if (*where != tmp) { 194 *where = tmp; 195 } 196 break; 197 198 case R_PPC_COPY: 199 /* 200 * These are deferred until all other relocations 201 * have been done. All we do here is make sure 202 * that the COPY relocation is not in a shared 203 * library. They are allowed only in executable 204 * files. 205 */ 206 if (!obj->mainprog) { 207 _rtld_error("%s: Unexpected R_COPY " 208 " relocation in shared library", 209 obj->path); 210 return (-1); 211 } 212 break; 213 214 case R_PPC_JMP_SLOT: 215 /* 216 * These will be handled by the plt/jmpslot routines 217 */ 218 break; 219 220 case R_PPC64_DTPMOD64: 221 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 222 flags, cache, lockstate); 223 224 if (def == NULL) 225 return (-1); 226 227 *where = (Elf_Addr) defobj->tlsindex; 228 229 break; 230 231 case R_PPC64_TPREL64: 232 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 233 flags, cache, lockstate); 234 235 if (def == NULL) 236 return (-1); 237 238 /* 239 * We lazily allocate offsets for static TLS as we 240 * see the first relocation that references the 241 * TLS block. This allows us to support (small 242 * amounts of) static TLS in dynamically loaded 243 * modules. If we run out of space, we generate an 244 * error. 245 */ 246 if (!defobj->tls_done) { 247 if (!allocate_tls_offset((Obj_Entry*) defobj)) { 248 _rtld_error("%s: No space available for static " 249 "Thread Local Storage", obj->path); 250 return (-1); 251 } 252 } 253 254 *(Elf_Addr **)where = *where * sizeof(Elf_Addr) 255 + (Elf_Addr *)(def->st_value + rela->r_addend 256 + defobj->tlsoffset - TLS_TP_OFFSET); 257 258 break; 259 260 case R_PPC64_DTPREL64: 261 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 262 flags, cache, lockstate); 263 264 if (def == NULL) 265 return (-1); 266 267 *where += (Elf_Addr)(def->st_value + rela->r_addend 268 - TLS_DTV_OFFSET); 269 270 break; 271 272 default: 273 _rtld_error("%s: Unsupported relocation type %ld" 274 " in non-PLT relocations\n", obj->path, 275 ELF_R_TYPE(rela->r_info)); 276 return (-1); 277 } 278 return (0); 279 } 280 281 282 /* 283 * Process non-PLT relocations 284 */ 285 int 286 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 287 RtldLockState *lockstate) 288 { 289 const Elf_Rela *relalim; 290 const Elf_Rela *rela; 291 SymCache *cache; 292 int bytes = obj->dynsymcount * sizeof(SymCache); 293 int r = -1; 294 295 if ((flags & SYMLOOK_IFUNC) != 0) 296 /* XXX not implemented */ 297 return (0); 298 299 /* 300 * The dynamic loader may be called from a thread, we have 301 * limited amounts of stack available so we cannot use alloca(). 302 */ 303 if (obj != obj_rtld) { 304 cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, 305 -1, 0); 306 if (cache == MAP_FAILED) 307 cache = NULL; 308 } else 309 cache = NULL; 310 311 /* 312 * From the SVR4 PPC ABI: 313 * "The PowerPC family uses only the Elf32_Rela relocation 314 * entries with explicit addends." 315 */ 316 relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize); 317 for (rela = obj->rela; rela < relalim; rela++) { 318 if (reloc_nonplt_object(obj_rtld, obj, rela, cache, flags, 319 lockstate) < 0) 320 goto done; 321 } 322 r = 0; 323 done: 324 if (cache) 325 munmap(cache, bytes); 326 327 /* Synchronize icache for text seg in case we made any changes */ 328 __syncicache(obj->mapbase, obj->textsize); 329 330 return (r); 331 } 332 333 334 /* 335 * Initialise a PLT slot to the resolving trampoline 336 */ 337 static int 338 reloc_plt_object(Obj_Entry *obj, const Elf_Rela *rela) 339 { 340 Elf_Addr *where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 341 long reloff; 342 343 reloff = rela - obj->pltrela; 344 345 dbg(" reloc_plt_object: where=%p,reloff=%lx,glink=%#lx", (void *)where, 346 reloff, obj->glink); 347 348 #if !defined(_CALL_ELF) || _CALL_ELF == 1 349 /* Glink code is 3 instructions after the first 32k, 2 before */ 350 *where = (Elf_Addr)obj->glink + 32 + 351 8*((reloff < 0x8000) ? reloff : 0x8000) + 352 12*((reloff < 0x8000) ? 0 : (reloff - 0x8000)); 353 #else 354 *where = (Elf_Addr)obj->glink + 4*reloff + 32; 355 #endif 356 357 return (0); 358 } 359 360 361 /* 362 * Process the PLT relocations. 363 */ 364 int 365 reloc_plt(Obj_Entry *obj) 366 { 367 const Elf_Rela *relalim; 368 const Elf_Rela *rela; 369 370 if (obj->pltrelasize != 0) { 371 relalim = (const Elf_Rela *)((char *)obj->pltrela + 372 obj->pltrelasize); 373 for (rela = obj->pltrela; rela < relalim; rela++) { 374 assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 375 376 if (reloc_plt_object(obj, rela) < 0) { 377 return (-1); 378 } 379 } 380 } 381 382 return (0); 383 } 384 385 386 /* 387 * LD_BIND_NOW was set - force relocation for all jump slots 388 */ 389 int 390 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 391 { 392 const Obj_Entry *defobj; 393 const Elf_Rela *relalim; 394 const Elf_Rela *rela; 395 const Elf_Sym *def; 396 Elf_Addr *where; 397 Elf_Addr target; 398 399 relalim = (const Elf_Rela *)((char *)obj->pltrela + obj->pltrelasize); 400 for (rela = obj->pltrela; rela < relalim; rela++) { 401 assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT); 402 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 403 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 404 SYMLOOK_IN_PLT | flags, NULL, lockstate); 405 if (def == NULL) { 406 dbg("reloc_jmpslots: sym not found"); 407 return (-1); 408 } 409 410 target = (Elf_Addr)(defobj->relocbase + def->st_value); 411 412 if (def == &sym_zero) { 413 /* Zero undefined weak symbols */ 414 #if !defined(_CALL_ELF) || _CALL_ELF == 1 415 bzero(where, sizeof(struct funcdesc)); 416 #else 417 *where = 0; 418 #endif 419 } else { 420 reloc_jmpslot(where, target, defobj, obj, 421 (const Elf_Rel *) rela); 422 } 423 } 424 425 obj->jmpslots_done = true; 426 427 return (0); 428 } 429 430 431 /* 432 * Update the value of a PLT jump slot. 433 */ 434 Elf_Addr 435 reloc_jmpslot(Elf_Addr *wherep, Elf_Addr target, const Obj_Entry *defobj, 436 const Obj_Entry *obj, const Elf_Rel *rel) 437 { 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 445 #if !defined(_CALL_ELF) || _CALL_ELF == 1 446 dbg(" reloc_jmpslot: where=%p, target=%p (%#lx + %#lx)", 447 (void *)wherep, (void *)target, *(Elf_Addr *)target, 448 (Elf_Addr)defobj->relocbase); 449 450 /* 451 * For the trampoline, the second two elements of the function 452 * descriptor are unused, so we are fine replacing those at any time 453 * with the real ones with no thread safety implications. However, we 454 * need to make sure the main entry point pointer ([0]) is seen to be 455 * modified *after* the second two elements. This can't be done in 456 * general, since there are no barriers in the reading code, but put in 457 * some isyncs to at least make it a little better. 458 */ 459 memcpy(wherep, (void *)target, sizeof(struct funcdesc)); 460 wherep[2] = ((Elf_Addr *)target)[2]; 461 wherep[1] = ((Elf_Addr *)target)[1]; 462 __asm __volatile ("isync" : : : "memory"); 463 wherep[0] = ((Elf_Addr *)target)[0]; 464 __asm __volatile ("isync" : : : "memory"); 465 466 if (((struct funcdesc *)(wherep))->addr < (Elf_Addr)defobj->relocbase) { 467 /* 468 * It is possible (LD_BIND_NOW) that the function 469 * descriptor we are copying has not yet been relocated. 470 * If this happens, fix it. Don't worry about threading in 471 * this case since LD_BIND_NOW makes it irrelevant. 472 */ 473 474 ((struct funcdesc *)(wherep))->addr += 475 (Elf_Addr)defobj->relocbase; 476 ((struct funcdesc *)(wherep))->toc += 477 (Elf_Addr)defobj->relocbase; 478 } 479 #else 480 dbg(" reloc_jmpslot: where=%p, target=%p", (void *)wherep, 481 (void *)target); 482 483 *wherep = target; 484 #endif 485 486 return (target); 487 } 488 489 int 490 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) 491 { 492 493 /* XXX not implemented */ 494 return (0); 495 } 496 497 int 498 reloc_gnu_ifunc(Obj_Entry *obj, int flags, 499 struct Struct_RtldLockState *lockstate) 500 { 501 502 /* XXX not implemented */ 503 return (0); 504 } 505 506 void 507 init_pltgot(Obj_Entry *obj) 508 { 509 Elf_Addr *pltcall; 510 511 pltcall = obj->pltgot; 512 513 if (pltcall == NULL) { 514 return; 515 } 516 517 #if defined(_CALL_ELF) && _CALL_ELF == 2 518 pltcall[0] = (Elf_Addr)&_rtld_bind_start; 519 pltcall[1] = (Elf_Addr)obj; 520 #else 521 memcpy(pltcall, _rtld_bind_start, sizeof(struct funcdesc)); 522 pltcall[2] = (Elf_Addr)obj; 523 #endif 524 } 525 526 void 527 allocate_initial_tls(Obj_Entry *list) 528 { 529 Elf_Addr **tp; 530 531 /* 532 * Fix the size of the static TLS block by using the maximum 533 * offset allocated so far and adding a bit for dynamic modules to 534 * use. 535 */ 536 537 tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; 538 539 tp = (Elf_Addr **) ((char *)allocate_tls(list, NULL, TLS_TCB_SIZE, 16) 540 + TLS_TP_OFFSET + TLS_TCB_SIZE); 541 542 __asm __volatile("mr 13,%0" :: "r"(tp)); 543 } 544 545 void* 546 __tls_get_addr(tls_index* ti) 547 { 548 Elf_Addr **tp; 549 char *p; 550 551 __asm __volatile("mr %0,13" : "=r"(tp)); 552 p = tls_get_addr_common((Elf_Addr**)((Elf_Addr)tp - TLS_TP_OFFSET 553 - TLS_TCB_SIZE), ti->ti_module, ti->ti_offset); 554 555 return (p + TLS_DTV_OFFSET); 556 } 557