1 /*- 2 * Copyright (c) 2014-2015 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * Portions of this software were developed by Andrew Turner 6 * under sponsorship from the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/types.h> 34 35 #include <stdlib.h> 36 37 #include "debug.h" 38 #include "rtld.h" 39 #include "rtld_printf.h" 40 41 /* 42 * It is possible for the compiler to emit relocations for unaligned data. 43 * We handle this situation with these inlines. 44 */ 45 #define RELOC_ALIGNED_P(x) \ 46 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0) 47 48 /* 49 * This is not the correct prototype, but we only need it for 50 * a function pointer to a simple asm function. 51 */ 52 void *_rtld_tlsdesc(void *); 53 void *_rtld_tlsdesc_dynamic(void *); 54 55 void _exit(int); 56 57 void 58 init_pltgot(Obj_Entry *obj) 59 { 60 61 if (obj->pltgot != NULL) { 62 obj->pltgot[1] = (Elf_Addr) obj; 63 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; 64 } 65 } 66 67 int 68 do_copy_relocations(Obj_Entry *dstobj) 69 { 70 const Obj_Entry *srcobj, *defobj; 71 const Elf_Rela *relalim; 72 const Elf_Rela *rela; 73 const Elf_Sym *srcsym; 74 const Elf_Sym *dstsym; 75 const void *srcaddr; 76 const char *name; 77 void *dstaddr; 78 SymLook req; 79 size_t size; 80 int res; 81 82 /* 83 * COPY relocs are invalid outside of the main program 84 */ 85 assert(dstobj->mainprog); 86 87 relalim = (const Elf_Rela *)((const char *)dstobj->rela + 88 dstobj->relasize); 89 for (rela = dstobj->rela; rela < relalim; rela++) { 90 if (ELF_R_TYPE(rela->r_info) != R_AARCH64_COPY) 91 continue; 92 93 dstaddr = (void *)(dstobj->relocbase + rela->r_offset); 94 dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info); 95 name = dstobj->strtab + dstsym->st_name; 96 size = dstsym->st_size; 97 98 symlook_init(&req, name); 99 req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); 100 req.flags = SYMLOOK_EARLY; 101 102 for (srcobj = globallist_next(dstobj); srcobj != NULL; 103 srcobj = globallist_next(srcobj)) { 104 res = symlook_obj(&req, srcobj); 105 if (res == 0) { 106 srcsym = req.sym_out; 107 defobj = req.defobj_out; 108 break; 109 } 110 } 111 if (srcobj == NULL) { 112 _rtld_error("Undefined symbol \"%s\" referenced from " 113 "COPY relocation in %s", name, dstobj->path); 114 return (-1); 115 } 116 117 srcaddr = (const void *)(defobj->relocbase + srcsym->st_value); 118 memcpy(dstaddr, srcaddr, size); 119 } 120 121 return (0); 122 } 123 124 struct tls_data { 125 int64_t index; 126 Obj_Entry *obj; 127 const Elf_Rela *rela; 128 }; 129 130 int64_t rtld_tlsdesc_handle(struct tls_data *tlsdesc, int flags); 131 132 static struct tls_data * 133 reloc_tlsdesc_alloc(Obj_Entry *obj, const Elf_Rela *rela) 134 { 135 struct tls_data *tlsdesc; 136 137 tlsdesc = xmalloc(sizeof(struct tls_data)); 138 tlsdesc->index = -1; 139 tlsdesc->obj = obj; 140 tlsdesc->rela = rela; 141 142 return (tlsdesc); 143 } 144 145 /* 146 * Look up the symbol to find its tls index 147 */ 148 static int64_t 149 rtld_tlsdesc_handle_locked(struct tls_data *tlsdesc, int flags, 150 RtldLockState *lockstate) 151 { 152 const Elf_Rela *rela; 153 const Elf_Sym *def; 154 const Obj_Entry *defobj; 155 Obj_Entry *obj; 156 157 rela = tlsdesc->rela; 158 obj = tlsdesc->obj; 159 160 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, flags, NULL, 161 lockstate); 162 if (def == NULL) 163 rtld_die(); 164 165 tlsdesc->index = defobj->tlsoffset + def->st_value + rela->r_addend; 166 167 return (tlsdesc->index); 168 } 169 170 int64_t 171 rtld_tlsdesc_handle(struct tls_data *tlsdesc, int flags) 172 { 173 RtldLockState lockstate; 174 175 /* We have already found the index, return it */ 176 if (tlsdesc->index >= 0) 177 return (tlsdesc->index); 178 179 wlock_acquire(rtld_bind_lock, &lockstate); 180 /* tlsdesc->index may have been set by another thread */ 181 if (tlsdesc->index == -1) 182 rtld_tlsdesc_handle_locked(tlsdesc, flags, &lockstate); 183 lock_release(rtld_bind_lock, &lockstate); 184 185 return (tlsdesc->index); 186 } 187 188 static void 189 reloc_tlsdesc(Obj_Entry *obj, const Elf_Rela *rela, Elf_Addr *where) 190 { 191 if (ELF_R_SYM(rela->r_info) == 0) { 192 where[0] = (Elf_Addr)_rtld_tlsdesc; 193 where[1] = obj->tlsoffset + rela->r_addend; 194 } else { 195 where[0] = (Elf_Addr)_rtld_tlsdesc_dynamic; 196 where[1] = (Elf_Addr)reloc_tlsdesc_alloc(obj, rela); 197 } 198 } 199 200 /* 201 * Process the PLT relocations. 202 */ 203 int 204 reloc_plt(Obj_Entry *obj) 205 { 206 const Elf_Rela *relalim; 207 const Elf_Rela *rela; 208 209 relalim = (const Elf_Rela *)((const char *)obj->pltrela + 210 obj->pltrelasize); 211 for (rela = obj->pltrela; rela < relalim; rela++) { 212 Elf_Addr *where; 213 214 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 215 216 switch(ELF_R_TYPE(rela->r_info)) { 217 case R_AARCH64_JUMP_SLOT: 218 *where += (Elf_Addr)obj->relocbase; 219 break; 220 case R_AARCH64_TLSDESC: 221 reloc_tlsdesc(obj, rela, where); 222 break; 223 case R_AARCH64_IRELATIVE: 224 obj->irelative = true; 225 break; 226 default: 227 _rtld_error("Unknown relocation type %u in PLT", 228 (unsigned int)ELF_R_TYPE(rela->r_info)); 229 return (-1); 230 } 231 } 232 233 return (0); 234 } 235 236 /* 237 * LD_BIND_NOW was set - force relocation for all jump slots 238 */ 239 int 240 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 241 { 242 const Obj_Entry *defobj; 243 const Elf_Rela *relalim; 244 const Elf_Rela *rela; 245 const Elf_Sym *def; 246 247 if (obj->jmpslots_done) 248 return (0); 249 250 relalim = (const Elf_Rela *)((const char *)obj->pltrela + 251 obj->pltrelasize); 252 for (rela = obj->pltrela; rela < relalim; rela++) { 253 Elf_Addr *where, target; 254 255 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 256 switch(ELF_R_TYPE(rela->r_info)) { 257 case R_AARCH64_JUMP_SLOT: 258 def = find_symdef(ELF_R_SYM(rela->r_info), obj, 259 &defobj, SYMLOOK_IN_PLT | flags, NULL, lockstate); 260 if (def == NULL) 261 return (-1); 262 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 263 obj->gnu_ifunc = true; 264 continue; 265 } 266 target = (Elf_Addr)(defobj->relocbase + def->st_value); 267 reloc_jmpslot(where, target, defobj, obj, 268 (const Elf_Rel *)rela); 269 break; 270 } 271 } 272 obj->jmpslots_done = true; 273 274 return (0); 275 } 276 277 int 278 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) 279 { 280 const Elf_Rela *relalim; 281 const Elf_Rela *rela; 282 Elf_Addr *where, target, *ptr; 283 284 if (!obj->irelative) 285 return (0); 286 relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); 287 for (rela = obj->pltrela; rela < relalim; rela++) { 288 if (ELF_R_TYPE(rela->r_info) == R_AARCH64_IRELATIVE) { 289 ptr = (Elf_Addr *)(obj->relocbase + rela->r_addend); 290 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 291 lock_release(rtld_bind_lock, lockstate); 292 target = call_ifunc_resolver(ptr); 293 wlock_acquire(rtld_bind_lock, lockstate); 294 *where = target; 295 } 296 } 297 obj->irelative = false; 298 return (0); 299 } 300 301 int 302 reloc_gnu_ifunc(Obj_Entry *obj, int flags, 303 struct Struct_RtldLockState *lockstate) 304 { 305 const Elf_Rela *relalim; 306 const Elf_Rela *rela; 307 Elf_Addr *where, target; 308 const Elf_Sym *def; 309 const Obj_Entry *defobj; 310 311 if (!obj->gnu_ifunc) 312 return (0); 313 relalim = (const Elf_Rela *)((const char *)obj->pltrela + obj->pltrelasize); 314 for (rela = obj->pltrela; rela < relalim; rela++) { 315 if (ELF_R_TYPE(rela->r_info) == R_AARCH64_JUMP_SLOT) { 316 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 317 def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, 318 SYMLOOK_IN_PLT | flags, NULL, lockstate); 319 if (def == NULL) 320 return (-1); 321 if (ELF_ST_TYPE(def->st_info) != STT_GNU_IFUNC) 322 continue; 323 lock_release(rtld_bind_lock, lockstate); 324 target = (Elf_Addr)rtld_resolve_ifunc(defobj, def); 325 wlock_acquire(rtld_bind_lock, lockstate); 326 reloc_jmpslot(where, target, defobj, obj, 327 (const Elf_Rel *)rela); 328 } 329 } 330 obj->gnu_ifunc = false; 331 return (0); 332 } 333 334 Elf_Addr 335 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, 336 const Obj_Entry *defobj __unused, const Obj_Entry *obj __unused, 337 const Elf_Rel *rel) 338 { 339 340 assert(ELF_R_TYPE(rel->r_info) == R_AARCH64_JUMP_SLOT || 341 ELF_R_TYPE(rel->r_info) == R_AARCH64_IRELATIVE); 342 343 if (*where != target && !ld_bind_not) 344 *where = target; 345 return (target); 346 } 347 348 void 349 ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) 350 { 351 352 } 353 354 void 355 pre_init(void) 356 { 357 358 } 359 360 /* 361 * Process non-PLT relocations 362 */ 363 int 364 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 365 RtldLockState *lockstate) 366 { 367 const Obj_Entry *defobj; 368 const Elf_Rela *relalim; 369 const Elf_Rela *rela; 370 const Elf_Sym *def; 371 SymCache *cache; 372 Elf_Addr *where, symval; 373 374 /* 375 * The dynamic loader may be called from a thread, we have 376 * limited amounts of stack available so we cannot use alloca(). 377 */ 378 if (obj == obj_rtld) 379 cache = NULL; 380 else 381 cache = calloc(obj->dynsymcount, sizeof(SymCache)); 382 /* No need to check for NULL here */ 383 384 relalim = (const Elf_Rela *)((const char *)obj->rela + obj->relasize); 385 for (rela = obj->rela; rela < relalim; rela++) { 386 /* 387 * First, resolve symbol for relocations which 388 * reference symbols. 389 */ 390 switch (ELF_R_TYPE(rela->r_info)) { 391 case R_AARCH64_ABS64: 392 case R_AARCH64_GLOB_DAT: 393 case R_AARCH64_TLS_TPREL64: 394 def = find_symdef(ELF_R_SYM(rela->r_info), obj, 395 &defobj, flags, cache, lockstate); 396 if (def == NULL) 397 return (-1); 398 /* 399 * If symbol is IFUNC, only perform relocation 400 * when caller allowed it by passing 401 * SYMLOOK_IFUNC flag. Skip the relocations 402 * otherwise. 403 * 404 * Also error out in case IFUNC relocations 405 * are specified for TLS, which cannot be 406 * usefully interpreted. 407 */ 408 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 409 switch (ELF_R_TYPE(rela->r_info)) { 410 case R_AARCH64_ABS64: 411 case R_AARCH64_GLOB_DAT: 412 if ((flags & SYMLOOK_IFUNC) == 0) { 413 obj->non_plt_gnu_ifunc = true; 414 continue; 415 } 416 symval = (Elf_Addr)rtld_resolve_ifunc( 417 defobj, def); 418 break; 419 default: 420 _rtld_error("%s: IFUNC for TLS reloc", 421 obj->path); 422 return (-1); 423 } 424 } else { 425 if ((flags & SYMLOOK_IFUNC) != 0) 426 continue; 427 symval = (Elf_Addr)defobj->relocbase + 428 def->st_value; 429 } 430 break; 431 default: 432 if ((flags & SYMLOOK_IFUNC) != 0) 433 continue; 434 } 435 436 where = (Elf_Addr *)(obj->relocbase + rela->r_offset); 437 438 switch (ELF_R_TYPE(rela->r_info)) { 439 case R_AARCH64_ABS64: 440 case R_AARCH64_GLOB_DAT: 441 *where = symval + rela->r_addend; 442 break; 443 case R_AARCH64_COPY: 444 /* 445 * These are deferred until all other relocations have 446 * been done. All we do here is make sure that the 447 * COPY relocation is not in a shared library. They 448 * are allowed only in executable files. 449 */ 450 if (!obj->mainprog) { 451 _rtld_error("%s: Unexpected R_AARCH64_COPY " 452 "relocation in shared library", obj->path); 453 return (-1); 454 } 455 break; 456 case R_AARCH64_TLSDESC: 457 reloc_tlsdesc(obj, rela, where); 458 break; 459 case R_AARCH64_TLS_TPREL64: 460 /* 461 * We lazily allocate offsets for static TLS as we 462 * see the first relocation that references the 463 * TLS block. This allows us to support (small 464 * amounts of) static TLS in dynamically loaded 465 * modules. If we run out of space, we generate an 466 * error. 467 */ 468 if (!defobj->tls_done) { 469 if (!allocate_tls_offset( 470 __DECONST(Obj_Entry *, defobj))) { 471 _rtld_error( 472 "%s: No space available for static " 473 "Thread Local Storage", obj->path); 474 return (-1); 475 } 476 } 477 478 *where = def->st_value + rela->r_addend + 479 defobj->tlsoffset; 480 break; 481 case R_AARCH64_RELATIVE: 482 *where = (Elf_Addr)(obj->relocbase + rela->r_addend); 483 break; 484 default: 485 rtld_printf("%s: Unhandled relocation %lu\n", 486 obj->path, ELF_R_TYPE(rela->r_info)); 487 return (-1); 488 } 489 } 490 491 return (0); 492 } 493 494 void 495 allocate_initial_tls(Obj_Entry *objs) 496 { 497 Elf_Addr **tp; 498 499 /* 500 * Fix the size of the static TLS block by using the maximum 501 * offset allocated so far and adding a bit for dynamic modules to 502 * use. 503 */ 504 tls_static_space = tls_last_offset + tls_last_size + 505 RTLD_STATIC_TLS_EXTRA; 506 507 tp = (Elf_Addr **) allocate_tls(objs, NULL, TLS_TCB_SIZE, 16); 508 509 asm volatile("msr tpidr_el0, %0" : : "r"(tp)); 510 } 511 512 void * 513 __tls_get_addr(tls_index* ti) 514 { 515 char *p; 516 void *_tp; 517 518 __asm __volatile("mrs %0, tpidr_el0" : "=r" (_tp)); 519 p = tls_get_addr_common((Elf_Addr **)(_tp), ti->ti_module, ti->ti_offset); 520 521 return (p); 522 } 523