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