reloc.c revision 309061
1/* $NetBSD: mdreloc.c,v 1.23 2003/07/26 15:04:38 mrg Exp $ */ 2 3#include <sys/cdefs.h> 4__FBSDID("$FreeBSD: stable/10/libexec/rtld-elf/arm/reloc.c 309061 2016-11-23 17:48:43Z kib $"); 5#include <sys/param.h> 6#include <sys/mman.h> 7 8#include <errno.h> 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12#include <unistd.h> 13 14#include "machine/sysarch.h" 15 16#include "debug.h" 17#include "rtld.h" 18 19void 20init_pltgot(Obj_Entry *obj) 21{ 22 if (obj->pltgot != NULL) { 23 obj->pltgot[1] = (Elf_Addr) obj; 24 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; 25 } 26} 27 28int 29do_copy_relocations(Obj_Entry *dstobj) 30{ 31 const Elf_Rel *rellim; 32 const Elf_Rel *rel; 33 34 assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ 35 36 rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize); 37 for (rel = dstobj->rel; rel < rellim; rel++) { 38 if (ELF_R_TYPE(rel->r_info) == R_ARM_COPY) { 39 void *dstaddr; 40 const Elf_Sym *dstsym; 41 const char *name; 42 size_t size; 43 const void *srcaddr; 44 const Elf_Sym *srcsym; 45 const Obj_Entry *srcobj, *defobj; 46 SymLook req; 47 int res; 48 49 dstaddr = (void *) (dstobj->relocbase + rel->r_offset); 50 dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info); 51 name = dstobj->strtab + dstsym->st_name; 52 size = dstsym->st_size; 53 54 symlook_init(&req, name); 55 req.ventry = fetch_ventry(dstobj, 56 ELF_R_SYM(rel->r_info)); 57 req.flags = SYMLOOK_EARLY; 58 59 for (srcobj = globallist_next(dstobj); srcobj != NULL; 60 srcobj = globallist_next(srcobj)) { 61 res = symlook_obj(&req, srcobj); 62 if (res == 0) { 63 srcsym = req.sym_out; 64 defobj = req.defobj_out; 65 break; 66 } 67 } 68 if (srcobj == NULL) { 69 _rtld_error( 70"Undefined symbol \"%s\" referenced from COPY relocation in %s", 71 name, dstobj->path); 72 return (-1); 73 } 74 75 srcaddr = (const void *)(defobj->relocbase + 76 srcsym->st_value); 77 memcpy(dstaddr, srcaddr, size); 78 } 79 } 80 return 0; 81} 82 83void _rtld_bind_start(void); 84void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 85 86int open(); 87int _open(); 88void 89_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 90{ 91 const Elf_Rel *rel = 0, *rellim; 92 Elf_Addr relsz = 0; 93 Elf_Addr *where; 94 uint32_t size; 95 96 for (; dynp->d_tag != DT_NULL; dynp++) { 97 switch (dynp->d_tag) { 98 case DT_REL: 99 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr); 100 break; 101 case DT_RELSZ: 102 relsz = dynp->d_un.d_val; 103 break; 104 } 105 } 106 rellim = (const Elf_Rel *)((caddr_t)rel + relsz); 107 size = (rellim - 1)->r_offset - rel->r_offset; 108 for (; rel < rellim; rel++) { 109 where = (Elf_Addr *)(relocbase + rel->r_offset); 110 111 *where += (Elf_Addr)relocbase; 112 } 113} 114/* 115 * It is possible for the compiler to emit relocations for unaligned data. 116 * We handle this situation with these inlines. 117 */ 118#define RELOC_ALIGNED_P(x) \ 119 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0) 120 121static __inline Elf_Addr 122load_ptr(void *where) 123{ 124 Elf_Addr res; 125 126 memcpy(&res, where, sizeof(res)); 127 128 return (res); 129} 130 131static __inline void 132store_ptr(void *where, Elf_Addr val) 133{ 134 135 memcpy(where, &val, sizeof(val)); 136} 137 138static int 139reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache, 140 int flags, RtldLockState *lockstate) 141{ 142 Elf_Addr *where; 143 const Elf_Sym *def; 144 const Obj_Entry *defobj; 145 Elf_Addr tmp; 146 unsigned long symnum; 147 148 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 149 symnum = ELF_R_SYM(rel->r_info); 150 151 switch (ELF_R_TYPE(rel->r_info)) { 152 case R_ARM_NONE: 153 break; 154 155#if 1 /* XXX should not occur */ 156 case R_ARM_PC24: { /* word32 S - P + A */ 157 Elf32_Sword addend; 158 159 /* 160 * Extract addend and sign-extend if needed. 161 */ 162 addend = *where; 163 if (addend & 0x00800000) 164 addend |= 0xff000000; 165 166 def = find_symdef(symnum, obj, &defobj, flags, cache, 167 lockstate); 168 if (def == NULL) 169 return -1; 170 tmp = (Elf_Addr)obj->relocbase + def->st_value 171 - (Elf_Addr)where + (addend << 2); 172 if ((tmp & 0xfe000000) != 0xfe000000 && 173 (tmp & 0xfe000000) != 0) { 174 _rtld_error( 175 "%s: R_ARM_PC24 relocation @ %p to %s failed " 176 "(displacement %ld (%#lx) out of range)", 177 obj->path, where, 178 obj->strtab + obj->symtab[symnum].st_name, 179 (long) tmp, (long) tmp); 180 return -1; 181 } 182 tmp >>= 2; 183 *where = (*where & 0xff000000) | (tmp & 0x00ffffff); 184 dbg("PC24 %s in %s --> %p @ %p in %s", 185 obj->strtab + obj->symtab[symnum].st_name, 186 obj->path, (void *)*where, where, defobj->path); 187 break; 188 } 189#endif 190 191 case R_ARM_ABS32: /* word32 B + S + A */ 192 case R_ARM_GLOB_DAT: /* word32 B + S */ 193 def = find_symdef(symnum, obj, &defobj, flags, cache, 194 lockstate); 195 if (def == NULL) 196 return -1; 197 if (__predict_true(RELOC_ALIGNED_P(where))) { 198 tmp = *where + (Elf_Addr)defobj->relocbase + 199 def->st_value; 200 *where = tmp; 201 } else { 202 tmp = load_ptr(where) + 203 (Elf_Addr)defobj->relocbase + 204 def->st_value; 205 store_ptr(where, tmp); 206 } 207 dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s", 208 obj->strtab + obj->symtab[symnum].st_name, 209 obj->path, (void *)tmp, where, defobj->path); 210 break; 211 212 case R_ARM_RELATIVE: /* word32 B + A */ 213 if (__predict_true(RELOC_ALIGNED_P(where))) { 214 tmp = *where + (Elf_Addr)obj->relocbase; 215 *where = tmp; 216 } else { 217 tmp = load_ptr(where) + 218 (Elf_Addr)obj->relocbase; 219 store_ptr(where, tmp); 220 } 221 dbg("RELATIVE in %s --> %p", obj->path, 222 (void *)tmp); 223 break; 224 225 case R_ARM_COPY: 226 /* 227 * These are deferred until all other relocations have 228 * been done. All we do here is make sure that the 229 * COPY relocation is not in a shared library. They 230 * are allowed only in executable files. 231 */ 232 if (!obj->mainprog) { 233 _rtld_error( 234 "%s: Unexpected R_COPY relocation in shared library", 235 obj->path); 236 return -1; 237 } 238 dbg("COPY (avoid in main)"); 239 break; 240 241 case R_ARM_TLS_DTPOFF32: 242 def = find_symdef(symnum, obj, &defobj, flags, cache, 243 lockstate); 244 if (def == NULL) 245 return -1; 246 247 tmp = (Elf_Addr)(def->st_value); 248 if (__predict_true(RELOC_ALIGNED_P(where))) 249 *where = tmp; 250 else 251 store_ptr(where, tmp); 252 253 dbg("TLS_DTPOFF32 %s in %s --> %p", 254 obj->strtab + obj->symtab[symnum].st_name, 255 obj->path, (void *)tmp); 256 257 break; 258 case R_ARM_TLS_DTPMOD32: 259 def = find_symdef(symnum, obj, &defobj, flags, cache, 260 lockstate); 261 if (def == NULL) 262 return -1; 263 264 tmp = (Elf_Addr)(defobj->tlsindex); 265 if (__predict_true(RELOC_ALIGNED_P(where))) 266 *where = tmp; 267 else 268 store_ptr(where, tmp); 269 270 dbg("TLS_DTPMOD32 %s in %s --> %p", 271 obj->strtab + obj->symtab[symnum].st_name, 272 obj->path, (void *)tmp); 273 274 break; 275 276 case R_ARM_TLS_TPOFF32: 277 def = find_symdef(symnum, obj, &defobj, flags, cache, 278 lockstate); 279 if (def == NULL) 280 return -1; 281 282 if (!defobj->tls_done && allocate_tls_offset(obj)) 283 return -1; 284 285 /* XXX: FIXME */ 286 tmp = (Elf_Addr)def->st_value + defobj->tlsoffset + 287 TLS_TCB_SIZE; 288 if (__predict_true(RELOC_ALIGNED_P(where))) 289 *where = tmp; 290 else 291 store_ptr(where, tmp); 292 dbg("TLS_TPOFF32 %s in %s --> %p", 293 obj->strtab + obj->symtab[symnum].st_name, 294 obj->path, (void *)tmp); 295 break; 296 297 298 default: 299 dbg("sym = %lu, type = %lu, offset = %p, " 300 "contents = %p, symbol = %s", 301 symnum, (u_long)ELF_R_TYPE(rel->r_info), 302 (void *)rel->r_offset, (void *)load_ptr(where), 303 obj->strtab + obj->symtab[symnum].st_name); 304 _rtld_error("%s: Unsupported relocation type %ld " 305 "in non-PLT relocations\n", 306 obj->path, (u_long) ELF_R_TYPE(rel->r_info)); 307 return -1; 308 } 309 return 0; 310} 311 312/* 313 * * Process non-PLT relocations 314 * */ 315int 316reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 317 RtldLockState *lockstate) 318{ 319 const Elf_Rel *rellim; 320 const Elf_Rel *rel; 321 SymCache *cache; 322 int r = -1; 323 324 /* The relocation for the dynamic loader has already been done. */ 325 if (obj == obj_rtld) 326 return (0); 327 if ((flags & SYMLOOK_IFUNC) != 0) 328 /* XXX not implemented */ 329 return (0); 330 331 /* 332 * The dynamic loader may be called from a thread, we have 333 * limited amounts of stack available so we cannot use alloca(). 334 */ 335 cache = calloc(obj->dynsymcount, sizeof(SymCache)); 336 /* No need to check for NULL here */ 337 338 rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize); 339 for (rel = obj->rel; rel < rellim; rel++) { 340 if (reloc_nonplt_object(obj, rel, cache, flags, lockstate) < 0) 341 goto done; 342 } 343 r = 0; 344done: 345 if (cache != NULL) 346 free(cache); 347 return (r); 348} 349 350/* 351 * * Process the PLT relocations. 352 * */ 353int 354reloc_plt(Obj_Entry *obj) 355{ 356 const Elf_Rel *rellim; 357 const Elf_Rel *rel; 358 359 rellim = (const Elf_Rel *)((char *)obj->pltrel + 360 obj->pltrelsize); 361 for (rel = obj->pltrel; rel < rellim; rel++) { 362 Elf_Addr *where; 363 364 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); 365 366 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 367 *where += (Elf_Addr )obj->relocbase; 368 } 369 370 return (0); 371} 372 373/* 374 * * LD_BIND_NOW was set - force relocation for all jump slots 375 * */ 376int 377reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 378{ 379 const Obj_Entry *defobj; 380 const Elf_Rel *rellim; 381 const Elf_Rel *rel; 382 const Elf_Sym *def; 383 Elf_Addr *where; 384 Elf_Addr target; 385 386 rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); 387 for (rel = obj->pltrel; rel < rellim; rel++) { 388 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); 389 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 390 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, 391 SYMLOOK_IN_PLT | flags, NULL, lockstate); 392 if (def == NULL) { 393 dbg("reloc_jmpslots: sym not found"); 394 return (-1); 395 } 396 397 target = (Elf_Addr)(defobj->relocbase + def->st_value); 398 reloc_jmpslot(where, target, defobj, obj, 399 (const Elf_Rel *) rel); 400 } 401 402 obj->jmpslots_done = true; 403 404 return (0); 405} 406 407int 408reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) 409{ 410 411 /* XXX not implemented */ 412 return (0); 413} 414 415int 416reloc_gnu_ifunc(Obj_Entry *obj, int flags, 417 struct Struct_RtldLockState *lockstate) 418{ 419 420 /* XXX not implemented */ 421 return (0); 422} 423 424Elf_Addr 425reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj, 426 const Obj_Entry *obj, const Elf_Rel *rel) 427{ 428 429 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); 430 431 if (*where != target) 432 *where = target; 433 434 return target; 435} 436 437void 438ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) 439{ 440} 441 442void 443allocate_initial_tls(Obj_Entry *objs) 444{ 445#ifdef ARM_TP_ADDRESS 446 void **_tp = (void **)ARM_TP_ADDRESS; 447#endif 448 449 /* 450 * Fix the size of the static TLS block by using the maximum 451 * offset allocated so far and adding a bit for dynamic modules to 452 * use. 453 */ 454 455 tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; 456 457#ifdef ARM_TP_ADDRESS 458 (*_tp) = (void *) allocate_tls(objs, NULL, TLS_TCB_SIZE, 8); 459#else 460 sysarch(ARM_SET_TP, allocate_tls(objs, NULL, TLS_TCB_SIZE, 8)); 461#endif 462} 463 464void * 465__tls_get_addr(tls_index* ti) 466{ 467 char *p; 468#ifdef ARM_TP_ADDRESS 469 void **_tp = (void **)ARM_TP_ADDRESS; 470 471 p = tls_get_addr_common((Elf_Addr **)(*_tp), ti->ti_module, ti->ti_offset); 472#else 473 void *_tp; 474 __asm __volatile("mrc p15, 0, %0, c13, c0, 3" \ 475 : "=r" (_tp)); 476 p = tls_get_addr_common((Elf_Addr **)(_tp), ti->ti_module, ti->ti_offset); 477#endif 478 479 return (p); 480} 481