reloc.c revision 204687
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__FBSDID("$FreeBSD: head/libexec/rtld-elf/mips/reloc.c 204687 2010-03-04 04:53:05Z imp $"); 33 34#include <sys/types.h> 35#include <sys/stat.h> 36#include <sys/endian.h> 37 38#include <stdlib.h> 39#include <string.h> 40 41#include "debug.h" 42#include "rtld.h" 43 44void 45init_pltgot(Obj_Entry *obj) 46{ 47 if (obj->pltgot != NULL) { 48 obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start; 49 /* XXX only if obj->pltgot[1] & 0x80000000 ?? */ 50 obj->pltgot[1] |= (Elf_Addr) obj; 51 } 52} 53 54int 55do_copy_relocations(Obj_Entry *dstobj) 56{ 57 /* Do nothing */ 58 return 0; 59} 60 61void _rtld_relocate_nonplt_self(Elf_Dyn *, Elf_Addr); 62 63/* 64 * It is possible for the compiler to emit relocations for unaligned data. 65 * We handle this situation with these inlines. 66 */ 67#if ELFSIZE == 64 68/* 69 * ELF64 MIPS encodes the relocs uniquely. The first 32-bits of info contain 70 * the symbol index. The top 32-bits contain three relocation types encoded 71 * in big-endian integer with first relocation in LSB. This means for little 72 * endian we have to byte swap that interger (r_type). 73 */ 74#define Elf_Sxword Elf64_Sxword 75#define ELF_R_NXTTYPE_64_P(r_type) ((((r_type) >> 8) & 0xff) == R_TYPE(64)) 76#if BYTE_ORDER == LITTLE_ENDIAN 77#undef ELF_R_SYM 78#undef ELF_R_TYPE 79#define ELF_R_SYM(r_info) ((r_info) & 0xffffffff) 80#define ELF_R_TYPE(r_info) bswap32((r_info) >> 32) 81#endif 82#else 83#define ELF_R_NXTTYPE_64_P(r_type) (0) 84#define Elf_Sxword Elf32_Sword 85#endif 86 87static __inline Elf_Sxword 88load_ptr(void *where, size_t len) 89{ 90 Elf_Sxword val; 91 92 if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) { 93#if ELFSIZE == 64 94 if (len == sizeof(Elf_Sxword)) 95 return *(Elf_Sxword *)where; 96#endif 97 return *(Elf_Sword *)where; 98 } 99 100 val = 0; 101#if BYTE_ORDER == LITTLE_ENDIAN 102 (void)memcpy(&val, where, len); 103#endif 104#if BYTE_ORDER == BIG_ENDIAN 105 (void)memcpy((uint8_t *)((&val)+1) - len, where, len); 106#endif 107 return (len == sizeof(Elf_Sxword)) ? val : (Elf_Sword)val; 108} 109 110static __inline void 111store_ptr(void *where, Elf_Sxword val, size_t len) 112{ 113 if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) { 114#if ELFSIZE == 64 115 if (len == sizeof(Elf_Sxword)) { 116 *(Elf_Sxword *)where = val; 117 return; 118 } 119#endif 120 *(Elf_Sword *)where = val; 121 return; 122 } 123#if BYTE_ORDER == LITTLE_ENDIAN 124 (void)memcpy(where, &val, len); 125#endif 126#if BYTE_ORDER == BIG_ENDIAN 127 (void)memcpy(where, (const uint8_t *)((&val)+1) - len, len); 128#endif 129} 130 131void 132_rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 133{ 134 const Elf_Rel *rel = 0, *rellim; 135 Elf_Addr relsz = 0; 136 const Elf_Sym *symtab = NULL, *sym; 137 Elf_Addr *where; 138 Elf_Addr *got = NULL; 139 Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0; 140 size_t i; 141 142 for (; dynp->d_tag != DT_NULL; dynp++) { 143 switch (dynp->d_tag) { 144 case DT_REL: 145 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr); 146 break; 147 case DT_RELSZ: 148 relsz = dynp->d_un.d_val; 149 break; 150 case DT_SYMTAB: 151 symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr); 152 break; 153 case DT_PLTGOT: 154 got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr); 155 break; 156 case DT_MIPS_LOCAL_GOTNO: 157 local_gotno = dynp->d_un.d_val; 158 break; 159 case DT_MIPS_SYMTABNO: 160 symtabno = dynp->d_un.d_val; 161 break; 162 case DT_MIPS_GOTSYM: 163 gotsym = dynp->d_un.d_val; 164 break; 165 } 166 } 167 168 i = (got[1] & 0x80000000) ? 2 : 1; 169 /* Relocate the local GOT entries */ 170 got += i; 171 for (; i < local_gotno; i++) { 172 *got++ += relocbase; 173 } 174 175 sym = symtab + gotsym; 176 /* Now do the global GOT entries */ 177 for (i = gotsym; i < symtabno; i++) { 178 *got = sym->st_value + relocbase; 179 ++sym; 180 ++got; 181 } 182 183 rellim = (const Elf_Rel *)((caddr_t)rel + relsz); 184 for (; rel < rellim; rel++) { 185 Elf_Word r_symndx, r_type; 186 187 where = (void *)(relocbase + rel->r_offset); 188 189 r_symndx = ELF_R_SYM(rel->r_info); 190 r_type = ELF_R_TYPE(rel->r_info); 191 192 switch (r_type & 0xff) { 193 case R_TYPE(REL32): { 194 const size_t rlen = 195 ELF_R_NXTTYPE_64_P(r_type) 196 ? sizeof(Elf_Sxword) 197 : sizeof(Elf_Sword); 198 Elf_Sxword old = load_ptr(where, rlen); 199 Elf_Sxword val = old; 200#if ELFSIZE == 64 201 assert(r_type == R_TYPE(REL32) 202 || r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8))); 203#endif 204 assert(r_symndx < gotsym); 205 sym = symtab + r_symndx; 206 assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL); 207 val += relocbase; 208 store_ptr(where, val, sizeof(Elf_Sword)); 209 dbg("REL32/L(%p) %p -> %p in <self>", 210 where, (void *)old, (void *)val); 211 store_ptr(where, val, rlen); 212 break; 213 } 214 215 case R_TYPE(GPREL32): 216 case R_TYPE(NONE): 217 break; 218 219 220 default: 221 abort(); 222 break; 223 } 224 } 225} 226 227Elf_Addr 228_mips_rtld_bind(Obj_Entry *obj, Elf_Size reloff) 229{ 230 Elf_Addr *got = obj->pltgot; 231 const Elf_Sym *def; 232 const Obj_Entry *defobj; 233 Elf_Addr target; 234 235 def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL); 236 if (def == NULL) 237 _rtld_error("bind failed no symbol"); 238 239 target = (Elf_Addr)(defobj->relocbase + def->st_value); 240 dbg("bind now/fixup at %s sym # %d in %s --> was=%p new=%p", 241 obj->path, 242 reloff, defobj->strtab + def->st_name, 243 (void *)got[obj->local_gotno + reloff - obj->gotsym], 244 (void *)target); 245 got[obj->local_gotno + reloff - obj->gotsym] = target; 246 return (Elf_Addr)target; 247} 248 249int 250reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld) 251{ 252 const Elf_Rel *rel; 253 const Elf_Rel *rellim; 254 Elf_Addr *got = obj->pltgot; 255 const Elf_Sym *sym, *def; 256 const Obj_Entry *defobj; 257 Elf_Word i; 258#ifdef SUPPORT_OLD_BROKEN_LD 259 int broken; 260#endif 261 262 /* The relocation for the dynamic loader has already been done. */ 263 if (obj == obj_rtld) 264 return (0); 265 266#ifdef SUPPORT_OLD_BROKEN_LD 267 broken = 0; 268 sym = obj->symtab; 269 for (i = 1; i < 12; i++) 270 if (sym[i].st_info == ELF_ST_INFO(STB_LOCAL, STT_NOTYPE)) 271 broken = 1; 272 dbg("%s: broken=%d", obj->path, broken); 273#endif 274 275 i = (got[1] & 0x80000000) ? 2 : 1; 276 277 /* Relocate the local GOT entries */ 278 got += i; 279 dbg("got:%p for %d entries adding %x", 280 got, obj->local_gotno, (uint32_t)obj->relocbase); 281 for (; i < obj->local_gotno; i++) { 282 *got += (Elf_Addr)obj->relocbase; 283 got++; 284 } 285 sym = obj->symtab + obj->gotsym; 286 287 dbg("got:%p for %d entries", 288 got, obj->symtabno); 289 /* Now do the global GOT entries */ 290 for (i = obj->gotsym; i < obj->symtabno; i++) { 291 dbg(" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym, 292 sym->st_name + obj->strtab, (u_long) *got); 293 294#ifdef SUPPORT_OLD_BROKEN_LD 295 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC && 296 broken && sym->st_shndx == SHN_UNDEF) { 297 /* 298 * XXX DANGER WILL ROBINSON! 299 * You might think this is stupid, as it intentionally 300 * defeats lazy binding -- and you'd be right. 301 * Unfortunately, for lazy binding to work right, we 302 * need to a way to force the GOT slots used for 303 * function pointers to be resolved immediately. This 304 * is supposed to be done automatically by the linker, 305 * by not outputting a PLT slot and setting st_value 306 * to 0 if there are non-PLT references, but older 307 * versions of GNU ld do not do this. 308 */ 309 def = find_symdef(i, obj, &defobj, false, NULL); 310 if (def == NULL) 311 return -1; 312 *got = def->st_value + (Elf_Addr)defobj->relocbase; 313 } else 314#endif 315 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC && 316 sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) { 317 /* 318 * If there are non-PLT references to the function, 319 * st_value should be 0, forcing us to resolve the 320 * address immediately. 321 * 322 * XXX DANGER WILL ROBINSON! 323 * The linker is not outputting PLT slots for calls to 324 * functions that are defined in the same shared 325 * library. This is a bug, because it can screw up 326 * link ordering rules if the symbol is defined in 327 * more than one module. For now, if there is a 328 * definition, we fail the test above and force a full 329 * symbol lookup. This means that all intra-module 330 * calls are bound immediately. - mycroft, 2003/09/24 331 */ 332 *got = sym->st_value + (Elf_Addr)obj->relocbase; 333 if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) { 334 dbg("Warning2, i:%d maps to relocbase address:%x", 335 i, (uint32_t)obj->relocbase); 336 } 337 338 } else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) { 339 /* Symbols with index SHN_ABS are not relocated. */ 340 if (sym->st_shndx != SHN_ABS) { 341 *got = sym->st_value + 342 (Elf_Addr)obj->relocbase; 343 if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) { 344 dbg("Warning3, i:%d maps to relocbase address:%x", 345 i, (uint32_t)obj->relocbase); 346 } 347 } 348 } else { 349 /* TODO: add cache here */ 350 def = find_symdef(i, obj, &defobj, false, NULL); 351 if (def == NULL) { 352 dbg("Warning4, cant find symbole %d", i); 353 return -1; 354 } 355 *got = def->st_value + (Elf_Addr)defobj->relocbase; 356 if ((Elf_Addr)(*got) == (Elf_Addr)obj->relocbase) { 357 dbg("Warning4, i:%d maps to relocbase address:%x", 358 i, (uint32_t)obj->relocbase); 359 dbg("via first obj symbol %s", 360 obj->strtab + obj->symtab[i].st_name); 361 dbg("found in obj %p:%s", 362 defobj, defobj->path); 363 } 364 } 365 366 dbg(" --> now %lx", (u_long) *got); 367 ++sym; 368 ++got; 369 } 370 371 got = obj->pltgot; 372 rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize); 373 for (rel = obj->rel; rel < rellim; rel++) { 374 Elf_Word r_symndx, r_type; 375 void *where; 376 377 where = obj->relocbase + rel->r_offset; 378 r_symndx = ELF_R_SYM(rel->r_info); 379 r_type = ELF_R_TYPE(rel->r_info); 380 381 switch (r_type & 0xff) { 382 case R_TYPE(NONE): 383 break; 384 385 case R_TYPE(REL32): { 386 /* 32-bit PC-relative reference */ 387 const size_t rlen = 388 ELF_R_NXTTYPE_64_P(r_type) 389 ? sizeof(Elf_Sxword) 390 : sizeof(Elf_Sword); 391 Elf_Sxword old = load_ptr(where, rlen); 392 Elf_Sxword val = old; 393 394 def = obj->symtab + r_symndx; 395 396 if (r_symndx >= obj->gotsym) { 397 val += got[obj->local_gotno + r_symndx - obj->gotsym]; 398 dbg("REL32/G(%p) %p --> %p (%s) in %s", 399 where, (void *)old, (void *)val, 400 obj->strtab + def->st_name, 401 obj->path); 402 } else { 403 /* 404 * XXX: ABI DIFFERENCE! 405 * 406 * Old NetBSD binutils would generate shared 407 * libs with section-relative relocations being 408 * already adjusted for the start address of 409 * the section. 410 * 411 * New binutils, OTOH, generate shared libs 412 * with the same relocations being based at 413 * zero, so we need to add in the start address 414 * of the section. 415 * 416 * --rkb, Oct 6, 2001 417 */ 418 419 if (def->st_info == 420 ELF_ST_INFO(STB_LOCAL, STT_SECTION) 421#ifdef SUPPORT_OLD_BROKEN_LD 422 && !broken 423#endif 424 ) 425 val += (Elf_Addr)def->st_value; 426 427 val += (Elf_Addr)obj->relocbase; 428 429 dbg("REL32/L(%p) %p -> %p (%s) in %s", 430 where, (void *)old, (void *)val, 431 obj->strtab + def->st_name, obj->path); 432 } 433 store_ptr(where, val, rlen); 434 break; 435 } 436 437 default: 438 dbg("sym = %lu, type = %lu, offset = %p, " 439 "contents = %p, symbol = %s", 440 (u_long)r_symndx, (u_long)ELF_R_TYPE(rel->r_info), 441 (void *)rel->r_offset, 442 (void *)load_ptr(where, sizeof(Elf_Sword)), 443 obj->strtab + obj->symtab[r_symndx].st_name); 444 _rtld_error("%s: Unsupported relocation type %ld " 445 "in non-PLT relocations", 446 obj->path, (u_long) ELF_R_TYPE(rel->r_info)); 447 return -1; 448 } 449 } 450 451 return 0; 452} 453 454/* 455 * Process the PLT relocations. 456 */ 457int 458reloc_plt(Obj_Entry *obj) 459{ 460#if 0 461 const Elf_Rel *rellim; 462 const Elf_Rel *rel; 463 464 dbg("reloc_plt obj:%p pltrel:%p sz:%d", obj, obj->pltrel, (int)obj->pltrelsize); 465 dbg("gottable %p num syms:%d", obj->pltgot, obj->symtabno ); 466 dbg("*****************************************************"); 467 rellim = (const Elf_Rel *)((char *)obj->pltrel + 468 obj->pltrelsize); 469 for (rel = obj->pltrel; rel < rellim; rel++) { 470 Elf_Addr *where; 471 where = (Elf_Addr *)(obj->relocbase + rel->r_offset); 472 *where += (Elf_Addr )obj->relocbase; 473 } 474 475#endif 476 /* PLT fixups were done above in the GOT relocation. */ 477 return (0); 478} 479 480/* 481 * LD_BIND_NOW was set - force relocation for all jump slots 482 */ 483int 484reloc_jmpslots(Obj_Entry *obj) 485{ 486 /* Do nothing */ 487 obj->jmpslots_done = true; 488 489 return (0); 490} 491 492Elf_Addr 493reloc_jmpslot(Elf_Addr *where, Elf_Addr target, const Obj_Entry *defobj, 494 const Obj_Entry *obj, const Elf_Rel *rel) 495{ 496 497 /* Do nothing */ 498 499 return target; 500} 501 502void 503allocate_initial_tls(Obj_Entry *objs) 504{ 505 506} 507 508void * 509__tls_get_addr(tls_index* ti) 510{ 511 return (NULL); 512} 513