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