1 /* $NetBSD: mips_reloc.c,v 1.58 2010/01/14 11:57:06 skrll Exp $ */ 2 3 /* 4 * Copyright 1997 Michael L. Hitch <mhitch@montana.edu> 5 * Portions copyright 2002 Charles M. Hannum <root@ihack.net> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 #ifndef lint 33 __RCSID("$NetBSD: mips_reloc.c,v 1.58 2010/01/14 11:57:06 skrll Exp $"); 34 #endif /* not lint */ 35 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <sys/endian.h> 39 40 #include <stdlib.h> 41 #include <string.h> 42 43 #include "debug.h" 44 #include "rtld.h" 45 46 #ifdef __mips_o32 47 #define SUPPORT_OLD_BROKEN_LD 48 #endif 49 50 void _rtld_bind_start(void); 51 void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 52 caddr_t _rtld_bind(Elf_Word, Elf_Addr, Elf_Addr, Elf_Addr); 53 54 /* 55 * It is possible for the compiler to emit relocations for unaligned data. 56 * We handle this situation with these inlines. 57 */ 58 59 #if ELFSIZE == 64 60 /* 61 * ELF64 MIPS encodes the relocs uniquely. The first 32-bits of info contain 62 * the symbol index. The top 32-bits contain three relocation types encoded 63 * in big-endian integer with first relocation in LSB. This means for little 64 * endian we have to byte swap that interger (r_type). 65 */ 66 #define Elf_Sxword Elf64_Sxword 67 #define ELF_R_NXTTYPE_64_P(r_type) ((((r_type) >> 8) & 0xff) == R_TYPE(64)) 68 #if BYTE_ORDER == LITTLE_ENDIAN 69 #undef ELF_R_SYM 70 #undef ELF_R_TYPE 71 #define ELF_R_SYM(r_info) ((r_info) & 0xffffffff) 72 #define ELF_R_TYPE(r_info) bswap32((r_info) >> 32) 73 #endif 74 #else 75 #define ELF_R_NXTTYPE_64_P(r_type) (0) 76 #define Elf_Sxword Elf32_Sword 77 #endif 78 79 static inline Elf_Sxword 80 load_ptr(void *where, size_t len) 81 { 82 Elf_Sxword val; 83 84 if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) { 85 #if ELFSIZE == 64 86 if (len == sizeof(Elf_Sxword)) 87 return *(Elf_Sxword *)where; 88 #endif 89 return *(Elf_Sword *)where; 90 } 91 92 val = 0; 93 #if BYTE_ORDER == LITTLE_ENDIAN 94 (void)memcpy(&val, where, len); 95 #endif 96 #if BYTE_ORDER == BIG_ENDIAN 97 (void)memcpy((uint8_t *)((&val)+1) - len, where, len); 98 #endif 99 return (len == sizeof(Elf_Sxword)) ? val : (Elf_Sword)val; 100 } 101 102 static inline void 103 store_ptr(void *where, Elf_Sxword val, size_t len) 104 { 105 if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) { 106 #if ELFSIZE == 64 107 if (len == sizeof(Elf_Sxword)) { 108 *(Elf_Sxword *)where = val; 109 return; 110 } 111 #endif 112 *(Elf_Sword *)where = val; 113 return; 114 } 115 #if BYTE_ORDER == LITTLE_ENDIAN 116 (void)memcpy(where, &val, len); 117 #endif 118 #if BYTE_ORDER == BIG_ENDIAN 119 (void)memcpy(where, (const uint8_t *)((&val)+1) - len, len); 120 #endif 121 } 122 123 124 void 125 _rtld_setup_pltgot(const Obj_Entry *obj) 126 { 127 obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start; 128 /* XXX only if obj->pltgot[1] & 0x80000000 ?? */ 129 obj->pltgot[1] |= (Elf_Addr) obj; 130 } 131 132 void 133 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 134 { 135 const Elf_Rel *rel = 0, *rellim; 136 Elf_Addr relsz = 0; 137 void *where; 138 const Elf_Sym *symtab = NULL, *sym; 139 Elf_Addr *got = NULL; 140 Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0; 141 size_t i; 142 143 for (; dynp->d_tag != DT_NULL; dynp++) { 144 switch (dynp->d_tag) { 145 case DT_REL: 146 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr); 147 break; 148 case DT_RELSZ: 149 relsz = dynp->d_un.d_val; 150 break; 151 case DT_SYMTAB: 152 symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr); 153 break; 154 case DT_PLTGOT: 155 got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr); 156 break; 157 case DT_MIPS_LOCAL_GOTNO: 158 local_gotno = dynp->d_un.d_val; 159 break; 160 case DT_MIPS_SYMTABNO: 161 symtabno = dynp->d_un.d_val; 162 break; 163 case DT_MIPS_GOTSYM: 164 gotsym = dynp->d_un.d_val; 165 break; 166 } 167 } 168 169 i = (got[1] & 0x80000000) ? 2 : 1; 170 /* Relocate the local GOT entries */ 171 got += i; 172 for (; i < local_gotno; i++) 173 *got++ += relocbase; 174 sym = symtab + gotsym; 175 /* Now do the global GOT entries */ 176 for (i = gotsym; i < symtabno; i++) { 177 *got = sym->st_value + relocbase; 178 ++sym; 179 ++got; 180 } 181 182 rellim = (const Elf_Rel *)((uintptr_t)rel + relsz); 183 for (; rel < rellim; rel++) { 184 Elf_Word r_symndx, r_type; 185 186 where = (void *)(relocbase + rel->r_offset); 187 188 r_symndx = ELF_R_SYM(rel->r_info); 189 r_type = ELF_R_TYPE(rel->r_info); 190 191 switch (r_type & 0xff) { 192 case R_TYPE(REL32): { 193 const size_t rlen = 194 ELF_R_NXTTYPE_64_P(r_type) 195 ? sizeof(Elf_Sxword) 196 : sizeof(Elf_Sword); 197 Elf_Sxword old = load_ptr(where, rlen); 198 Elf_Sxword val = old; 199 #if ELFSIZE == 64 200 assert(r_type == R_TYPE(REL32) 201 || r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8))); 202 #endif 203 assert(r_symndx < gotsym); 204 sym = symtab + r_symndx; 205 assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL); 206 val += relocbase; 207 store_ptr(where, val, sizeof(Elf_Sword)); 208 rdbg(("REL32/L(%p) %p -> %p in <self>", 209 where, (void *)old, (void *)val)); 210 store_ptr(where, val, rlen); 211 break; 212 } 213 214 case R_TYPE(GPREL32): 215 case R_TYPE(NONE): 216 break; 217 218 219 default: 220 abort(); 221 } 222 } 223 } 224 225 int 226 _rtld_relocate_nonplt_objects(const Obj_Entry *obj) 227 { 228 const Elf_Rel *rel; 229 Elf_Addr *got = obj->pltgot; 230 const Elf_Sym *sym, *def; 231 const Obj_Entry *defobj; 232 Elf_Word i; 233 #ifdef SUPPORT_OLD_BROKEN_LD 234 int broken; 235 #endif 236 237 #ifdef SUPPORT_OLD_BROKEN_LD 238 broken = 0; 239 sym = obj->symtab; 240 for (i = 1; i < 12; i++) 241 if (sym[i].st_info == ELF_ST_INFO(STB_LOCAL, STT_NOTYPE)) 242 broken = 1; 243 dbg(("%s: broken=%d", obj->path, broken)); 244 #endif 245 246 i = (got[1] & 0x80000000) ? 2 : 1; 247 /* Relocate the local GOT entries */ 248 got += i; 249 for (; i < obj->local_gotno; i++) 250 *got++ += (Elf_Addr)obj->relocbase; 251 sym = obj->symtab + obj->gotsym; 252 /* Now do the global GOT entries */ 253 for (i = obj->gotsym; i < obj->symtabno; i++) { 254 rdbg((" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym, 255 sym->st_name + obj->strtab, (u_long) *got)); 256 257 #ifdef SUPPORT_OLD_BROKEN_LD 258 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC && 259 broken && sym->st_shndx == SHN_UNDEF) { 260 /* 261 * XXX DANGER WILL ROBINSON! 262 * You might think this is stupid, as it intentionally 263 * defeats lazy binding -- and you'd be right. 264 * Unfortunately, for lazy binding to work right, we 265 * need to a way to force the GOT slots used for 266 * function pointers to be resolved immediately. This 267 * is supposed to be done automatically by the linker, 268 * by not outputting a PLT slot and setting st_value 269 * to 0 if there are non-PLT references, but older 270 * versions of GNU ld do not do this. 271 */ 272 def = _rtld_find_symdef(i, obj, &defobj, false); 273 if (def == NULL) 274 return -1; 275 *got = def->st_value + (Elf_Addr)defobj->relocbase; 276 } else 277 #endif 278 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC && 279 sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) { 280 /* 281 * If there are non-PLT references to the function, 282 * st_value should be 0, forcing us to resolve the 283 * address immediately. 284 * 285 * XXX DANGER WILL ROBINSON! 286 * The linker is not outputting PLT slots for calls to 287 * functions that are defined in the same shared 288 * library. This is a bug, because it can screw up 289 * link ordering rules if the symbol is defined in 290 * more than one module. For now, if there is a 291 * definition, we fail the test above and force a full 292 * symbol lookup. This means that all intra-module 293 * calls are bound immediately. - mycroft, 2003/09/24 294 */ 295 *got = sym->st_value + (Elf_Addr)obj->relocbase; 296 } else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) { 297 /* Symbols with index SHN_ABS are not relocated. */ 298 if (sym->st_shndx != SHN_ABS) 299 *got = sym->st_value + 300 (Elf_Addr)obj->relocbase; 301 } else { 302 def = _rtld_find_symdef(i, obj, &defobj, false); 303 if (def == NULL) 304 return -1; 305 *got = def->st_value + (Elf_Addr)defobj->relocbase; 306 } 307 308 rdbg((" --> now %lx", (u_long) *got)); 309 ++sym; 310 ++got; 311 } 312 313 got = obj->pltgot; 314 for (rel = obj->rel; rel < obj->rellim; rel++) { 315 Elf_Word r_symndx, r_type; 316 void *where; 317 318 where = obj->relocbase + rel->r_offset; 319 r_symndx = ELF_R_SYM(rel->r_info); 320 r_type = ELF_R_TYPE(rel->r_info); 321 322 switch (r_type & 0xff) { 323 case R_TYPE(NONE): 324 break; 325 326 case R_TYPE(REL32): { 327 /* 32-bit PC-relative reference */ 328 const size_t rlen = 329 ELF_R_NXTTYPE_64_P(r_type) 330 ? sizeof(Elf_Sxword) 331 : sizeof(Elf_Sword); 332 Elf_Sxword old = load_ptr(where, rlen); 333 Elf_Sxword val = old; 334 335 def = obj->symtab + r_symndx; 336 337 if (r_symndx >= obj->gotsym) { 338 val += got[obj->local_gotno + r_symndx - obj->gotsym]; 339 rdbg(("REL32/G(%p) %p --> %p (%s) in %s", 340 where, (void *)old, (void *)val, 341 obj->strtab + def->st_name, 342 obj->path)); 343 } else { 344 /* 345 * XXX: ABI DIFFERENCE! 346 * 347 * Old NetBSD binutils would generate shared 348 * libs with section-relative relocations being 349 * already adjusted for the start address of 350 * the section. 351 * 352 * New binutils, OTOH, generate shared libs 353 * with the same relocations being based at 354 * zero, so we need to add in the start address 355 * of the section. 356 * 357 * --rkb, Oct 6, 2001 358 */ 359 360 if (def->st_info == 361 ELF_ST_INFO(STB_LOCAL, STT_SECTION) 362 #ifdef SUPPORT_OLD_BROKEN_LD 363 && !broken 364 #endif 365 ) 366 val += (Elf_Addr)def->st_value; 367 368 val += (Elf_Addr)obj->relocbase; 369 370 rdbg(("REL32/L(%p) %p -> %p (%s) in %s", 371 where, (void *)old, (void *)val, 372 obj->strtab + def->st_name, obj->path)); 373 } 374 store_ptr(where, val, rlen); 375 break; 376 } 377 378 default: 379 rdbg(("sym = %lu, type = %lu, offset = %p, " 380 "contents = %p, symbol = %s", 381 (u_long)r_symndx, (u_long)ELF_R_TYPE(rel->r_info), 382 (void *)rel->r_offset, 383 (void *)load_ptr(where, sizeof(Elf_Sword)), 384 obj->strtab + obj->symtab[r_symndx].st_name)); 385 _rtld_error("%s: Unsupported relocation type %ld " 386 "in non-PLT relocations", 387 obj->path, (u_long) ELF_R_TYPE(rel->r_info)); 388 return -1; 389 } 390 } 391 392 return 0; 393 } 394 395 int 396 _rtld_relocate_plt_lazy(const Obj_Entry *obj) 397 { 398 /* PLT fixups were done above in the GOT relocation. */ 399 return 0; 400 } 401 402 static inline int 403 _rtld_relocate_plt_object(const Obj_Entry *obj, Elf_Word sym, Elf_Addr *tp) 404 { 405 Elf_Addr *got = obj->pltgot; 406 const Elf_Sym *def; 407 const Obj_Entry *defobj; 408 Elf_Addr new_value; 409 410 def = _rtld_find_plt_symdef(sym, obj, &defobj, tp != NULL); 411 if (__predict_false(def == NULL)) 412 return -1; 413 if (__predict_false(def == &_rtld_sym_zero)) 414 return 0; 415 416 new_value = (Elf_Addr)(defobj->relocbase + def->st_value); 417 rdbg(("bind now/fixup in %s --> new=%p", 418 defobj->strtab + def->st_name, (void *)new_value)); 419 got[obj->local_gotno + sym - obj->gotsym] = new_value; 420 421 if (tp) 422 *tp = new_value; 423 return 0; 424 } 425 426 caddr_t 427 _rtld_bind(Elf_Word a0, Elf_Addr a1, Elf_Addr a2, Elf_Addr a3) 428 { 429 Elf_Addr *got = (Elf_Addr *)(a2 - 0x7ff0); 430 const Obj_Entry *obj = (Obj_Entry *)(got[1] & 0x7fffffff); 431 Elf_Addr new_value = 0; /* XXX gcc */ 432 int err; 433 434 err = _rtld_relocate_plt_object(obj, a0, &new_value); 435 if (err) 436 _rtld_die(); 437 438 return (caddr_t)new_value; 439 } 440 441 int 442 _rtld_relocate_plt_objects(const Obj_Entry *obj) 443 { 444 const Elf_Sym *sym = obj->symtab + obj->gotsym; 445 Elf_Word i; 446 447 for (i = obj->gotsym; i < obj->symtabno; i++, sym++) { 448 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC) 449 if (_rtld_relocate_plt_object(obj, i, NULL) < 0) 450 return -1; 451 } 452 453 return 0; 454 } 455