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