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