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