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