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