Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "crazy_linker_elf_relocations.h" | 5 #include "crazy_linker_elf_relocations.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 | 8 |
| 9 #include "crazy_linker_debug.h" | 9 #include "crazy_linker_debug.h" |
| 10 #include "crazy_linker_elf_symbols.h" | 10 #include "crazy_linker_elf_symbols.h" |
| 11 #include "crazy_linker_elf_view.h" | 11 #include "crazy_linker_elf_view.h" |
| 12 #include "crazy_linker_error.h" | 12 #include "crazy_linker_error.h" |
| 13 #include "crazy_linker_system.h" | |
| 13 #include "crazy_linker_util.h" | 14 #include "crazy_linker_util.h" |
| 14 #include "linker_phdr.h" | 15 #include "linker_phdr.h" |
| 15 | 16 |
| 16 #define DEBUG_RELOCATIONS 0 | 17 #define DEBUG_RELOCATIONS 0 |
| 17 | 18 |
| 18 #define RLOG(...) LOG_IF(DEBUG_RELOCATIONS, __VA_ARGS__) | 19 #define RLOG(...) LOG_IF(DEBUG_RELOCATIONS, __VA_ARGS__) |
| 19 #define RLOG_ERRNO(...) LOG_ERRNO_IF(DEBUG_RELOCATIONS, __VA_ARGS__) | 20 #define RLOG_ERRNO(...) LOG_ERRNO_IF(DEBUG_RELOCATIONS, __VA_ARGS__) |
| 20 | 21 |
| 21 #ifndef DF_SYMBOLIC | 22 #ifndef DF_SYMBOLIC |
| 22 #define DF_SYMBOLIC 2 | 23 #define DF_SYMBOLIC 2 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 58 | 59 |
| 59 /* i386 relocations */ | 60 /* i386 relocations */ |
| 60 #define R_386_32 1 | 61 #define R_386_32 1 |
| 61 #define R_386_PC32 2 | 62 #define R_386_PC32 2 |
| 62 #define R_386_GLOB_DAT 6 | 63 #define R_386_GLOB_DAT 6 |
| 63 #define R_386_JMP_SLOT 7 | 64 #define R_386_JMP_SLOT 7 |
| 64 #define R_386_RELATIVE 8 | 65 #define R_386_RELATIVE 8 |
| 65 | 66 |
| 66 #endif // __i386__ | 67 #endif // __i386__ |
| 67 | 68 |
| 69 // Processor-specific extension dynamic tags for packed relocations. | |
| 70 #ifdef __arm__ | |
| 71 | |
| 72 #define DT_ANDROID_ARM_REL_OFFSET (DT_LOPROC) | |
| 73 #define DT_ANDROID_ARM_REL_SIZE (DT_LOPROC + 1) | |
|
rmcilroy
2014/06/18 10:56:05
nit - just move this up to the preceding ifdef __a
simonb1
2014/06/18 15:41:28
Moved to crazy_linker_shared_library.cpp in patch
| |
| 74 | |
| 75 #endif // __arm__ | |
| 76 | |
| 68 namespace crazy { | 77 namespace crazy { |
| 69 | 78 |
| 70 namespace { | 79 namespace { |
| 71 | 80 |
| 72 // List of known relocation types the relocator knows about. | 81 // List of known relocation types the relocator knows about. |
| 73 enum RelocationType { | 82 enum RelocationType { |
| 74 RELOCATION_TYPE_UNKNOWN = 0, | 83 RELOCATION_TYPE_UNKNOWN = 0, |
| 75 RELOCATION_TYPE_ABSOLUTE = 1, | 84 RELOCATION_TYPE_ABSOLUTE = 1, |
| 76 RELOCATION_TYPE_RELATIVE = 2, | 85 RELOCATION_TYPE_RELATIVE = 2, |
| 77 RELOCATION_TYPE_PC_RELATIVE = 3, | 86 RELOCATION_TYPE_PC_RELATIVE = 3, |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 214 break; | 223 break; |
| 215 case DT_FLAGS: | 224 case DT_FLAGS: |
| 216 if (dyn_value & DF_TEXTREL) | 225 if (dyn_value & DF_TEXTREL) |
| 217 has_text_relocations_ = true; | 226 has_text_relocations_ = true; |
| 218 if (dyn_value & DF_SYMBOLIC) | 227 if (dyn_value & DF_SYMBOLIC) |
| 219 has_symbolic_ = true; | 228 has_symbolic_ = true; |
| 220 RLOG(" DT_FLAGS has_text_relocations=%s has_symbolic=%s\n", | 229 RLOG(" DT_FLAGS has_text_relocations=%s has_symbolic=%s\n", |
| 221 has_text_relocations_ ? "true" : "false", | 230 has_text_relocations_ ? "true" : "false", |
| 222 has_symbolic_ ? "true" : "false"); | 231 has_symbolic_ ? "true" : "false"); |
| 223 break; | 232 break; |
| 233 #if defined(__arm__) | |
| 234 case DT_ANDROID_ARM_REL_OFFSET: | |
| 235 arm_packed_relocations_ = dyn.GetOffset(); | |
| 236 RLOG(" DT_ANDROID_ARM_REL_OFFSET addr=%p\n", arm_packed_relocations_); | |
| 237 break; | |
| 238 case DT_ANDROID_ARM_REL_SIZE: | |
| 239 arm_packed_relocations_size_ = dyn.GetValue(); | |
| 240 RLOG(" DT_ANDROID_ARM_REL_SIZE=%d\n", arm_packed_relocations_size_); | |
| 241 break; | |
| 242 #endif | |
| 224 #if defined(__mips__) | 243 #if defined(__mips__) |
| 225 case DT_MIPS_SYMTABNO: | 244 case DT_MIPS_SYMTABNO: |
| 226 RLOG(" DT_MIPS_SYMTABNO value=%d\n", dyn_value); | 245 RLOG(" DT_MIPS_SYMTABNO value=%d\n", dyn_value); |
| 227 mips_symtab_count_ = dyn_value; | 246 mips_symtab_count_ = dyn_value; |
| 228 break; | 247 break; |
| 229 | 248 |
| 230 case DT_MIPS_LOCAL_GOTNO: | 249 case DT_MIPS_LOCAL_GOTNO: |
| 231 RLOG(" DT_MIPS_LOCAL_GOTNO value=%d\n", dyn_value); | 250 RLOG(" DT_MIPS_LOCAL_GOTNO value=%d\n", dyn_value); |
| 232 mips_local_got_count_ = dyn_value; | 251 mips_local_got_count_ = dyn_value; |
| 233 break; | 252 break; |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 254 if (relocations_type_ == DT_RELA && has_rel_relocations) { | 273 if (relocations_type_ == DT_RELA && has_rel_relocations) { |
| 255 *error = "Found DT_REL in dyn section, but DT_PLTREL is DT_RELA"; | 274 *error = "Found DT_REL in dyn section, but DT_PLTREL is DT_RELA"; |
| 256 return false; | 275 return false; |
| 257 } | 276 } |
| 258 | 277 |
| 259 return true; | 278 return true; |
| 260 } | 279 } |
| 261 | 280 |
| 262 bool ElfRelocations::ApplyAll(const ElfSymbols* symbols, | 281 bool ElfRelocations::ApplyAll(const ElfSymbols* symbols, |
| 263 SymbolResolver* resolver, | 282 SymbolResolver* resolver, |
| 283 const char* full_path CRAZY_UNUSED, | |
|
rmcilroy
2014/06/18 10:56:05
Rather than passing the full path here, and having
simonb1
2014/06/18 15:41:28
Done. It's a bit more diffuse, so greater occurre
| |
| 264 Error* error) { | 284 Error* error) { |
| 265 LOG("%s: Enter\n", __FUNCTION__); | 285 LOG("%s: Enter\n", __FUNCTION__); |
| 266 | 286 |
| 267 if (has_text_relocations_) { | 287 if (has_text_relocations_) { |
| 268 if (phdr_table_unprotect_segments(phdr_, phdr_count_, load_bias_) < 0) { | 288 if (phdr_table_unprotect_segments(phdr_, phdr_count_, load_bias_) < 0) { |
| 269 error->Format("Can't unprotect loadable segments: %s", strerror(errno)); | 289 error->Format("Can't unprotect loadable segments: %s", strerror(errno)); |
| 270 return false; | 290 return false; |
| 271 } | 291 } |
| 272 } | 292 } |
| 273 | 293 |
| 274 if (relocations_type_ == DT_REL) { | 294 if (relocations_type_ == DT_REL) { |
| 275 if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(plt_relocations_), | 295 if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(plt_relocations_), |
| 276 plt_relocations_size_ / sizeof(ELF::Rel), | 296 plt_relocations_size_ / sizeof(ELF::Rel), |
| 277 symbols, | 297 symbols, |
| 278 resolver, | 298 resolver, |
| 279 error)) | 299 error)) |
| 280 return false; | 300 return false; |
| 281 if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(relocations_), | 301 if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(relocations_), |
| 282 relocations_size_ / sizeof(ELF::Rel), | 302 relocations_size_ / sizeof(ELF::Rel), |
| 283 symbols, | 303 symbols, |
| 284 resolver, | 304 resolver, |
| 285 error)) | 305 error)) |
| 286 return false; | 306 return false; |
| 287 } | 307 } |
| 288 | 308 |
| 289 else if (relocations_type_ == DT_RELA) { | 309 if (relocations_type_ == DT_RELA) { |
| 290 if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(plt_relocations_), | 310 if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(plt_relocations_), |
| 291 plt_relocations_size_ / sizeof(ELF::Rela), | 311 plt_relocations_size_ / sizeof(ELF::Rela), |
| 292 symbols, | 312 symbols, |
| 293 resolver, | 313 resolver, |
| 294 error)) | 314 error)) |
| 295 return false; | 315 return false; |
| 296 if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(relocations_), | 316 if (!ApplyRelaRelocs(reinterpret_cast<ELF::Rela*>(relocations_), |
| 297 relocations_size_ / sizeof(ELF::Rela), | 317 relocations_size_ / sizeof(ELF::Rela), |
| 298 symbols, | 318 symbols, |
| 299 resolver, | 319 resolver, |
| 300 error)) | 320 error)) |
| 301 return false; | 321 return false; |
| 302 } | 322 } |
| 303 | 323 |
| 324 #ifdef __arm__ | |
| 325 if (!ApplyArmPackedRelocs(full_path, error)) | |
| 326 return false; | |
| 327 #endif | |
| 328 | |
| 304 #ifdef __mips__ | 329 #ifdef __mips__ |
| 305 if (!RelocateMipsGot(symbols, resolver, error)) | 330 if (!RelocateMipsGot(symbols, resolver, error)) |
| 306 return false; | 331 return false; |
| 307 #endif | 332 #endif |
| 308 | 333 |
| 309 if (has_text_relocations_) { | 334 if (has_text_relocations_) { |
| 310 if (phdr_table_protect_segments(phdr_, phdr_count_, load_bias_) < 0) { | 335 if (phdr_table_protect_segments(phdr_, phdr_count_, load_bias_) < 0) { |
| 311 error->Format("Can't reprotect loadable segments: %s", strerror(errno)); | 336 error->Format("Can't reprotect loadable segments: %s", strerror(errno)); |
| 312 return false; | 337 return false; |
| 313 } | 338 } |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 634 error); | 659 error); |
| 635 } | 660 } |
| 636 | 661 |
| 637 if (!ApplyRelaReloc(rela, sym_addr, resolved, error)) | 662 if (!ApplyRelaReloc(rela, sym_addr, resolved, error)) |
| 638 return false; | 663 return false; |
| 639 } | 664 } |
| 640 | 665 |
| 641 return true; | 666 return true; |
| 642 } | 667 } |
| 643 | 668 |
| 669 #ifdef __arm__ | |
| 670 | |
| 671 // Helper class for decoding packed ARM relocation data. | |
| 672 // http://en.wikipedia.org/wiki/LEB128 | |
| 673 class Leb128Decoder { | |
| 674 public: | |
| 675 explicit Leb128Decoder(const uint8_t* encoding) | |
| 676 : encoding_(encoding), cursor_(0) { } | |
| 677 | |
| 678 uint32_t Dequeue() { | |
| 679 size_t extent = cursor_; | |
| 680 while (encoding_[extent] >> 7) | |
| 681 extent++; | |
| 682 | |
| 683 uint32_t value = 0; | |
| 684 for (size_t i = extent; i > cursor_; --i) { | |
| 685 value = (value << 7) | (encoding_[i] & 127); | |
| 686 } | |
| 687 value = (value << 7) | (encoding_[cursor_] & 127); | |
| 688 | |
| 689 cursor_ = extent + 1; | |
| 690 return value; | |
| 691 } | |
| 692 | |
| 693 private: | |
| 694 const uint8_t* encoding_; | |
| 695 size_t cursor_; | |
| 696 }; | |
| 697 | |
| 698 // Helper class to provide a simple scoped buffer. ScopedPtr is not | |
| 699 // usable here because it calls delete, not delete []. | |
| 700 class ScopedBuffer { | |
| 701 public: | |
| 702 explicit ScopedBuffer(size_t bytes) : buffer_(new uint8_t[bytes]) { } | |
| 703 ~ScopedBuffer() { delete [] buffer_; } | |
| 704 | |
| 705 uint8_t* Get() { return buffer_; } | |
| 706 | |
| 707 private: | |
| 708 uint8_t* buffer_; | |
| 709 }; | |
| 710 | |
| 711 bool ElfRelocations::ApplyArmPackedRelocs(const char* full_path, | |
| 712 Error* error) { | |
| 713 RLOG("%s: packed_relocations=%p, packed_relocations_size=%d\n", | |
| 714 __FUNCTION__, | |
| 715 arm_packed_relocations_, | |
| 716 arm_packed_relocations_size_); | |
| 717 | |
| 718 if (arm_packed_relocations_size_ == 0) | |
| 719 return true; | |
| 720 | |
| 721 // Allocate and then read the packed relocations section. | |
| 722 ScopedBuffer scoped_packed_data(arm_packed_relocations_size_); | |
| 723 uint8_t* packed_data = scoped_packed_data.Get(); | |
| 724 | |
| 725 FileDescriptor fd; | |
| 726 if (!fd.OpenReadOnly(full_path)) { | |
| 727 error->Format("Error opening file '%s'", full_path); | |
| 728 return false; | |
| 729 } | |
| 730 if (fd.SeekTo(arm_packed_relocations_) == -1) { | |
| 731 error->Format("Error seeking to %d in file '%s'", | |
| 732 arm_packed_relocations_, | |
| 733 full_path); | |
| 734 return false; | |
| 735 } | |
| 736 const ssize_t bytes = fd.Read(packed_data, arm_packed_relocations_size_); | |
| 737 if (bytes != arm_packed_relocations_size_) { | |
| 738 error->Format("Error reading %d bytes from file '%s'", | |
| 739 arm_packed_relocations_size_, | |
| 740 full_path); | |
| 741 return false; | |
| 742 } | |
| 743 fd.Close(); | |
| 744 | |
| 745 Leb128Decoder decoder(packed_data); | |
| 746 | |
| 747 // Check for the initial APR1 header. | |
| 748 if (decoder.Dequeue() != 'A' || decoder.Dequeue() != 'P' || | |
| 749 decoder.Dequeue() != 'R' || decoder.Dequeue() != '1') { | |
| 750 error->Format("Bad packed relocations ident, expected APR1"); | |
| 751 return false; | |
| 752 } | |
| 753 | |
| 754 // Find the count of pairs and the start address. | |
| 755 size_t pairs = decoder.Dequeue(); | |
| 756 const Elf32_Addr start_address = decoder.Dequeue(); | |
| 757 | |
| 758 // Emit initial R_ARM_RELATIVE relocation. | |
| 759 Elf32_Rel relocation = {start_address, R_ARM_RELATIVE}; | |
| 760 const ELF::Addr sym_addr = 0; | |
| 761 const bool resolved = false; | |
| 762 if (!ApplyRelReloc(&relocation, sym_addr, resolved, error)) | |
| 763 return false; | |
| 764 | |
| 765 size_t unpacked_count = 1; | |
| 766 | |
| 767 // Emit relocations for each count-delta pair. | |
| 768 while (pairs) { | |
| 769 size_t count = decoder.Dequeue(); | |
| 770 const size_t delta = decoder.Dequeue(); | |
| 771 | |
| 772 // Emit count R_ARM_RELATIVE relocations with delta offset. | |
| 773 while (count) { | |
| 774 relocation.r_offset += delta; | |
| 775 if (!ApplyRelReloc(&relocation, sym_addr, resolved, error)) | |
| 776 return false; | |
| 777 unpacked_count++; | |
| 778 count--; | |
| 779 } | |
| 780 pairs--; | |
| 781 } | |
| 782 | |
| 783 RLOG("%s: unpacked_count=%d\n", __FUNCTION__, unpacked_count); | |
| 784 return true; | |
| 785 } | |
| 786 | |
| 787 #endif // __arm__ | |
| 788 | |
| 644 #ifdef __mips__ | 789 #ifdef __mips__ |
| 645 bool ElfRelocations::RelocateMipsGot(const ElfSymbols* symbols, | 790 bool ElfRelocations::RelocateMipsGot(const ElfSymbols* symbols, |
| 646 SymbolResolver* resolver, | 791 SymbolResolver* resolver, |
| 647 Error* error) { | 792 Error* error) { |
| 648 if (!plt_got_) | 793 if (!plt_got_) |
| 649 return true; | 794 return true; |
| 650 | 795 |
| 651 // Handle the local GOT entries. | 796 // Handle the local GOT entries. |
| 652 // This mimics what the system linker does. | 797 // This mimics what the system linker does. |
| 653 // Note from the system linker: | 798 // Note from the system linker: |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 820 if (got_addr < src_addr || got_addr >= src_addr + size) | 965 if (got_addr < src_addr || got_addr >= src_addr + size) |
| 821 continue; | 966 continue; |
| 822 ELF::Addr* dst_ptr = reinterpret_cast<ELF::Addr*>(got_addr + dst_delta); | 967 ELF::Addr* dst_ptr = reinterpret_cast<ELF::Addr*>(got_addr + dst_delta); |
| 823 *dst_ptr += map_delta; | 968 *dst_ptr += map_delta; |
| 824 } | 969 } |
| 825 } | 970 } |
| 826 #endif | 971 #endif |
| 827 } | 972 } |
| 828 | 973 |
| 829 } // namespace crazy | 974 } // namespace crazy |
| OLD | NEW |