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/mman.h> 7 8 #include <errno.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <unistd.h> 13 #include "debug.h" 14 #include "rtld.h" 15 16 void 17 init_pltgot(Obj_Entry *obj) 18 { 19 if (obj->pltgot != NULL) { 20 obj->pltgot[1] = (Elf_Addr) obj; 21 obj->pltgot[2] = (Elf_Addr) &_rtld_bind_start; 22 } 23 } 24 25 int 26 do_copy_relocations(Obj_Entry *dstobj) 27 { 28 const Elf_Rel *rellim; 29 const Elf_Rel *rel; 30 31 assert(dstobj->mainprog); /* COPY relocations are invalid elsewhere */ 32 33 rellim = (const Elf_Rel *) ((caddr_t) dstobj->rel + dstobj->relsize); 34 for (rel = dstobj->rel; rel < rellim; rel++) { 35 if (ELF_R_TYPE(rel->r_info) == R_ARM_COPY) { 36 void *dstaddr; 37 const Elf_Sym *dstsym; 38 const char *name; 39 size_t size; 40 const void *srcaddr; 41 const Elf_Sym *srcsym; 42 const Obj_Entry *srcobj, *defobj; 43 SymLook req; 44 int res; 45 46 dstaddr = (void *) (dstobj->relocbase + rel->r_offset); 47 dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info); 48 name = dstobj->strtab + dstsym->st_name; 49 size = dstsym->st_size; 50 51 symlook_init(&req, name); 52 req.ventry = fetch_ventry(dstobj, 53 ELF_R_SYM(rel->r_info)); 54 for (srcobj = dstobj->next; srcobj != NULL; 55 srcobj = srcobj->next) { 56 res = symlook_obj(&req, srcobj); 57 if (res == 0) { 58 srcsym = req.sym_out; 59 defobj = req.defobj_out; 60 break; 61 } 62 } 63 if (srcobj == NULL) { 64 _rtld_error( 65 "Undefined symbol \"%s\" referenced from COPY relocation in %s", 66 name, dstobj->path); 67 return (-1); 68 } 69 70 srcaddr = (const void *)(defobj->relocbase + 71 srcsym->st_value); 72 memcpy(dstaddr, srcaddr, size); 73 } 74 } 75 return 0; 76 } 77 78 void _rtld_bind_start(void); 79 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 80 81 int open(); 82 int _open(); 83 void 84 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 85 { 86 const Elf_Rel *rel = 0, *rellim; 87 Elf_Addr relsz = 0; 88 Elf_Addr *where; 89 uint32_t size; 90 91 for (; dynp->d_tag != DT_NULL; dynp++) { 92 switch (dynp->d_tag) { 93 case DT_REL: 94 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr); 95 break; 96 case DT_RELSZ: 97 relsz = dynp->d_un.d_val; 98 break; 99 } 100 } 101 rellim = (const Elf_Rel *)((caddr_t)rel + relsz); 102 size = (rellim - 1)->r_offset - rel->r_offset; 103 for (; rel < rellim; rel++) { 104 where = (Elf_Addr *)(relocbase + rel->r_offset); 105 106 *where += (Elf_Addr)relocbase; 107 } 108 } 109 /* 110 * It is possible for the compiler to emit relocations for unaligned data. 111 * We handle this situation with these inlines. 112 */ 113 #define RELOC_ALIGNED_P(x) \ 114 (((uintptr_t)(x) & (sizeof(void *) - 1)) == 0) 115 116 static __inline Elf_Addr 117 load_ptr(void *where) 118 { 119 Elf_Addr res; 120 121 memcpy(&res, where, sizeof(res)); 122 123 return (res); 124 } 125 126 static __inline void 127 store_ptr(void *where, Elf_Addr val) 128 { 129 130 memcpy(where, &val, sizeof(val)); 131 } 132 133 static int 134 reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache, 135 RtldLockState *lockstate) 136 { 137 Elf_Addr *where; 138 const Elf_Sym *def; 139 const Obj_Entry *defobj; 140 Elf_Addr tmp; 141 unsigned long symnum; 142 143 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 144 symnum = ELF_R_SYM(rel->r_info); 145 146 switch (ELF_R_TYPE(rel->r_info)) { 147 case R_ARM_NONE: 148 break; 149 150 #if 1 /* XXX should not occur */ 151 case R_ARM_PC24: { /* word32 S - P + A */ 152 Elf32_Sword addend; 153 154 /* 155 * Extract addend and sign-extend if needed. 156 */ 157 addend = *where; 158 if (addend & 0x00800000) 159 addend |= 0xff000000; 160 161 def = find_symdef(symnum, obj, &defobj, false, cache, 162 lockstate); 163 if (def == NULL) 164 return -1; 165 tmp = (Elf_Addr)obj->relocbase + def->st_value 166 - (Elf_Addr)where + (addend << 2); 167 if ((tmp & 0xfe000000) != 0xfe000000 && 168 (tmp & 0xfe000000) != 0) { 169 _rtld_error( 170 "%s: R_ARM_PC24 relocation @ %p to %s failed " 171 "(displacement %ld (%#lx) out of range)", 172 obj->path, where, 173 obj->strtab + obj->symtab[symnum].st_name, 174 (long) tmp, (long) tmp); 175 return -1; 176 } 177 tmp >>= 2; 178 *where = (*where & 0xff000000) | (tmp & 0x00ffffff); 179 dbg("PC24 %s in %s --> %p @ %p in %s", 180 obj->strtab + obj->symtab[symnum].st_name, 181 obj->path, (void *)*where, where, defobj->path); 182 break; 183 } 184 #endif 185 186 case R_ARM_ABS32: /* word32 B + S + A */ 187 case R_ARM_GLOB_DAT: /* word32 B + S */ 188 def = find_symdef(symnum, obj, &defobj, false, cache, 189 lockstate); 190 if (def == NULL) 191 return -1; 192 if (__predict_true(RELOC_ALIGNED_P(where))) { 193 tmp = *where + (Elf_Addr)defobj->relocbase + 194 def->st_value; 195 *where = tmp; 196 } else { 197 tmp = load_ptr(where) + 198 (Elf_Addr)defobj->relocbase + 199 def->st_value; 200 store_ptr(where, tmp); 201 } 202 dbg("ABS32/GLOB_DAT %s in %s --> %p @ %p in %s", 203 obj->strtab + obj->symtab[symnum].st_name, 204 obj->path, (void *)tmp, where, defobj->path); 205 break; 206 207 case R_ARM_RELATIVE: /* word32 B + A */ 208 if (__predict_true(RELOC_ALIGNED_P(where))) { 209 tmp = *where + (Elf_Addr)obj->relocbase; 210 *where = tmp; 211 } else { 212 tmp = load_ptr(where) + 213 (Elf_Addr)obj->relocbase; 214 store_ptr(where, tmp); 215 } 216 dbg("RELATIVE in %s --> %p", obj->path, 217 (void *)tmp); 218 break; 219 220 case R_ARM_COPY: 221 /* 222 * These are deferred until all other relocations have 223 * been done. All we do here is make sure that the 224 * COPY relocation is not in a shared library. They 225 * are allowed only in executable files. 226 */ 227 if (!obj->mainprog) { 228 _rtld_error( 229 "%s: Unexpected R_COPY relocation in shared library", 230 obj->path); 231 return -1; 232 } 233 dbg("COPY (avoid in main)"); 234 break; 235 236 default: 237 dbg("sym = %lu, type = %lu, offset = %p, " 238 "contents = %p, symbol = %s", 239 symnum, (u_long)ELF_R_TYPE(rel->r_info), 240 (void *)rel->r_offset, (void *)load_ptr(where), 241 obj->strtab + obj->symtab[symnum].st_name); 242 _rtld_error("%s: Unsupported relocation type %ld " 243 "in non-PLT relocations\n", 244 obj->path, (u_long) ELF_R_TYPE(rel->r_info)); 245 return -1; 246 } 247 return 0; 248 } 249 250 /* 251 * * Process non-PLT relocations 252 * */ 253 int 254 reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate) 255 { 256 const Elf_Rel *rellim; 257 const Elf_Rel *rel; 258 SymCache *cache; 259 int r = -1; 260 261 /* The relocation for the dynamic loader has already been done. */ 262 if (obj == obj_rtld) 263 return (0); 264 /* 265 * The dynamic loader may be called from a thread, we have 266 * limited amounts of stack available so we cannot use alloca(). 267 */ 268 cache = calloc(obj->nchains, sizeof(SymCache)); 269 /* No need to check for NULL here */ 270 271 rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize); 272 for (rel = obj->rel; rel < rellim; rel++) { 273 if (reloc_nonplt_object(obj, rel, cache, lockstate) < 0) 274 goto done; 275 } 276 r = 0; 277 done: 278 if (cache != NULL) 279 free(cache); 280 return (r); 281 } 282 283 /* 284 * * Process the PLT relocations. 285 * */ 286 int 287 reloc_plt(Obj_Entry *obj) 288 { 289 const Elf_Rel *rellim; 290 const Elf_Rel *rel; 291 292 rellim = (const Elf_Rel *)((char *)obj->pltrel + 293 obj->pltrelsize); 294 for (rel = obj->pltrel; rel < rellim; rel++) { 295 Elf_Addr *where; 296 297 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); 298 299 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 300 *where += (Elf_Addr )obj->relocbase; 301 } 302 303 return (0); 304 } 305 306 /* 307 * * LD_BIND_NOW was set - force relocation for all jump slots 308 * */ 309 int 310 reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate) 311 { 312 const Obj_Entry *defobj; 313 const Elf_Rel *rellim; 314 const Elf_Rel *rel; 315 const Elf_Sym *def; 316 Elf_Addr *where; 317 Elf_Addr target; 318 319 rellim = (const Elf_Rel *)((char *)obj->pltrel + obj->pltrelsize); 320 for (rel = obj->pltrel; rel < rellim; rel++) { 321 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); 322 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 323 def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, 324 true, NULL, lockstate); 325 if (def == NULL) { 326 dbg("reloc_jmpslots: sym not found"); 327 return (-1); 328 } 329 330 target = (Elf_Addr)(defobj->relocbase + def->st_value); 331 reloc_jmpslot(where, target, defobj, obj, 332 (const Elf_Rel *) rel); 333 } 334 335 obj->jmpslots_done = true; 336 337 return (0); 338 } 339 340 int 341 reloc_iresolve(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) 342 { 343 344 /* XXX not implemented */ 345 return (0); 346 } 347 348 int 349 reloc_gnu_ifunc(Obj_Entry *obj, struct Struct_RtldLockState *lockstate) 350 { 351 352 /* XXX not implemented */ 353 return (0); 354 } 355 356 Elf_Addr 357 reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj, 358 const Obj_Entry *obj, const Elf_Rel *rel) 359 { 360 361 assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT); 362 363 if (*where != target) 364 *where = target; 365 366 return target; 367 } 368 369 void 370 allocate_initial_tls(Obj_Entry *objs) 371 { 372 373 } 374 375 void * 376 __tls_get_addr(tls_index* ti) 377 { 378 return (NULL); 379 } 380