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 *) ((caddr_t) 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 int open(); 129 int _open(); 130 void 131 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 132 { 133 const Elf_Rel *rel = NULL, *rellim; 134 Elf_Addr relsz = 0; 135 Elf_Addr *where; 136 uint32_t size; 137 138 for (; dynp->d_tag != DT_NULL; dynp++) { 139 switch (dynp->d_tag) { 140 case DT_REL: 141 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr); 142 break; 143 case DT_RELSZ: 144 relsz = dynp->d_un.d_val; 145 break; 146 } 147 } 148 rellim = (const Elf_Rel *)((caddr_t)rel + relsz); 149 size = (rellim - 1)->r_offset - rel->r_offset; 150 for (; rel < rellim; rel++) { 151 where = (Elf_Addr *)(relocbase + rel->r_offset); 152 153 *where += (Elf_Addr)relocbase; 154 } 155 } 156 /* 157 * It is possible for the compiler to emit relocations for unaligned data. 158 * We handle this situation with these inlines. 159 */ 160 #define RELOC_ALIGNED_P(x) \ 161 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0) 162 163 static __inline Elf_Addr 164 load_ptr(void *where) 165 { 166 Elf_Addr res; 167 168 memcpy(&res, where, sizeof(res)); 169 170 return (res); 171 } 172 173 static __inline void 174 store_ptr(void *where, Elf_Addr val) 175 { 176 177 memcpy(where, &val, sizeof(val)); 178 } 179 180 static int 181 reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache, 182 int flags, RtldLockState *lockstate) 183 { 184 Elf_Addr *where; 185 const Elf_Sym *def; 186 const Obj_Entry *defobj; 187 Elf_Addr tmp; 188 unsigned long symnum; 189 190 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 191 symnum = ELF_R_SYM(rel->r_info); 192 193 switch (ELF_R_TYPE(rel->r_info)) { 194 case R_ARM_NONE: 195 break; 196 197 #if 1 /* XXX should not occur */ 198 case R_ARM_PC24: { /* word32 S - P + A */ 199 Elf32_Sword addend; 200 201 /* 202 * Extract addend and sign-extend if needed. 203 */ 204 addend = *where; 205 if (addend & 0x00800000) 206 addend |= 0xff000000; 207 208 def = find_symdef(symnum, obj, &defobj, flags, cache, 209 lockstate); 210 if (def == NULL) 211 return -1; 212 tmp = (Elf_Addr)obj->relocbase + def->st_value 213 - (Elf_Addr)where + (addend << 2); 214 if ((tmp & 0xfe000000) != 0xfe000000 && 215 (tmp & 0xfe000000) != 0) { 216 _rtld_error( 217 "%s: R_ARM_PC24 relocation @ %p to %s failed " 218 "(displacement %ld (%#lx) out of range)", 219 obj->path, where, 220 obj->strtab + obj->symtab[symnum].st_name, 221 (long) tmp, (long) tmp); 222 return -1; 223 } 224 tmp >>= 2; 225 *where = (*where & 0xff000000) | (tmp & 0x00ffffff); 226 dbg("PC24 %s in %s --> %p @ %p in %s", 227 obj->strtab + obj->symtab[symnum].st_name, 228 obj->path, (void *)*where, where, defobj->path); 229 break; 230 } 231 #endif 232 233 case R_ARM_ABS32: /* word32 B + S + A */ 234 case R_ARM_GLOB_DAT: /* word32 B + S */ 235 def = find_symdef(symnum, obj, &defobj, flags, cache, 236 lockstate); 237 if (def == NULL) 238 return -1; 239 if (__predict_true(RELOC_ALIGNED_P(where))) { 240 tmp = *where + (Elf_Addr)defobj->relocbase + 241 def->st_value; 242 *where = tmp; 243 } else { 244 tmp = load_ptr(where) + 245 (Elf_Addr)defobj->relocbase + 246 def->st_value; 247 store_ptr(where, tmp); 248 } 249 dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s", 250 obj->strtab + obj->symtab[symnum].st_name, 251 obj->path, (void *)tmp, where, defobj->path); 252 break; 253 254 case R_ARM_RELATIVE: /* word32 B + A */ 255 if (__predict_true(RELOC_ALIGNED_P(where))) { 256 tmp = *where + (Elf_Addr)obj->relocbase; 257 *where = tmp; 258 } else { 259 tmp = load_ptr(where) + 260 (Elf_Addr)obj->relocbase; 261 store_ptr(where, tmp); 262 } 263 dbg("RELATIVE in %s --> %p", obj->path, 264 (void *)tmp); 265 break; 266 267 case R_ARM_COPY: 268 /* 269 * These are deferred until all other relocations have 270 * been done. All we do here is make sure that the 271 * COPY relocation is not in a shared library. They 272 * are allowed only in executable files. 273 */ 274 if (!obj->mainprog) { 275 _rtld_error( 276 "%s: Unexpected R_COPY relocation in shared library", 277 obj->path); 278 return -1; 279 } 280 dbg("COPY (avoid in main)"); 281 break; 282 283 case R_ARM_TLS_DTPOFF32: 284 def = find_symdef(symnum, obj, &defobj, flags, cache, 285 lockstate); 286 if (def == NULL) 287 return -1; 288 289 tmp = (Elf_Addr)(def->st_value); 290 if (__predict_true(RELOC_ALIGNED_P(where))) 291 *where = tmp; 292 else 293 store_ptr(where, tmp); 294 295 dbg("TLS_DTPOFF32 %s in %s --> %p", 296 obj->strtab + obj->symtab[symnum].st_name, 297 obj->path, (void *)tmp); 298 299 break; 300 case R_ARM_TLS_DTPMOD32: 301 def = find_symdef(symnum, obj, &defobj, flags, cache, 302 lockstate); 303 if (def == NULL) 304 return -1; 305 306 tmp = (Elf_Addr)(defobj->tlsindex); 307 if (__predict_true(RELOC_ALIGNED_P(where))) 308 *where = tmp; 309 else 310 store_ptr(where, tmp); 311 312 dbg("TLS_DTPMOD32 %s in %s --> %p", 313 obj->strtab + obj->symtab[symnum].st_name, 314 obj->path, (void *)tmp); 315 316 break; 317 318 case R_ARM_TLS_TPOFF32: 319 def = find_symdef(symnum, obj, &defobj, flags, cache, 320 lockstate); 321 if (def == NULL) 322 return -1; 323 324 if (!defobj->tls_done && allocate_tls_offset(obj)) 325 return -1; 326 327 tmp = (Elf_Addr)def->st_value + defobj->tlsoffset; 328 if (__predict_true(RELOC_ALIGNED_P(where))) 329 *where = tmp; 330 else 331 store_ptr(where, tmp); 332 dbg("TLS_TPOFF32 %s in %s --> %p", 333 obj->strtab + obj->symtab[symnum].st_name, 334 obj->path, (void *)tmp); 335 break; 336 337 338 default: 339 dbg("sym = %lu, type = %lu, offset = %p, " 340 "contents = %p, symbol = %s", 341 symnum, (u_long)ELF_R_TYPE(rel->r_info), 342 (void *)rel->r_offset, (void *)load_ptr(where), 343 obj->strtab + obj->symtab[symnum].st_name); 344 _rtld_error("%s: Unsupported relocation type %ld " 345 "in non-PLT relocations\n", 346 obj->path, (u_long) ELF_R_TYPE(rel->r_info)); 347 return -1; 348 } 349 return 0; 350 } 351 352 /* 353 * * Process non-PLT relocations 354 * */ 355 int 356 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 357 RtldLockState *lockstate) 358 { 359 const Elf_Rel *rellim; 360 const Elf_Rel *rel; 361 SymCache *cache; 362 int r = -1; 363 364 /* The relocation for the dynamic loader has already been done. */ 365 if (obj == obj_rtld) 366 return (0); 367 if ((flags & SYMLOOK_IFUNC) != 0) 368 /* XXX not implemented */ 369 return (0); 370 371 /* 372 * The dynamic loader may be called from a thread, we have 373 * limited amounts of stack available so we cannot use alloca(). 374 */ 375 cache = calloc(obj->dynsymcount, sizeof(SymCache)); 376 /* No need to check for NULL here */ 377 378 rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize); 379 for (rel = obj->rel; rel < rellim; rel++) { 380 if (reloc_nonplt_object(obj, rel, cache, flags, lockstate) < 0) 381 goto done; 382 } 383 r = 0; 384 done: 385 if (cache != NULL) 386 free(cache); 387 return (r); 388 } 389 390 /* 391 * * Process the PLT relocations. 392 * */ 393 int 394 reloc_plt(Obj_Entry *obj) 395 { 396 const Elf_Rel *rellim; 397 const Elf_Rel *rel; 398 399 rellim = (const Elf_Rel *)((char *)obj->pltrel + 400 obj->pltrelsize); 401 for (rel = obj->pltrel; rel < rellim; rel++) { 402 Elf_Addr *where; 403 404 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); 405 406 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 407 *where += (Elf_Addr )obj->relocbase; 408 } 409 410 return (0); 411 } 412 413 /* 414 * * LD_BIND_NOW was set - force relocation for all jump slots 415 * */ 416 int 417 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 418 { 419 const Obj_Entry *defobj; 420 const Elf_Rel *rellim; 421 const Elf_Rel *rel; 422 const Elf_Sym *def; 423 Elf_Addr *where; 424 Elf_Addr target; 425 426 rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); 427 for (rel = obj->pltrel; rel < rellim; rel++) { 428 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); 429 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 430 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, 431 SYMLOOK_IN_PLT | flags, NULL, lockstate); 432 if (def == NULL) { 433 dbg("reloc_jmpslots: sym not found"); 434 return (-1); 435 } 436 437 target = (Elf_Addr)(defobj->relocbase + def->st_value); 438 reloc_jmpslot(where, target, defobj, obj, 439 (const Elf_Rel *) rel); 440 } 441 442 obj->jmpslots_done = true; 443 444 return (0); 445 } 446 447 int 448 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) 449 { 450 451 /* XXX not implemented */ 452 return (0); 453 } 454 455 int 456 reloc_gnu_ifunc(Obj_Entry *obj, int flags, 457 struct Struct_RtldLockState *lockstate) 458 { 459 460 /* XXX not implemented */ 461 return (0); 462 } 463 464 Elf_Addr 465 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj, 466 const Obj_Entry *obj, 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