1 /* $NetBSD: mips_reloc.c,v 1.73 2019/11/03 03:15:59 christos 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.73 2019/11/03 03:15:59 christos Exp $"); 34 #endif /* not lint */ 35 36 #include <sys/types.h> 37 #include <sys/endian.h> 38 #include <sys/tls.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 integer (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 #define GOT1_MASK (~(Elf_Addr)0 >> 1) 79 80 static inline Elf_Sxword 81 load_ptr(void *where, size_t len) 82 { 83 Elf_Sxword val; 84 85 if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) { 86 #if ELFSIZE == 64 87 if (len == sizeof(Elf_Sxword)) 88 return *(Elf_Sxword *)where; 89 #endif 90 return *(Elf_Sword *)where; 91 } 92 93 val = 0; 94 #if BYTE_ORDER == LITTLE_ENDIAN 95 (void)memcpy(&val, where, len); 96 #endif 97 #if BYTE_ORDER == BIG_ENDIAN 98 uint8_t *valp = (void *)&val; 99 (void)memcpy(valp + sizeof(val) - len, where, len); 100 #endif 101 return (len == sizeof(Elf_Sxword)) ? val : (Elf_Sword)val; 102 } 103 104 static inline void 105 store_ptr(void *where, Elf_Sxword val, size_t len) 106 { 107 if (__predict_true(((uintptr_t)where & (len - 1)) == 0)) { 108 #if ELFSIZE == 64 109 if (len == sizeof(Elf_Sxword)) { 110 *(Elf_Sxword *)where = val; 111 return; 112 } 113 #endif 114 *(Elf_Sword *)where = val; 115 return; 116 } 117 #if BYTE_ORDER == LITTLE_ENDIAN 118 (void)memcpy(where, &val, len); 119 #endif 120 #if BYTE_ORDER == BIG_ENDIAN 121 const uint8_t *valp = (const void *)&val; 122 (void)memcpy(where, valp + sizeof(val) - len, len); 123 #endif 124 } 125 126 127 void 128 _rtld_setup_pltgot(const Obj_Entry *obj) 129 { 130 obj->pltgot[0] = (Elf_Addr) &_rtld_bind_start; 131 /* XXX only if obj->pltgot[1] & 0x80000000 ?? */ 132 obj->pltgot[1] |= (Elf_Addr) obj; 133 } 134 135 void 136 _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Addr relocbase) 137 { 138 const Elf_Rel *rel = 0, *rellim; 139 Elf_Addr relsz = 0; 140 void *where; 141 const Elf_Sym *symtab = NULL, *sym; 142 Elf_Addr *got = NULL; 143 Elf_Word local_gotno = 0, symtabno = 0, gotsym = 0; 144 size_t i; 145 146 for (; dynp->d_tag != DT_NULL; dynp++) { 147 switch (dynp->d_tag) { 148 case DT_REL: 149 rel = (const Elf_Rel *)(relocbase + dynp->d_un.d_ptr); 150 break; 151 case DT_RELSZ: 152 relsz = dynp->d_un.d_val; 153 break; 154 case DT_SYMTAB: 155 symtab = (const Elf_Sym *)(relocbase + dynp->d_un.d_ptr); 156 break; 157 case DT_PLTGOT: 158 got = (Elf_Addr *)(relocbase + dynp->d_un.d_ptr); 159 break; 160 case DT_MIPS_LOCAL_GOTNO: 161 local_gotno = dynp->d_un.d_val; 162 break; 163 case DT_MIPS_SYMTABNO: 164 symtabno = dynp->d_un.d_val; 165 break; 166 case DT_MIPS_GOTSYM: 167 gotsym = dynp->d_un.d_val; 168 break; 169 } 170 } 171 172 i = (got[1] & 0x80000000) ? 2 : 1; 173 /* Relocate the local GOT entries */ 174 got += i; 175 for (; i < local_gotno; i++) 176 *got++ += relocbase; 177 sym = symtab + gotsym; 178 /* Now do the global GOT entries */ 179 for (i = gotsym; i < symtabno; i++) { 180 *got = sym->st_value + relocbase; 181 ++sym; 182 ++got; 183 } 184 185 rellim = (const Elf_Rel *)((uintptr_t)rel + relsz); 186 for (; rel < rellim; rel++) { 187 Elf_Word r_symndx, r_type; 188 189 where = (void *)(relocbase + rel->r_offset); 190 191 r_symndx = ELF_R_SYM(rel->r_info); 192 r_type = ELF_R_TYPE(rel->r_info); 193 194 switch (r_type & 0xff) { 195 case R_TYPE(REL32): { 196 const size_t rlen = 197 ELF_R_NXTTYPE_64_P(r_type) 198 ? sizeof(Elf_Sxword) 199 : sizeof(Elf_Sword); 200 Elf_Sxword old = load_ptr(where, rlen); 201 Elf_Sxword val = old; 202 #if ELFSIZE == 64 203 assert(r_type == R_TYPE(REL32) 204 || r_type == (R_TYPE(REL32)|(R_TYPE(64) << 8))); 205 #endif 206 assert(r_symndx < gotsym); 207 sym = symtab + r_symndx; 208 assert(ELF_ST_BIND(sym->st_info) == STB_LOCAL); 209 val += relocbase; 210 store_ptr(where, val, sizeof(Elf_Sword)); 211 rdbg(("REL32/L(%p) %p -> %p in <self>", 212 where, (void *)old, (void *)val)); 213 store_ptr(where, val, rlen); 214 break; 215 } 216 217 case R_TYPE(GPREL32): 218 case R_TYPE(NONE): 219 break; 220 221 222 default: 223 abort(); 224 } 225 } 226 } 227 228 int 229 _rtld_relocate_nonplt_objects(Obj_Entry *obj) 230 { 231 const Elf_Rel *rel; 232 Elf_Addr *got = obj->pltgot; 233 const Elf_Sym *sym, *def = NULL; 234 const Obj_Entry *defobj = NULL; 235 unsigned long last_symnum = ULONG_MAX; 236 Elf_Word i; 237 #ifdef SUPPORT_OLD_BROKEN_LD 238 int broken; 239 #endif 240 241 #ifdef SUPPORT_OLD_BROKEN_LD 242 broken = 0; 243 sym = obj->symtab; 244 for (i = 1; i < 12; i++) 245 if (sym[i].st_info == ELF_ST_INFO(STB_LOCAL, STT_NOTYPE)) 246 broken = 1; 247 dbg(("%s: broken=%d", obj->path, broken)); 248 #endif 249 250 i = (got[1] & 0x80000000) ? 2 : 1; 251 /* Relocate the local GOT entries */ 252 got += i; 253 for (; i < obj->local_gotno; i++) 254 *got++ += (Elf_Addr)obj->relocbase; 255 sym = obj->symtab + obj->gotsym; 256 /* Now do the global GOT entries */ 257 for (i = obj->gotsym; i < obj->symtabno; i++) { 258 rdbg((" doing got %d sym %p (%s, %lx)", i - obj->gotsym, sym, 259 sym->st_name + obj->strtab, (u_long) *got)); 260 261 #ifdef SUPPORT_OLD_BROKEN_LD 262 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC && 263 broken && sym->st_shndx == SHN_UNDEF) { 264 /* 265 * XXX DANGER WILL ROBINSON! 266 * You might think this is stupid, as it intentionally 267 * defeats lazy binding -- and you'd be right. 268 * Unfortunately, for lazy binding to work right, we 269 * need to a way to force the GOT slots used for 270 * function pointers to be resolved immediately. This 271 * is supposed to be done automatically by the linker, 272 * by not outputting a PLT slot and setting st_value 273 * to 0 if there are non-PLT references, but older 274 * versions of GNU ld do not do this. 275 */ 276 def = _rtld_find_symdef(i, obj, &defobj, false); 277 if (def == NULL) 278 return -1; 279 *got = def->st_value + (Elf_Addr)defobj->relocbase; 280 } else 281 #endif 282 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC && 283 sym->st_value != 0 && sym->st_shndx == SHN_UNDEF) { 284 /* 285 * If there are non-PLT references to the function, 286 * st_value should be 0, forcing us to resolve the 287 * address immediately. 288 * 289 * XXX DANGER WILL ROBINSON! 290 * The linker is not outputting PLT slots for calls to 291 * functions that are defined in the same shared 292 * library. This is a bug, because it can screw up 293 * link ordering rules if the symbol is defined in 294 * more than one module. For now, if there is a 295 * definition, we fail the test above and force a full 296 * symbol lookup. This means that all intra-module 297 * calls are bound immediately. - mycroft, 2003/09/24 298 */ 299 *got = sym->st_value + (Elf_Addr)obj->relocbase; 300 } else if (sym->st_info == ELF_ST_INFO(STB_GLOBAL, STT_SECTION)) { 301 /* Symbols with index SHN_ABS are not relocated. */ 302 if (sym->st_shndx != SHN_ABS) 303 *got = sym->st_value + 304 (Elf_Addr)obj->relocbase; 305 } else { 306 def = _rtld_find_symdef(i, obj, &defobj, false); 307 if (def == NULL) 308 return -1; 309 *got = def->st_value + (Elf_Addr)defobj->relocbase; 310 } 311 312 rdbg((" --> now %lx", (u_long) *got)); 313 ++sym; 314 ++got; 315 } 316 317 got = obj->pltgot; 318 for (rel = obj->rel; rel < obj->rellim; rel++) { 319 unsigned long symnum; 320 void *where; 321 322 where = obj->relocbase + rel->r_offset; 323 324 switch (ELF_R_TYPE(rel->r_info) & 0xff) { 325 #if ELFSIZE == 64 326 case R_TYPE(TLS_DTPMOD64): 327 case R_TYPE(TLS_DTPREL64): 328 case R_TYPE(TLS_TPREL64): 329 #else 330 case R_TYPE(TLS_DTPMOD32): 331 case R_TYPE(TLS_DTPREL32): 332 case R_TYPE(TLS_TPREL32): 333 #endif 334 symnum = ELF_R_SYM(rel->r_info); 335 if (last_symnum != symnum) { 336 last_symnum = symnum; 337 def = _rtld_find_symdef(symnum, obj, &defobj, 338 false); 339 if (def == NULL) 340 return -1; 341 } 342 break; 343 default: 344 break; 345 } 346 347 switch (ELF_R_TYPE(rel->r_info) & 0xff) { 348 case R_TYPE(NONE): 349 break; 350 351 case R_TYPE(REL32): { 352 /* 32-bit PC-relative reference */ 353 const Elf_Sym *def2; 354 const size_t rlen = 355 ELF_R_NXTTYPE_64_P(ELF_R_TYPE(rel->r_info)) 356 ? sizeof(Elf_Sxword) 357 : sizeof(Elf_Sword); 358 Elf_Sxword old = load_ptr(where, rlen); 359 Elf_Sxword val = old; 360 361 def2 = obj->symtab + ELF_R_SYM(rel->r_info); 362 363 if (ELF_R_SYM(rel->r_info) >= obj->gotsym) { 364 val += got[obj->local_gotno + 365 ELF_R_SYM(rel->r_info) - obj->gotsym]; 366 rdbg(("REL32/G(%p) %p --> %p (%s) in %s", 367 where, (void *)old, (void *)val, 368 obj->strtab + def2->st_name, 369 obj->path)); 370 } else { 371 /* 372 * XXX: ABI DIFFERENCE! 373 * 374 * Old NetBSD binutils would generate shared 375 * libs with section-relative relocations being 376 * already adjusted for the start address of 377 * the section. 378 * 379 * New binutils, OTOH, generate shared libs 380 * with the same relocations being based at 381 * zero, so we need to add in the start address 382 * of the section. 383 * 384 * --rkb, Oct 6, 2001 385 */ 386 387 if (def2->st_info == 388 ELF_ST_INFO(STB_LOCAL, STT_SECTION) 389 #ifdef SUPPORT_OLD_BROKEN_LD 390 && !broken 391 #endif 392 ) 393 val += (Elf_Addr)def->st_value; 394 395 val += (Elf_Addr)obj->relocbase; 396 397 rdbg(("REL32/L(%p) %p -> %p (%s) in %s", 398 where, (void *)old, (void *)val, 399 obj->strtab + def2->st_name, obj->path)); 400 } 401 store_ptr(where, val, rlen); 402 break; 403 } 404 405 #if ELFSIZE == 64 406 case R_TYPE(TLS_DTPMOD64): 407 #else 408 case R_TYPE(TLS_DTPMOD32): 409 #endif 410 { 411 Elf_Addr old = load_ptr(where, ELFSIZE / 8); 412 Elf_Addr val = old; 413 414 val += (Elf_Addr)defobj->tlsindex; 415 416 store_ptr(where, val, ELFSIZE / 8); 417 rdbg(("DTPMOD %s in %s --> %p in %s", 418 obj->strtab + obj->symtab[ELF_R_SYM(rel->r_info)].st_name, 419 obj->path, (void *)old, defobj->path)); 420 break; 421 } 422 423 #if ELFSIZE == 64 424 case R_TYPE(TLS_DTPREL64): 425 #else 426 case R_TYPE(TLS_DTPREL32): 427 #endif 428 { 429 Elf_Addr old = load_ptr(where, ELFSIZE / 8); 430 Elf_Addr val = old; 431 432 if (!defobj->tls_done && _rtld_tls_offset_allocate(obj)) 433 return -1; 434 435 val += (Elf_Addr)def->st_value - TLS_DTV_OFFSET; 436 store_ptr(where, val, ELFSIZE / 8); 437 438 rdbg(("DTPREL %s in %s --> %p in %s", 439 obj->strtab + obj->symtab[ELF_R_SYM(rel->r_info)].st_name, 440 obj->path, (void *)old, defobj->path)); 441 break; 442 } 443 444 #if ELFSIZE == 64 445 case R_TYPE(TLS_TPREL64): 446 #else 447 case R_TYPE(TLS_TPREL32): 448 #endif 449 { 450 Elf_Addr old = load_ptr(where, ELFSIZE / 8); 451 Elf_Addr val = old; 452 453 if (!defobj->tls_done && _rtld_tls_offset_allocate(obj)) 454 return -1; 455 456 val += (Elf_Addr)(def->st_value + defobj->tlsoffset 457 - TLS_TP_OFFSET); 458 store_ptr(where, val, ELFSIZE / 8); 459 460 rdbg(("TPREL %s in %s --> %p in %s", 461 obj->strtab + obj->symtab[ELF_R_SYM(rel->r_info)].st_name, 462 obj->path, where, defobj->path)); 463 break; 464 } 465 466 default: 467 rdbg(("sym = %lu, type = %lu, offset = %p, " 468 "contents = %p, symbol = %s", 469 (u_long)ELF_R_SYM(rel->r_info), 470 (u_long)ELF_R_TYPE(rel->r_info), 471 (void *)rel->r_offset, 472 (void *)load_ptr(where, sizeof(Elf_Sword)), 473 obj->strtab + obj->symtab[ELF_R_SYM(rel->r_info)].st_name)); 474 _rtld_error("%s: Unsupported relocation type %ld " 475 "in non-PLT relocations", 476 obj->path, (u_long) ELF_R_TYPE(rel->r_info)); 477 return -1; 478 } 479 } 480 481 return 0; 482 } 483 484 int 485 _rtld_relocate_plt_lazy(Obj_Entry *obj) 486 { 487 /* PLT fixups were done above in the GOT relocation. */ 488 return 0; 489 } 490 491 static inline int 492 _rtld_relocate_plt_object(const Obj_Entry *obj, Elf_Word sym, Elf_Addr *tp) 493 { 494 Elf_Addr *got = obj->pltgot; 495 const Elf_Sym *def; 496 const Obj_Entry *defobj; 497 Elf_Addr new_value; 498 499 def = _rtld_find_plt_symdef(sym, obj, &defobj, tp != NULL); 500 if (__predict_false(def == NULL)) 501 return -1; 502 if (__predict_false(def == &_rtld_sym_zero)) 503 return 0; 504 505 if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) { 506 if (tp == NULL) 507 return 0; 508 new_value = _rtld_resolve_ifunc(defobj, def); 509 } else { 510 new_value = (Elf_Addr)(defobj->relocbase + def->st_value); 511 } 512 rdbg(("bind now/fixup in %s --> new=%p", 513 defobj->strtab + def->st_name, (void *)new_value)); 514 got[obj->local_gotno + sym - obj->gotsym] = new_value; 515 516 if (tp) 517 *tp = new_value; 518 return 0; 519 } 520 521 caddr_t 522 _rtld_bind(Elf_Word a0, Elf_Addr a1, Elf_Addr a2, Elf_Addr a3) 523 { 524 Elf_Addr *got = (Elf_Addr *)(a2 - 0x7ff0); 525 const Obj_Entry *obj = (Obj_Entry *)(got[1] & GOT1_MASK); 526 Elf_Addr new_value = 0; /* XXX gcc */ 527 int err; 528 529 _rtld_shared_enter(); 530 err = _rtld_relocate_plt_object(obj, a0, &new_value); 531 if (err) 532 _rtld_die(); 533 _rtld_shared_exit(); 534 535 return (caddr_t)new_value; 536 } 537 538 int 539 _rtld_relocate_plt_objects(const Obj_Entry *obj) 540 { 541 const Elf_Sym *sym = obj->symtab + obj->gotsym; 542 Elf_Word i; 543 544 for (i = obj->gotsym; i < obj->symtabno; i++, sym++) { 545 if (ELF_ST_TYPE(sym->st_info) == STT_FUNC) 546 if (_rtld_relocate_plt_object(obj, i, NULL) < 0) 547 return -1; 548 } 549 550 return 0; 551 } 552