1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "crazy_linker_elf_relocations.h" 6 7 #include <errno.h> 8 9 #include "crazy_linker_debug.h" 10 #include "crazy_linker_elf_symbols.h" 11 #include "crazy_linker_elf_view.h" 12 #include "crazy_linker_error.h" 13 #include "crazy_linker_util.h" 14 #include "linker_phdr.h" 15 16 #define DEBUG_RELOCATIONS 0 17 18 #define RLOG(...) LOG_IF(DEBUG_RELOCATIONS, __VA_ARGS__) 19 #define RLOG_ERRNO(...) LOG_ERRNO_IF(DEBUG_RELOCATIONS, __VA_ARGS__) 20 21 #ifndef DF_SYMBOLIC 22 #define DF_SYMBOLIC 2 23 #endif 24 25 #ifndef DF_TEXTREL 26 #define DF_TEXTREL 4 27 #endif 28 29 #ifndef DT_FLAGS 30 #define DT_FLAGS 30 31 #endif 32 33 // Processor-specific relocation types supported by the linker. 34 #ifdef __arm__ 35 36 /* arm32 relocations */ 37 #define R_ARM_ABS32 2 38 #define R_ARM_REL32 3 39 #define R_ARM_GLOB_DAT 21 40 #define R_ARM_JUMP_SLOT 22 41 #define R_ARM_COPY 20 42 #define R_ARM_RELATIVE 23 43 44 #endif // __arm__ 45 46 #ifdef __aarch64__ 47 48 /* arm64 relocations */ 49 #define R_AARCH64_ABS64 257 50 #define R_AARCH64_COPY 1024 51 #define R_AARCH64_GLOB_DAT 1025 52 #define R_AARCH64_JUMP_SLOT 1026 53 #define R_AARCH64_RELATIVE 1027 54 55 #endif // __aarch64__ 56 57 #ifdef __i386__ 58 59 /* i386 relocations */ 60 #define R_386_32 1 61 #define R_386_PC32 2 62 #define R_386_GLOB_DAT 6 63 #define R_386_JMP_SLOT 7 64 #define R_386_RELATIVE 8 65 66 #endif // __i386__ 67 68 namespace crazy { 69 70 namespace { 71 72 // List of known relocation types the relocator knows about. 73 enum RelocationType { 74 RELOCATION_TYPE_UNKNOWN = 0, 75 RELOCATION_TYPE_ABSOLUTE = 1, 76 RELOCATION_TYPE_RELATIVE = 2, 77 RELOCATION_TYPE_PC_RELATIVE = 3, 78 RELOCATION_TYPE_COPY = 4, 79 }; 80 81 // Convert an ELF relocation type info a RelocationType value. 82 RelocationType GetRelocationType(ELF::Word r_type) { 83 switch (r_type) { 84 #ifdef __arm__ 85 case R_ARM_JUMP_SLOT: 86 case R_ARM_GLOB_DAT: 87 case R_ARM_ABS32: 88 return RELOCATION_TYPE_ABSOLUTE; 89 90 case R_ARM_REL32: 91 case R_ARM_RELATIVE: 92 return RELOCATION_TYPE_RELATIVE; 93 94 case R_ARM_COPY: 95 return RELOCATION_TYPE_COPY; 96 #endif 97 98 #ifdef __aarch64__ 99 case R_AARCH64_JUMP_SLOT: 100 case R_AARCH64_GLOB_DAT: 101 case R_AARCH64_ABS64: 102 return RELOCATION_TYPE_ABSOLUTE; 103 104 case R_AARCH64_RELATIVE: 105 return RELOCATION_TYPE_RELATIVE; 106 107 case R_AARCH64_COPY: 108 return RELOCATION_TYPE_COPY; 109 #endif 110 111 #ifdef __i386__ 112 case R_386_JMP_SLOT: 113 case R_386_GLOB_DAT: 114 case R_386_32: 115 return RELOCATION_TYPE_ABSOLUTE; 116 117 case R_386_RELATIVE: 118 return RELOCATION_TYPE_RELATIVE; 119 120 case R_386_PC32: 121 return RELOCATION_TYPE_PC_RELATIVE; 122 #endif 123 124 #ifdef __mips__ 125 case R_MIPS_REL32: 126 return RELOCATION_TYPE_RELATIVE; 127 #endif 128 129 default: 130 return RELOCATION_TYPE_UNKNOWN; 131 } 132 } 133 134 } // namespace 135 136 bool ElfRelocations::Init(const ElfView* view, Error* error) { 137 // Save these for later. 138 phdr_ = view->phdr(); 139 phdr_count_ = view->phdr_count(); 140 load_bias_ = view->load_bias(); 141 142 // We handle only Rel or Rela, but not both. If DT_RELA or DT_RELASZ 143 // then we require DT_PLTREL to agree. 144 bool has_rela_relocations = false; 145 bool has_rel_relocations = false; 146 147 // Parse the dynamic table. 148 ElfView::DynamicIterator dyn(view); 149 for (; dyn.HasNext(); dyn.GetNext()) { 150 ELF::Addr dyn_value = dyn.GetValue(); 151 uintptr_t dyn_addr = dyn.GetAddress(view->load_bias()); 152 153 const ELF::Addr tag = dyn.GetTag(); 154 switch (tag) { 155 case DT_PLTREL: 156 RLOG(" DT_PLTREL value=%d\n", dyn_value); 157 if (dyn_value != DT_REL && dyn_value != DT_RELA) { 158 *error = "Invalid DT_PLTREL value in dynamic section"; 159 return false; 160 } 161 relocations_type_ = dyn_value; 162 break; 163 case DT_JMPREL: 164 RLOG(" DT_JMPREL addr=%p\n", dyn_addr); 165 plt_relocations_ = dyn_addr; 166 break; 167 case DT_PLTRELSZ: 168 plt_relocations_size_ = dyn_value; 169 RLOG(" DT_PLTRELSZ size=%d\n", dyn_value); 170 break; 171 case DT_RELA: 172 case DT_REL: 173 RLOG(" %s addr=%p\n", 174 (tag == DT_RELA) ? "DT_RELA" : "DT_REL", 175 dyn_addr); 176 if (relocations_) { 177 *error = "Unsupported DT_RELA/DT_REL combination in dynamic section"; 178 return false; 179 } 180 relocations_ = dyn_addr; 181 if (tag == DT_RELA) 182 has_rela_relocations = true; 183 else 184 has_rel_relocations = true; 185 break; 186 case DT_RELASZ: 187 case DT_RELSZ: 188 RLOG(" %s size=%d\n", 189 (tag == DT_RELASZ) ? "DT_RELASZ" : "DT_RELSZ", 190 dyn_addr); 191 if (relocations_size_) { 192 *error = "Unsupported DT_RELASZ/DT_RELSZ combination in dyn section"; 193 return false; 194 } 195 relocations_size_ = dyn_value; 196 if (tag == DT_RELASZ) 197 has_rela_relocations = true; 198 else 199 has_rel_relocations = true; 200 break; 201 case DT_PLTGOT: 202 // Only used on MIPS currently. Could also be used on other platforms 203 // when lazy binding (i.e. RTLD_LAZY) is implemented. 204 RLOG(" DT_PLTGOT addr=%p\n", dyn_addr); 205 plt_got_ = reinterpret_cast<ELF::Addr*>(dyn_addr); 206 break; 207 case DT_TEXTREL: 208 RLOG(" DT_TEXTREL\n"); 209 has_text_relocations_ = true; 210 break; 211 case DT_SYMBOLIC: 212 RLOG(" DT_SYMBOLIC\n"); 213 has_symbolic_ = true; 214 break; 215 case DT_FLAGS: 216 if (dyn_value & DF_TEXTREL) 217 has_text_relocations_ = true; 218 if (dyn_value & DF_SYMBOLIC) 219 has_symbolic_ = true; 220 RLOG(" DT_FLAGS has_text_relocations=%s has_symbolic=%s\n", 221 has_text_relocations_ ? "true" : "false", 222 has_symbolic_ ? "true" : "false"); 223 break; 224 #if defined(__mips__) 225 case DT_MIPS_SYMTABNO: 226 RLOG(" DT_MIPS_SYMTABNO value=%d\n", dyn_value); 227 mips_symtab_count_ = dyn_value; 228 break; 229 230 case DT_MIPS_LOCAL_GOTNO: 231 RLOG(" DT_MIPS_LOCAL_GOTNO value=%d\n", dyn_value); 232 mips_local_got_count_ = dyn_value; 233 break; 234 235 case DT_MIPS_GOTSYM: 236 RLOG(" DT_MIPS_GOTSYM value=%d\n", dyn_value); 237 mips_gotsym_ = dyn_value; 238 break; 239 #endif 240 default: 241 ; 242 } 243 } 244 245 if (relocations_type_ != DT_REL && relocations_type_ != DT_RELA) { 246 *error = "Unsupported or missing DT_PLTREL in dynamic section"; 247 return false; 248 } 249 250 if (relocations_type_ == DT_REL && has_rela_relocations) { 251 *error = "Found DT_RELA in dyn section, but DT_PLTREL is DT_REL"; 252 return false; 253 } 254 if (relocations_type_ == DT_RELA && has_rel_relocations) { 255 *error = "Found DT_REL in dyn section, but DT_PLTREL is DT_RELA"; 256 return false; 257 } 258 259 return true; 260 } 261 262 bool ElfRelocations::ApplyAll(const ElfSymbols* symbols, 263 SymbolResolver* resolver, 264 Error* error) { 265 LOG("%s: Enter\n", __FUNCTION__); 266 267 if (has_text_relocations_) { 268 if (phdr_table_unprotect_segments(phdr_, phdr_count_, load_bias_) < 0) { 269 error->Format("Can't unprotect loadable segments: %s", strerror(errno)); 270 return false; 271 } 272 } 273 274 if (relocations_type_ == DT_REL) { 275 if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(plt_relocations_), 276 plt_relocations_size_ / sizeof(ELF::Rel), 277 symbols, 278 resolver, 279 error)) 280 return false; 281 if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(relocations_), 282 relocations_size_ / sizeof(ELF::Rel), 283 symbols, 284 resolver, 285 error)) 286 return false; 287 } 288 289 else if (relocations_type_ == DT_RELA) { 290 if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(plt_relocations_), 291 plt_relocations_size_ / sizeof(ELF::Rela), 292 symbols, 293 resolver, 294 error)) 295 return false; 296 if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(relocations_), 297 relocations_size_ / sizeof(ELF::Rela), 298 symbols, 299 resolver, 300 error)) 301 return false; 302 } 303 304 #ifdef __mips__ 305 if (!RelocateMipsGot(symbols, resolver, error)) 306 return false; 307 #endif 308 309 if (has_text_relocations_) { 310 if (phdr_table_protect_segments(phdr_, phdr_count_, load_bias_) < 0) { 311 error->Format("Can't reprotect loadable segments: %s", strerror(errno)); 312 return false; 313 } 314 } 315 316 LOG("%s: Done\n", __FUNCTION__); 317 return true; 318 } 319 320 bool ElfRelocations::ApplyRelaReloc(const ELF::Rela* rela, 321 ELF::Addr sym_addr, 322 bool resolved CRAZY_UNUSED, 323 Error* error) { 324 const ELF::Word rela_type = ELF_R_TYPE(rela->r_info); 325 const ELF::Word CRAZY_UNUSED rela_symbol = ELF_R_SYM(rela->r_info); 326 const ELF::Sword CRAZY_UNUSED addend = rela->r_addend; 327 328 const ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_); 329 330 RLOG(" rela reloc=%p offset=%p type=%d addend=%p\n", 331 reloc, 332 rela->r_offset, 333 rela_type, 334 addend); 335 336 // Apply the relocation. 337 ELF::Addr* CRAZY_UNUSED target = reinterpret_cast<ELF::Addr*>(reloc); 338 switch (rela_type) { 339 #ifdef __aarch64__ 340 case R_AARCH64_JUMP_SLOT: 341 RLOG(" R_AARCH64_JUMP_SLOT target=%p addr=%p\n", 342 target, 343 sym_addr + addend); 344 *target = sym_addr + addend; 345 break; 346 347 case R_AARCH64_GLOB_DAT: 348 RLOG(" R_AARCH64_GLOB_DAT target=%p addr=%p\n", 349 target, 350 sym_addr + addend); 351 *target = sym_addr + addend; 352 break; 353 354 case R_AARCH64_ABS64: 355 RLOG(" R_AARCH64_ABS64 target=%p (%p) addr=%p\n", 356 target, 357 *target, 358 sym_addr + addend); 359 *target += sym_addr + addend; 360 break; 361 362 case R_AARCH64_RELATIVE: 363 RLOG(" R_AARCH64_RELATIVE target=%p (%p) bias=%p\n", 364 target, 365 *target, 366 load_bias_ + addend); 367 if (__builtin_expect(rela_symbol, 0)) { 368 *error = "Invalid relative relocation with symbol"; 369 return false; 370 } 371 *target = load_bias_ + addend; 372 break; 373 374 case R_AARCH64_COPY: 375 // NOTE: These relocations are forbidden in shared libraries. 376 RLOG(" R_AARCH64_COPY\n"); 377 *error = "Invalid R_AARCH64_COPY relocation in shared library"; 378 return false; 379 #endif // __aarch64__ 380 381 default: 382 error->Format("Invalid relocation type (%d)", rela_type); 383 return false; 384 } 385 386 return true; 387 } 388 389 bool ElfRelocations::ApplyRelReloc(const ELF::Rel* rel, 390 ELF::Addr sym_addr, 391 bool resolved CRAZY_UNUSED, 392 Error* error) { 393 const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); 394 const ELF::Word CRAZY_UNUSED rel_symbol = ELF_R_SYM(rel->r_info); 395 396 const ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); 397 398 RLOG(" rel reloc=%p offset=%p type=%d\n", reloc, rel->r_offset, rel_type); 399 400 // Apply the relocation. 401 ELF::Addr* CRAZY_UNUSED target = reinterpret_cast<ELF::Addr*>(reloc); 402 switch (rel_type) { 403 #ifdef __arm__ 404 case R_ARM_JUMP_SLOT: 405 RLOG(" R_ARM_JUMP_SLOT target=%p addr=%p\n", target, sym_addr); 406 *target = sym_addr; 407 break; 408 409 case R_ARM_GLOB_DAT: 410 RLOG(" R_ARM_GLOB_DAT target=%p addr=%p\n", target, sym_addr); 411 *target = sym_addr; 412 break; 413 414 case R_ARM_ABS32: 415 RLOG(" R_ARM_ABS32 target=%p (%p) addr=%p\n", 416 target, 417 *target, 418 sym_addr); 419 *target += sym_addr; 420 break; 421 422 case R_ARM_REL32: 423 RLOG(" R_ARM_REL32 target=%p (%p) addr=%p offset=%p\n", 424 target, 425 *target, 426 sym_addr, 427 rel->r_offset); 428 *target += sym_addr - rel->r_offset; 429 break; 430 431 case R_ARM_RELATIVE: 432 RLOG(" R_ARM_RELATIVE target=%p (%p) bias=%p\n", 433 target, 434 *target, 435 load_bias_); 436 if (__builtin_expect(rel_symbol, 0)) { 437 *error = "Invalid relative relocation with symbol"; 438 return false; 439 } 440 *target += load_bias_; 441 break; 442 443 case R_ARM_COPY: 444 // NOTE: These relocations are forbidden in shared libraries. 445 // The Android linker has special code to deal with this, which 446 // is not needed here. 447 RLOG(" R_ARM_COPY\n"); 448 *error = "Invalid R_ARM_COPY relocation in shared library"; 449 return false; 450 #endif // __arm__ 451 452 #ifdef __i386__ 453 case R_386_JMP_SLOT: 454 *target = sym_addr; 455 break; 456 457 case R_386_GLOB_DAT: 458 *target = sym_addr; 459 break; 460 461 case R_386_RELATIVE: 462 if (rel_symbol) { 463 *error = "Invalid relative relocation with symbol"; 464 return false; 465 } 466 *target += load_bias_; 467 break; 468 469 case R_386_32: 470 *target += sym_addr; 471 break; 472 473 case R_386_PC32: 474 *target += (sym_addr - reloc); 475 break; 476 #endif // __i386__ 477 478 #ifdef __mips__ 479 case R_MIPS_REL32: 480 if (resolved) 481 *target += sym_addr; 482 else 483 *target += load_bias_; 484 break; 485 #endif // __mips__ 486 487 default: 488 error->Format("Invalid relocation type (%d)", rel_type); 489 return false; 490 } 491 492 return true; 493 } 494 495 bool ElfRelocations::ResolveSymbol(ELF::Word rel_type, 496 ELF::Word rel_symbol, 497 const ElfSymbols* symbols, 498 SymbolResolver* resolver, 499 ELF::Addr reloc, 500 ELF::Addr* sym_addr, 501 Error* error) { 502 const char* sym_name = symbols->LookupNameById(rel_symbol); 503 RLOG(" symbol name='%s'\n", sym_name); 504 void* address = resolver->Lookup(sym_name); 505 506 if (address) { 507 // The symbol was found, so compute its address. 508 RLOG("%s: symbol %s resolved to %p\n", __FUNCTION__, sym_name, address); 509 *sym_addr = reinterpret_cast<ELF::Addr>(address); 510 return true; 511 } 512 513 // The symbol was not found. Normally this is an error except 514 // if this is a weak reference. 515 if (!symbols->IsWeakById(rel_symbol)) { 516 error->Format("Could not find symbol '%s'", sym_name); 517 return false; 518 } 519 520 RLOG("%s: weak reference to unresolved symbol %s\n", __FUNCTION__, sym_name); 521 522 // IHI0044C AAELF 4.5.1.1: 523 // Libraries are not searched to resolve weak references. 524 // It is not an error for a weak reference to remain 525 // unsatisfied. 526 // 527 // During linking, the value of an undefined weak reference is: 528 // - Zero if the relocation type is absolute 529 // - The address of the place if the relocation is pc-relative 530 // - The address of nominal base address if the relocation 531 // type is base-relative. 532 RelocationType r = GetRelocationType(rel_type); 533 if (r == RELOCATION_TYPE_ABSOLUTE || r == RELOCATION_TYPE_RELATIVE) { 534 *sym_addr = 0; 535 return true; 536 } 537 538 if (r == RELOCATION_TYPE_PC_RELATIVE) { 539 *sym_addr = reloc; 540 return true; 541 } 542 543 error->Format( 544 "Invalid weak relocation type (%d) for unknown symbol '%s'", 545 r, 546 sym_name); 547 return false; 548 } 549 550 bool ElfRelocations::ApplyRelRelocs(const ELF::Rel* rel, 551 size_t rel_count, 552 const ElfSymbols* symbols, 553 SymbolResolver* resolver, 554 Error* error) { 555 RLOG("%s: rel=%p rel_count=%d\n", __FUNCTION__, rel, rel_count); 556 557 if (!rel) 558 return true; 559 560 for (size_t rel_n = 0; rel_n < rel_count; rel++, rel_n++) { 561 const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); 562 const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info); 563 564 ELF::Addr sym_addr = 0; 565 ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); 566 RLOG(" %d/%d reloc=%p offset=%p type=%d symbol=%d\n", 567 rel_n + 1, 568 rel_count, 569 reloc, 570 rel->r_offset, 571 rel_type, 572 rel_symbol); 573 574 if (rel_type == 0) 575 continue; 576 577 bool resolved = false; 578 579 // If this is a symbolic relocation, compute the symbol's address. 580 if (__builtin_expect(rel_symbol != 0, 0)) { 581 resolved = ResolveSymbol(rel_type, 582 rel_symbol, 583 symbols, 584 resolver, 585 reloc, 586 &sym_addr, 587 error); 588 } 589 590 if (!ApplyRelReloc(rel, sym_addr, resolved, error)) 591 return false; 592 } 593 594 return true; 595 } 596 597 bool ElfRelocations::ApplyRelaRelocs(const ELF::Rela* rela, 598 size_t rela_count, 599 const ElfSymbols* symbols, 600 SymbolResolver* resolver, 601 Error* error) { 602 RLOG("%s: rela=%p rela_count=%d\n", __FUNCTION__, rela, rela_count); 603 604 if (!rela) 605 return true; 606 607 for (size_t rel_n = 0; rel_n < rela_count; rela++, rel_n++) { 608 const ELF::Word rel_type = ELF_R_TYPE(rela->r_info); 609 const ELF::Word rel_symbol = ELF_R_SYM(rela->r_info); 610 611 ELF::Addr sym_addr = 0; 612 ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_); 613 RLOG(" %d/%d reloc=%p offset=%p type=%d symbol=%d\n", 614 rel_n + 1, 615 rela_count, 616 reloc, 617 rela->r_offset, 618 rel_type, 619 rel_symbol); 620 621 if (rel_type == 0) 622 continue; 623 624 bool resolved = false; 625 626 // If this is a symbolic relocation, compute the symbol's address. 627 if (__builtin_expect(rel_symbol != 0, 0)) { 628 resolved = ResolveSymbol(rel_type, 629 rel_symbol, 630 symbols, 631 resolver, 632 reloc, 633 &sym_addr, 634 error); 635 } 636 637 if (!ApplyRelaReloc(rela, sym_addr, resolved, error)) 638 return false; 639 } 640 641 return true; 642 } 643 644 #ifdef __mips__ 645 bool ElfRelocations::RelocateMipsGot(const ElfSymbols* symbols, 646 SymbolResolver* resolver, 647 Error* error) { 648 if (!plt_got_) 649 return true; 650 651 // Handle the local GOT entries. 652 // This mimics what the system linker does. 653 // Note from the system linker: 654 // got[0]: lazy resolver function address. 655 // got[1]: may be used for a GNU extension. 656 // Set it to a recognizable address in case someone calls it 657 // (should be _rtld_bind_start). 658 ELF::Addr* got = plt_got_; 659 got[0] = 0xdeadbeef; 660 if (got[1] & 0x80000000) 661 got[1] = 0xdeadbeef; 662 663 for (ELF::Addr n = 2; n < mips_local_got_count_; ++n) 664 got[n] += load_bias_; 665 666 // Handle the global GOT entries. 667 got += mips_local_got_count_; 668 for (size_t idx = mips_gotsym_; idx < mips_symtab_count_; idx++, got++) { 669 const char* sym_name = symbols->LookupNameById(idx); 670 void* sym_addr = resolver->Lookup(sym_name); 671 if (sym_addr) { 672 // Found symbol, update GOT entry. 673 *got = reinterpret_cast<ELF::Addr>(sym_addr); 674 continue; 675 } 676 677 if (symbols->IsWeakById(idx)) { 678 // Undefined symbols are only ok if this is a weak reference. 679 // Update GOT entry to 0 though. 680 *got = 0; 681 continue; 682 } 683 684 error->Format("Cannot locate symbol %s", sym_name); 685 return false; 686 } 687 688 return true; 689 } 690 #endif // __mips__ 691 692 void ElfRelocations::AdjustRelocation(ELF::Word rel_type, 693 ELF::Addr src_reloc, 694 size_t dst_delta, 695 size_t map_delta) { 696 ELF::Addr* dst_ptr = reinterpret_cast<ELF::Addr*>(src_reloc + dst_delta); 697 698 switch (rel_type) { 699 #ifdef __arm__ 700 case R_ARM_RELATIVE: 701 *dst_ptr += map_delta; 702 break; 703 #endif // __arm__ 704 705 #ifdef __aarch64__ 706 case R_AARCH64_RELATIVE: 707 *dst_ptr += map_delta; 708 break; 709 #endif // __aarch64__ 710 711 #ifdef __i386__ 712 case R_386_RELATIVE: 713 *dst_ptr += map_delta; 714 break; 715 #endif 716 717 #ifdef __mips__ 718 case R_MIPS_REL32: 719 *dst_ptr += map_delta; 720 break; 721 #endif 722 default: 723 ; 724 } 725 } 726 727 void ElfRelocations::RelocateRela(size_t src_addr, 728 size_t dst_addr, 729 size_t map_addr, 730 size_t size) { 731 // Add this value to each source address to get the corresponding 732 // destination address. 733 const size_t dst_delta = dst_addr - src_addr; 734 const size_t map_delta = map_addr - src_addr; 735 736 // Ignore PLT relocations, which all target symbols (ignored here). 737 const ELF::Rela* rel = reinterpret_cast<ELF::Rela*>(relocations_); 738 const size_t relocations_count = relocations_size_ / sizeof(ELF::Rela); 739 const ELF::Rela* rel_limit = rel + relocations_count; 740 741 for (; rel < rel_limit; ++rel) { 742 const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); 743 const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info); 744 ELF::Addr src_reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); 745 746 if (rel_type == 0 || rel_symbol != 0) { 747 // Ignore empty and symbolic relocations 748 continue; 749 } 750 751 if (src_reloc < src_addr || src_reloc >= src_addr + size) { 752 // Ignore entries that don't relocate addresses inside the source section. 753 continue; 754 } 755 756 AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta); 757 } 758 } 759 760 void ElfRelocations::RelocateRel(size_t src_addr, 761 size_t dst_addr, 762 size_t map_addr, 763 size_t size) { 764 // Add this value to each source address to get the corresponding 765 // destination address. 766 const size_t dst_delta = dst_addr - src_addr; 767 const size_t map_delta = map_addr - src_addr; 768 769 // Ignore PLT relocations, which all target symbols (ignored here). 770 const ELF::Rel* rel = reinterpret_cast<ELF::Rel*>(relocations_); 771 const size_t relocations_count = relocations_size_ / sizeof(ELF::Rel); 772 const ELF::Rel* rel_limit = rel + relocations_count; 773 774 for (; rel < rel_limit; ++rel) { 775 const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); 776 const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info); 777 ELF::Addr src_reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); 778 779 if (rel_type == 0 || rel_symbol != 0) { 780 // Ignore empty and symbolic relocations 781 continue; 782 } 783 784 if (src_reloc < src_addr || src_reloc >= src_addr + size) { 785 // Ignore entries that don't relocate addresses inside the source section. 786 continue; 787 } 788 789 AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta); 790 } 791 } 792 793 void ElfRelocations::CopyAndRelocate(size_t src_addr, 794 size_t dst_addr, 795 size_t map_addr, 796 size_t size) { 797 // First, a straight copy. 798 ::memcpy(reinterpret_cast<void*>(dst_addr), 799 reinterpret_cast<void*>(src_addr), 800 size); 801 802 // Relocate relocations. 803 if (relocations_type_ == DT_REL) 804 RelocateRel(src_addr, dst_addr, map_addr, size); 805 806 else if (relocations_type_ == DT_RELA) 807 RelocateRela(src_addr, dst_addr, map_addr, size); 808 809 #ifdef __mips__ 810 // Add this value to each source address to get the corresponding 811 // destination address. 812 const size_t dst_delta = dst_addr - src_addr; 813 const size_t map_delta = map_addr - src_addr; 814 815 // Only relocate local GOT entries. 816 ELF::Addr* got = plt_got_; 817 if (got) { 818 for (ELF::Addr n = 2; n < mips_local_got_count_; ++n) { 819 size_t got_addr = reinterpret_cast<size_t>(&got[n]); 820 if (got_addr < src_addr || got_addr >= src_addr + size) 821 continue; 822 ELF::Addr* dst_ptr = reinterpret_cast<ELF::Addr*>(got_addr + dst_delta); 823 *dst_ptr += map_delta; 824 } 825 } 826 #endif 827 } 828 829 } // namespace crazy 830