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 /* XXX: FIXME */ 328 tmp = (Elf_Addr)def->st_value + defobj->tlsoffset + 329 TLS_TCB_SIZE; 330 if (__predict_true(RELOC_ALIGNED_P(where))) 331 *where = tmp; 332 else 333 store_ptr(where, tmp); 334 dbg("TLS_TPOFF32 %s in %s --> %p", 335 obj->strtab + obj->symtab[symnum].st_name, 336 obj->path, (void *)tmp); 337 break; 338 339 340 default: 341 dbg("sym = %lu, type = %lu, offset = %p, " 342 "contents = %p, symbol = %s", 343 symnum, (u_long)ELF_R_TYPE(rel->r_info), 344 (void *)rel->r_offset, (void *)load_ptr(where), 345 obj->strtab + obj->symtab[symnum].st_name); 346 _rtld_error("%s: Unsupported relocation type %ld " 347 "in non-PLT relocations\n", 348 obj->path, (u_long) ELF_R_TYPE(rel->r_info)); 349 return -1; 350 } 351 return 0; 352 } 353 354 /* 355 * * Process non-PLT relocations 356 * */ 357 int 358 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags, 359 RtldLockState *lockstate) 360 { 361 const Elf_Rel *rellim; 362 const Elf_Rel *rel; 363 SymCache *cache; 364 int r = -1; 365 366 /* The relocation for the dynamic loader has already been done. */ 367 if (obj == obj_rtld) 368 return (0); 369 if ((flags & SYMLOOK_IFUNC) != 0) 370 /* XXX not implemented */ 371 return (0); 372 373 /* 374 * The dynamic loader may be called from a thread, we have 375 * limited amounts of stack available so we cannot use alloca(). 376 */ 377 cache = calloc(obj->dynsymcount, sizeof(SymCache)); 378 /* No need to check for NULL here */ 379 380 rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize); 381 for (rel = obj->rel; rel < rellim; rel++) { 382 if (reloc_nonplt_object(obj, rel, cache, flags, lockstate) < 0) 383 goto done; 384 } 385 r = 0; 386 done: 387 if (cache != NULL) 388 free(cache); 389 return (r); 390 } 391 392 /* 393 * * Process the PLT relocations. 394 * */ 395 int 396 reloc_plt(Obj_Entry *obj) 397 { 398 const Elf_Rel *rellim; 399 const Elf_Rel *rel; 400 401 rellim = (const Elf_Rel *)((char *)obj->pltrel + 402 obj->pltrelsize); 403 for (rel = obj->pltrel; rel < rellim; rel++) { 404 Elf_Addr *where; 405 406 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); 407 408 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 409 *where += (Elf_Addr )obj->relocbase; 410 } 411 412 return (0); 413 } 414 415 /* 416 * * LD_BIND_NOW was set - force relocation for all jump slots 417 * */ 418 int 419 reloc_jmpslots(Obj_Entry *obj, int flags, RtldLockState *lockstate) 420 { 421 const Obj_Entry *defobj; 422 const Elf_Rel *rellim; 423 const Elf_Rel *rel; 424 const Elf_Sym *def; 425 Elf_Addr *where; 426 Elf_Addr target; 427 428 rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); 429 for (rel = obj->pltrel; rel < rellim; rel++) { 430 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); 431 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 432 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, 433 SYMLOOK_IN_PLT | flags, NULL, lockstate); 434 if (def == NULL) { 435 dbg("reloc_jmpslots: sym not found"); 436 return (-1); 437 } 438 439 target = (Elf_Addr)(defobj->relocbase + def->st_value); 440 reloc_jmpslot(where, target, defobj, obj, 441 (const Elf_Rel *) rel); 442 } 443 444 obj->jmpslots_done = true; 445 446 return (0); 447 } 448 449 int 450 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) 451 { 452 453 /* XXX not implemented */ 454 return (0); 455 } 456 457 int 458 reloc_gnu_ifunc(Obj_Entry *obj, int flags, 459 struct Struct_RtldLockState *lockstate) 460 { 461 462 /* XXX not implemented */ 463 return (0); 464 } 465 466 Elf_Addr 467 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj, 468 const Obj_Entry *obj, const Elf_Rel *rel) 469 { 470 471 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); 472 473 if (*where != target && !ld_bind_not) 474 *where = target; 475 return (target); 476 } 477 478 void 479 ifunc_init(Elf_Auxinfo aux_info[__min_size(AT_COUNT)] __unused) 480 { 481 482 } 483 484 void 485 pre_init(void) 486 { 487 488 } 489 490 void 491 allocate_initial_tls(Obj_Entry *objs) 492 { 493 #ifdef ARM_TP_ADDRESS 494 void **_tp = (void **)ARM_TP_ADDRESS; 495 #endif 496 497 /* 498 * Fix the size of the static TLS block by using the maximum 499 * offset allocated so far and adding a bit for dynamic modules to 500 * use. 501 */ 502 503 tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; 504 505 #ifdef ARM_TP_ADDRESS 506 (*_tp) = (void *) allocate_tls(objs, NULL, TLS_TCB_SIZE, 8); 507 #else 508 sysarch(ARM_SET_TP, allocate_tls(objs, NULL, TLS_TCB_SIZE, 8)); 509 #endif 510 } 511 512 void * 513 __tls_get_addr(tls_index* ti) 514 { 515 char *p; 516 #ifdef ARM_TP_ADDRESS 517 void **_tp = (void **)ARM_TP_ADDRESS; 518 519 p = tls_get_addr_common((Elf_Addr **)(*_tp), ti->ti_module, ti->ti_offset); 520 #else 521 void *_tp; 522 __asm __volatile("mrc p15, 0, %0, c13, c0, 3" \ 523 : "=r" (_tp)); 524 p = tls_get_addr_common((Elf_Addr **)(_tp), ti->ti_module, ti->ti_offset); 525 #endif 526 527 return (p); 528 } 529