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