reloc.c revision 153503
1/*- 2 * Copyright 1996, 1997, 1998, 1999 John D. Polstra. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * $FreeBSD: head/libexec/rtld-elf/ia64/reloc.c 153503 2005-12-18 01:38:26Z marcel $ 26 */ 27 28/* 29 * Dynamic linker for ELF. 30 * 31 * John Polstra <jdp@polstra.com>. 32 */ 33 34#include <sys/param.h> 35#include <sys/mman.h> 36#include <machine/ia64_cpu.h> 37 38#include <dlfcn.h> 39#include <err.h> 40#include <errno.h> 41#include <fcntl.h> 42#include <stdarg.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <unistd.h> 47 48#include "debug.h" 49#include "rtld.h" 50 51extern Elf_Dyn _DYNAMIC; 52 53/* 54 * Macros for loading/storing unaligned 64-bit values. These are 55 * needed because relocations can point to unaligned data. This 56 * occurs in the DWARF2 exception frame tables generated by the 57 * compiler, for instance. 58 * 59 * We don't use these when relocating jump slots and GOT entries, 60 * since they are guaranteed to be aligned. 61 * 62 * XXX dfr stub for now. 63 */ 64#define load64(p) (*(u_int64_t *) (p)) 65#define store64(p, v) (*(u_int64_t *) (p) = (v)) 66 67/* Allocate an @fptr. */ 68 69#define FPTR_CHUNK_SIZE 64 70 71struct fptr_chunk { 72 struct fptr fptrs[FPTR_CHUNK_SIZE]; 73}; 74 75static struct fptr_chunk first_chunk; 76static struct fptr_chunk *current_chunk = &first_chunk; 77static struct fptr *next_fptr = &first_chunk.fptrs[0]; 78static struct fptr *last_fptr = &first_chunk.fptrs[FPTR_CHUNK_SIZE]; 79 80/* 81 * We use static storage initially so that we don't have to call 82 * malloc during init_rtld(). 83 */ 84static struct fptr * 85alloc_fptr(Elf_Addr target, Elf_Addr gp) 86{ 87 struct fptr* fptr; 88 89 if (next_fptr == last_fptr) { 90 current_chunk = malloc(sizeof(struct fptr_chunk)); 91 next_fptr = ¤t_chunk->fptrs[0]; 92 last_fptr = ¤t_chunk->fptrs[FPTR_CHUNK_SIZE]; 93 } 94 fptr = next_fptr; 95 next_fptr++; 96 fptr->target = target; 97 fptr->gp = gp; 98 return fptr; 99} 100 101static struct fptr ** 102alloc_fptrs(Obj_Entry *obj, bool mapped) 103{ 104 struct fptr **fptrs; 105 size_t fbytes; 106 107 fbytes = obj->nchains * sizeof(struct fptr *); 108 109 /* 110 * Avoid malloc, if requested. Happens when relocating 111 * rtld itself on startup. 112 */ 113 if (mapped) { 114 fptrs = mmap(NULL, fbytes, PROT_READ|PROT_WRITE, 115 MAP_ANON, -1, 0); 116 if (fptrs == MAP_FAILED) 117 fptrs = NULL; 118 } else { 119 fptrs = malloc(fbytes); 120 if (fptrs != NULL) 121 memset(fptrs, 0, fbytes); 122 } 123 124 /* 125 * This assertion is necessary to guarantee function pointer 126 * uniqueness 127 */ 128 assert(fptrs != NULL); 129 130 return (obj->priv = fptrs); 131} 132 133static void 134free_fptrs(Obj_Entry *obj, bool mapped) 135{ 136 struct fptr **fptrs; 137 size_t fbytes; 138 139 fptrs = obj->priv; 140 if (fptrs == NULL) 141 return; 142 143 fbytes = obj->nchains * sizeof(struct fptr *); 144 if (mapped) 145 munmap(fptrs, fbytes); 146 else 147 free(fptrs); 148 obj->priv = NULL; 149} 150 151/* Relocate a non-PLT object with addend. */ 152static int 153reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela, 154 SymCache *cache) 155{ 156 struct fptr **fptrs; 157 Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset); 158 159 switch (ELF_R_TYPE(rela->r_info)) { 160 case R_IA64_REL64LSB: 161 /* 162 * We handle rtld's relocations in rtld_start.S 163 */ 164 if (obj != obj_rtld) 165 store64(where, 166 load64(where) + (Elf_Addr) obj->relocbase); 167 break; 168 169 case R_IA64_DIR64LSB: { 170 const Elf_Sym *def; 171 const Obj_Entry *defobj; 172 Elf_Addr target; 173 174 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 175 false, cache); 176 if (def == NULL) 177 return -1; 178 179 target = (def->st_shndx != SHN_UNDEF) 180 ? (Elf_Addr)(defobj->relocbase + def->st_value) : 0; 181 store64(where, target + rela->r_addend); 182 break; 183 } 184 185 case R_IA64_FPTR64LSB: { 186 /* 187 * We have to make sure that all @fptr references to 188 * the same function are identical so that code can 189 * compare function pointers. 190 */ 191 const Elf_Sym *def; 192 const Obj_Entry *defobj; 193 struct fptr *fptr = 0; 194 Elf_Addr target, gp; 195 int sym_index; 196 197 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 198 false, cache); 199 if (def == NULL) 200 return -1; 201 202 if (def->st_shndx != SHN_UNDEF) { 203 target = (Elf_Addr)(defobj->relocbase + def->st_value); 204 gp = (Elf_Addr)defobj->pltgot; 205 206 /* rtld is allowed to reference itself only */ 207 assert(!obj->rtld || obj == defobj); 208 fptrs = defobj->priv; 209 if (fptrs == NULL) 210 fptrs = alloc_fptrs((Obj_Entry *) defobj, 211 obj->rtld); 212 213 sym_index = def - defobj->symtab; 214 215 /* 216 * Find the @fptr, using fptrs as a helper. 217 */ 218 if (fptrs) 219 fptr = fptrs[sym_index]; 220 if (!fptr) { 221 fptr = alloc_fptr(target, gp); 222 if (fptrs) 223 fptrs[sym_index] = fptr; 224 } 225 } else 226 fptr = NULL; 227 228 store64(where, (Elf_Addr)fptr); 229 break; 230 } 231 232 case R_IA64_IPLTLSB: { 233 /* 234 * Relocation typically used to populate C++ virtual function 235 * tables. It creates a 128-bit function descriptor at the 236 * specified memory address. 237 */ 238 const Elf_Sym *def; 239 const Obj_Entry *defobj; 240 struct fptr *fptr; 241 Elf_Addr target, gp; 242 243 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 244 false, cache); 245 if (def == NULL) 246 return -1; 247 248 if (def->st_shndx != SHN_UNDEF) { 249 target = (Elf_Addr)(defobj->relocbase + def->st_value); 250 gp = (Elf_Addr)defobj->pltgot; 251 } else { 252 target = 0; 253 gp = 0; 254 } 255 256 fptr = (void*)where; 257 store64(&fptr->target, target); 258 store64(&fptr->gp, gp); 259 break; 260 } 261 262 case R_IA64_DTPMOD64LSB: { 263 const Elf_Sym *def; 264 const Obj_Entry *defobj; 265 266 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 267 false, cache); 268 if (def == NULL) 269 return -1; 270 271 store64(where, defobj->tlsindex); 272 break; 273 } 274 275 case R_IA64_DTPREL64LSB: { 276 const Elf_Sym *def; 277 const Obj_Entry *defobj; 278 279 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 280 false, cache); 281 if (def == NULL) 282 return -1; 283 284 store64(where, def->st_value + rela->r_addend); 285 break; 286 } 287 288 case R_IA64_TPREL64LSB: { 289 const Elf_Sym *def; 290 const Obj_Entry *defobj; 291 292 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 293 false, cache); 294 if (def == NULL) 295 return -1; 296 297 /* 298 * We lazily allocate offsets for static TLS as we 299 * see the first relocation that references the 300 * TLS block. This allows us to support (small 301 * amounts of) static TLS in dynamically loaded 302 * modules. If we run out of space, we generate an 303 * error. 304 */ 305 if (!defobj->tls_done) { 306 if (!allocate_tls_offset((Obj_Entry*) defobj)) { 307 _rtld_error("%s: No space available for static " 308 "Thread Local Storage", obj->path); 309 return -1; 310 } 311 } 312 313 store64(where, defobj->tlsoffset + def->st_value + rela->r_addend); 314 break; 315 } 316 317 case R_IA64_NONE: 318 break; 319 320 default: 321 _rtld_error("%s: Unsupported relocation type %u" 322 " in non-PLT relocations\n", obj->path, 323 (unsigned int)ELF_R_TYPE(rela->r_info)); 324 return -1; 325 } 326 327 return(0); 328} 329 330/* Process the non-PLT relocations. */ 331int 332reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) 333{ 334 const Elf_Rel *rellim; 335 const Elf_Rel *rel; 336 const Elf_Rela *relalim; 337 const Elf_Rela *rela; 338 SymCache *cache; 339 int bytes = obj->nchains * sizeof(SymCache); 340 int r = -1; 341 342 /* 343 * The dynamic loader may be called from a thread, we have 344 * limited amounts of stack available so we cannot use alloca(). 345 */ 346 cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0); 347 if (cache == MAP_FAILED) 348 cache = NULL; 349 350 /* Perform relocations without addend if there are any: */ 351 rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize); 352 for (rel = obj->rel; obj->rel != NULL && rel < rellim; rel++) { 353 Elf_Rela locrela; 354 355 locrela.r_info = rel->r_info; 356 locrela.r_offset = rel->r_offset; 357 locrela.r_addend = 0; 358 if (reloc_non_plt_obj(obj_rtld, obj, &locrela, cache)) 359 goto done; 360 } 361 362 /* Perform relocations with addend if there are any: */ 363 relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize); 364 for (rela = obj->rela; obj->rela != NULL && rela < relalim; rela++) { 365 if (reloc_non_plt_obj(obj_rtld, obj, rela, cache)) 366 goto done; 367 } 368 369 r = 0; 370done: 371 if (cache) 372 munmap(cache, bytes); 373 374 /* 375 * Release temporarily mapped fptrs if relocating 376 * rtld object itself. A new table will be created 377 * in make_function_pointer using malloc when needed. 378 */ 379 if (obj->rtld && obj->priv) 380 free_fptrs(obj, true); 381 382 return (r); 383} 384 385/* Process the PLT relocations. */ 386int 387reloc_plt(Obj_Entry *obj) 388{ 389 /* All PLT relocations are the same kind: Elf_Rel or Elf_Rela. */ 390 if (obj->pltrelsize != 0) { 391 const Elf_Rel *rellim; 392 const Elf_Rel *rel; 393 394 rellim = (const Elf_Rel *) 395 ((char *)obj->pltrel + obj->pltrelsize); 396 for (rel = obj->pltrel; rel < rellim; rel++) { 397 Elf_Addr *where; 398 399 assert(ELF_R_TYPE(rel->r_info) == R_IA64_IPLTLSB); 400 401 /* Relocate the @fptr pointing into the PLT. */ 402 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 403 *where += (Elf_Addr)obj->relocbase; 404 } 405 } else { 406 const Elf_Rela *relalim; 407 const Elf_Rela *rela; 408 409 relalim = (const Elf_Rela *) 410 ((char *)obj->pltrela + obj->pltrelasize); 411 for (rela = obj->pltrela; rela < relalim; rela++) { 412 Elf_Addr *where; 413 414 assert(ELF_R_TYPE(rela->r_info) == R_IA64_IPLTLSB); 415 416 /* Relocate the @fptr pointing into the PLT. */ 417 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 418 *where += (Elf_Addr)obj->relocbase; 419 } 420 } 421 return 0; 422} 423 424/* Relocate the jump slots in an object. */ 425int 426reloc_jmpslots(Obj_Entry *obj) 427{ 428 if (obj->jmpslots_done) 429 return 0; 430 /* All PLT relocations are the same kind: Elf_Rel or Elf_Rela. */ 431 if (obj->pltrelsize != 0) { 432 const Elf_Rel *rellim; 433 const Elf_Rel *rel; 434 435 rellim = (const Elf_Rel *) 436 ((char *)obj->pltrel + obj->pltrelsize); 437 for (rel = obj->pltrel; rel < rellim; rel++) { 438 Elf_Addr *where; 439 const Elf_Sym *def; 440 const Obj_Entry *defobj; 441 442 assert(ELF_R_TYPE(rel->r_info) == R_IA64_IPLTLSB); 443 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 444 def = find_symdef(ELF_R_SYM(rel->r_info), obj, 445 &defobj, true, NULL); 446 if (def == NULL) 447 return -1; 448 reloc_jmpslot(where, 449 (Elf_Addr)(defobj->relocbase 450 + def->st_value), 451 defobj, obj, rel); 452 } 453 } else { 454 const Elf_Rela *relalim; 455 const Elf_Rela *rela; 456 457 relalim = (const Elf_Rela *) 458 ((char *)obj->pltrela + obj->pltrelasize); 459 for (rela = obj->pltrela; rela < relalim; rela++) { 460 Elf_Addr *where; 461 const Elf_Sym *def; 462 const Obj_Entry *defobj; 463 464 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 465 def = find_symdef(ELF_R_SYM(rela->r_info), obj, 466 &defobj, true, NULL); 467 if (def == NULL) 468 return -1; 469 reloc_jmpslot(where, 470 (Elf_Addr)(defobj->relocbase 471 + def->st_value), 472 defobj, obj, (Elf_Rel *)rela); 473 } 474 } 475 obj->jmpslots_done = true; 476 return 0; 477} 478 479/* Fixup the jump slot at "where" to transfer control to "target". */ 480Elf_Addr 481reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *obj, 482 const Obj_Entry *refobj, const Elf_Rel *rel) 483{ 484 Elf_Addr stubaddr; 485 486 dbg(" reloc_jmpslot: where=%p, target=%p, gp=%p", 487 (void *)where, (void *)target, (void *)obj->pltgot); 488 stubaddr = *where; 489 if (stubaddr != target) { 490 491 /* 492 * Point this @fptr directly at the target. Update the 493 * gp value first so that we don't break another cpu 494 * which is currently executing the PLT entry. 495 */ 496 where[1] = (Elf_Addr) obj->pltgot; 497 ia64_mf(); 498 where[0] = target; 499 ia64_mf(); 500 } 501 502 /* 503 * The caller needs an @fptr for the adjusted entry. The PLT 504 * entry serves this purpose nicely. 505 */ 506 return (Elf_Addr) where; 507} 508 509/* 510 * XXX ia64 doesn't seem to have copy relocations. 511 * 512 * Returns 0 on success, -1 on failure. 513 */ 514int 515do_copy_relocations(Obj_Entry *dstobj) 516{ 517 518 return 0; 519} 520 521/* 522 * Return the @fptr representing a given function symbol. 523 */ 524void * 525make_function_pointer(const Elf_Sym *sym, const Obj_Entry *obj) 526{ 527 struct fptr **fptrs = obj->priv; 528 int index = sym - obj->symtab; 529 530 if (!fptrs) { 531 /* 532 * This should only happen for something like 533 * dlsym("dlopen"). Actually, I'm not sure it can ever 534 * happen. 535 */ 536 fptrs = alloc_fptrs((Obj_Entry *) obj, false); 537 } 538 if (!fptrs[index]) { 539 Elf_Addr target, gp; 540 target = (Elf_Addr) (obj->relocbase + sym->st_value); 541 gp = (Elf_Addr) obj->pltgot; 542 fptrs[index] = alloc_fptr(target, gp); 543 } 544 return fptrs[index]; 545} 546 547void 548call_initfini_pointer(const Obj_Entry *obj, Elf_Addr target) 549{ 550 struct fptr fptr; 551 552 fptr.gp = (Elf_Addr) obj->pltgot; 553 fptr.target = target; 554 dbg(" initfini: target=%p, gp=%p", 555 (void *) fptr.target, (void *) fptr.gp); 556 ((InitFunc) &fptr)(); 557} 558 559/* Initialize the special PLT entries. */ 560void 561init_pltgot(Obj_Entry *obj) 562{ 563 const Elf_Dyn *dynp; 564 Elf_Addr *pltres = 0; 565 566 /* 567 * When there are no PLT relocations, the DT_IA64_PLT_RESERVE entry 568 * is bogus. Do not setup the BOR pointers in that case. An example 569 * of where this happens is /usr/lib/libxpg4.so.3. 570 */ 571 if (obj->pltrelasize == 0 && obj->pltrelsize == 0) 572 return; 573 574 /* 575 * Find the PLT RESERVE section. 576 */ 577 for (dynp = obj->dynamic; dynp->d_tag != DT_NULL; dynp++) { 578 if (dynp->d_tag == DT_IA64_PLT_RESERVE) 579 pltres = (u_int64_t *) 580 (obj->relocbase + dynp->d_un.d_ptr); 581 } 582 if (!pltres) 583 errx(1, "Can't find DT_IA64_PLT_RESERVE entry"); 584 585 /* 586 * The PLT RESERVE section is used to get values to pass to 587 * _rtld_bind when lazy binding. 588 */ 589 pltres[0] = (Elf_Addr) obj; 590 pltres[1] = FPTR_TARGET(_rtld_bind_start); 591 pltres[2] = FPTR_GP(_rtld_bind_start); 592} 593 594void 595allocate_initial_tls(Obj_Entry *list) 596{ 597 register Elf_Addr** tp __asm__("r13"); 598 599 /* 600 * Fix the size of the static TLS block by using the maximum 601 * offset allocated so far and adding a bit for dynamic modules to 602 * use. 603 */ 604 tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; 605 606 tp = allocate_tls(list, 0, 16, 16); 607} 608 609void *__tls_get_addr(unsigned long module, unsigned long offset) 610{ 611 register Elf_Addr** tp __asm__("r13"); 612 613 return tls_get_addr_common(tp, module, offset); 614} 615