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 "elf_file.h" | 5 #include "elf_file.h" |
| 6 | 6 |
| 7 #include <stdlib.h> | 7 #include <stdlib.h> |
| 8 #include <sys/types.h> | 8 #include <sys/types.h> |
| 9 #include <unistd.h> | 9 #include <unistd.h> |
| 10 #include <string> | 10 #include <string> |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 197 | 197 |
| 198 // Note relocation section types. | 198 // Note relocation section types. |
| 199 if (section_header->sh_type == SHT_REL) { | 199 if (section_header->sh_type == SHT_REL) { |
| 200 has_rel_relocations = true; | 200 has_rel_relocations = true; |
| 201 } | 201 } |
| 202 if (section_header->sh_type == SHT_RELA) { | 202 if (section_header->sh_type == SHT_RELA) { |
| 203 has_rela_relocations = true; | 203 has_rela_relocations = true; |
| 204 } | 204 } |
| 205 | 205 |
| 206 // Note special sections as we encounter them. | 206 // Note special sections as we encounter them. |
| 207 if (name == ".rel.dyn" || name == ".rela.dyn") { | 207 if ((name == ".rel.dyn" || name == ".rela.dyn") && |
| 208 section_header->sh_size > 0) { | |
| 208 found_relocations_section = section; | 209 found_relocations_section = section; |
| 209 } | 210 } |
| 210 if (name == ".android.rel.dyn" || name == ".android.rela.dyn") { | 211 if ((name == ".android.rel.dyn" || name == ".android.rela.dyn") && |
| 212 section_header->sh_size > 0) { | |
| 211 found_android_relocations_section = section; | 213 found_android_relocations_section = section; |
| 212 } | 214 } |
| 213 if (section_header->sh_offset == dynamic_program_header->p_offset) { | 215 if (section_header->sh_offset == dynamic_program_header->p_offset) { |
| 214 found_dynamic_section = section; | 216 found_dynamic_section = section; |
| 215 } | 217 } |
| 216 | 218 |
| 217 // If we find a section named .debug*, set the debug warning flag. | 219 // If we find a section named .debug*, set the debug warning flag. |
| 218 if (std::string(name).find(".debug") == 0) { | 220 if (std::string(name).find(".debug") == 0) { |
| 219 has_debug_section = true; | 221 has_debug_section = true; |
| 220 } | 222 } |
| 221 | 223 |
| 222 // Ensure we preserve alignment, repeated later for the data block(s). | 224 // Ensure we preserve alignment, repeated later for the data block(s). |
| 223 CHECK(section_header->sh_addralign <= kPreserveAlignment); | 225 CHECK(section_header->sh_addralign <= kPreserveAlignment); |
| 224 | 226 |
| 225 Elf_Data* data = NULL; | 227 Elf_Data* data = NULL; |
| 226 while ((data = elf_getdata(section, data)) != NULL) { | 228 while ((data = elf_getdata(section, data)) != NULL) { |
| 227 CHECK(data->d_align <= kPreserveAlignment); | 229 CHECK(data->d_align <= kPreserveAlignment); |
| 228 VerboseLogSectionData(data); | 230 VerboseLogSectionData(data); |
| 229 } | 231 } |
| 230 } | 232 } |
| 231 | 233 |
| 232 // Loading failed if we did not find the required special sections. | 234 // Loading failed if we did not find the required special sections. |
| 233 if (!found_relocations_section) { | 235 if (!found_relocations_section) { |
| 234 LOG(ERROR) << "Missing .rel.dyn or .rela.dyn section"; | 236 LOG(ERROR) << "Missing or empty .rel.dyn or .rela.dyn section"; |
| 237 return false; | |
| 238 } | |
| 239 if (!found_android_relocations_section) { | |
| 240 LOG(ERROR) << "Missing or empty .android.rel.dyn or .android.rela.dyn " | |
| 241 << "section (to fix, run with --help and follow the " | |
| 242 << "pre-packing instructions)"; | |
| 235 return false; | 243 return false; |
| 236 } | 244 } |
| 237 if (!found_dynamic_section) { | 245 if (!found_dynamic_section) { |
| 238 LOG(ERROR) << "Missing .dynamic section"; | 246 LOG(ERROR) << "Missing .dynamic section"; |
| 239 return false; | 247 return false; |
| 240 } | 248 } |
| 241 if (!found_android_relocations_section) { | |
| 242 LOG(ERROR) << "Missing .android.rel.dyn or .android.rela.dyn section " | |
| 243 << "(to fix, run with --help and follow the pre-packing " | |
| 244 << "instructions)"; | |
| 245 return false; | |
| 246 } | |
| 247 | 249 |
| 248 // Loading failed if we could not identify the relocations type. | 250 // Loading failed if we could not identify the relocations type. |
| 249 if (!has_rel_relocations && !has_rela_relocations) { | 251 if (!has_rel_relocations && !has_rela_relocations) { |
| 250 LOG(ERROR) << "No relocations sections found"; | 252 LOG(ERROR) << "No relocations sections found"; |
| 251 return false; | 253 return false; |
| 252 } | 254 } |
| 253 if (has_rel_relocations && has_rela_relocations) { | 255 if (has_rel_relocations && has_rela_relocations) { |
| 254 LOG(ERROR) << "Multiple relocations sections with different types found, " | 256 LOG(ERROR) << "Multiple relocations sections with different types found, " |
| 255 << "not currently supported"; | 257 << "not currently supported"; |
| 256 return false; | 258 return false; |
| (...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 679 for (size_t i = slot; i < dynamics->size() - 1; ++i) { | 681 for (size_t i = slot; i < dynamics->size() - 1; ++i) { |
| 680 dynamics->at(i) = dynamics->at(i + 1); | 682 dynamics->at(i) = dynamics->at(i + 1); |
| 681 VLOG(1) << "dynamic[" << i | 683 VLOG(1) << "dynamic[" << i |
| 682 << "] overwritten with dynamic[" << i + 1 << "]"; | 684 << "] overwritten with dynamic[" << i + 1 << "]"; |
| 683 } | 685 } |
| 684 | 686 |
| 685 // Ensure that the end sentinel is still present. | 687 // Ensure that the end sentinel is still present. |
| 686 CHECK(dynamics->at(dynamics->size() - 1).d_tag == DT_NULL); | 688 CHECK(dynamics->at(dynamics->size() - 1).d_tag == DT_NULL); |
| 687 } | 689 } |
| 688 | 690 |
| 689 // Apply relative relocations to the file data to which they refer. | 691 // Adjust a relocation. For a relocation without addend, we find its target |
| 690 // This relocates data into the area it will occupy after the hole in | 692 // in the section and adjust that. For a relocation with addend, the target |
| 693 // is the relocation addend, and the section data at the target is zero. | |
| 694 template <typename Rel> | |
| 695 void AdjustRelocation(ssize_t index, | |
|
rmcilroy
2014/08/04 12:12:50
AdjustRelocationTarget?
| |
| 696 ELF::Addr hole_start, | |
| 697 ssize_t hole_size, | |
| 698 Rel* relocation, | |
| 699 ELF::Off* target); | |
| 700 | |
| 701 template <> | |
| 702 void AdjustRelocation<ELF::Rel>(ssize_t index, | |
| 703 ELF::Addr hole_start, | |
| 704 ssize_t hole_size, | |
| 705 ELF::Rel* relocation, | |
| 706 ELF::Off* target) { | |
| 707 // Adjust the target if after the hole start. | |
| 708 if (*target > hole_start) { | |
| 709 *target += hole_size; | |
| 710 VLOG(1) << "relocation[" << index << "] target adjusted to " << *target; | |
| 711 } | |
| 712 } | |
| 713 | |
| 714 template <> | |
| 715 void AdjustRelocation<ELF::Rela>(ssize_t index, | |
| 716 ELF::Addr hole_start, | |
| 717 ssize_t hole_size, | |
| 718 ELF::Rela* relocation, | |
| 719 ELF::Off* target) { | |
| 720 // The relocation's target is the addend. Adjust if after the hole start. | |
| 721 if (relocation->r_addend > hole_start) { | |
| 722 relocation->r_addend += hole_size; | |
| 723 VLOG(1) << "relocation[" | |
| 724 << index << "] addend adjusted to " << relocation->r_addend; | |
| 725 } | |
| 726 } | |
| 727 | |
| 728 // For relative relocations without addends, adjust the file data to which | |
| 729 // they refer. For relative relocations with addends, adjust the addends. | |
| 730 // This translates data into the area it will occupy after the hole in | |
| 691 // the dynamic relocations is added or removed. | 731 // the dynamic relocations is added or removed. |
| 692 template <typename Rel> | 732 template <typename Rel> |
| 693 void AdjustRelocationTargets(Elf* elf, | 733 void AdjustRelocationTargets(Elf* elf, |
| 694 ELF::Off hole_start, | 734 ELF::Off hole_start, |
| 695 ssize_t hole_size, | 735 ssize_t hole_size, |
| 696 const std::vector<Rel>& relocations) { | 736 std::vector<Rel>* relocations) { |
| 697 Elf_Scn* section = NULL; | 737 Elf_Scn* section = NULL; |
| 698 while ((section = elf_nextscn(elf, section)) != NULL) { | 738 while ((section = elf_nextscn(elf, section)) != NULL) { |
| 699 const ELF::Shdr* section_header = ELF::getshdr(section); | 739 const ELF::Shdr* section_header = ELF::getshdr(section); |
| 700 | 740 |
| 701 // Ignore sections that do not appear in a process memory image. | 741 // Ignore sections that do not appear in a process memory image. |
| 702 if (section_header->sh_addr == 0) | 742 if (section_header->sh_addr == 0) |
| 703 continue; | 743 continue; |
| 704 | 744 |
| 705 Elf_Data* data = GetSectionData(section); | 745 Elf_Data* data = GetSectionData(section); |
| 706 | 746 |
| 707 // Ignore sections with no effective data. | 747 // Ignore sections with no effective data. |
| 708 if (data->d_buf == NULL) | 748 if (data->d_buf == NULL) |
| 709 continue; | 749 continue; |
| 710 | 750 |
| 711 // Identify this section's start and end addresses. | 751 // Identify this section's start and end addresses. |
| 712 const ELF::Addr section_start = section_header->sh_addr; | 752 const ELF::Addr section_start = section_header->sh_addr; |
| 713 const ELF::Addr section_end = section_start + section_header->sh_size; | 753 const ELF::Addr section_end = section_start + section_header->sh_size; |
| 714 | 754 |
| 715 // Create a copy-on-write pointer to the section's data. | 755 // Create a copy of the section's data. |
| 716 uint8_t* area = reinterpret_cast<uint8_t*>(data->d_buf); | 756 uint8_t* area = new uint8_t[data->d_size]; |
| 757 memcpy(area, data->d_buf, data->d_size); | |
| 717 | 758 |
| 718 for (size_t i = 0; i < relocations.size(); ++i) { | 759 for (size_t i = 0; i < relocations->size(); ++i) { |
| 719 const Rel* relocation = &relocations[i]; | 760 Rel* relocation = &relocations->at(i); |
| 720 CHECK(ELF_R_TYPE(relocation->r_info) == ELF::kRelativeRelocationCode); | 761 CHECK(ELF_R_TYPE(relocation->r_info) == ELF::kRelativeRelocationCode); |
| 721 | 762 |
| 722 // See if this relocation points into the current section. | 763 // See if this relocation points into the current section. |
| 723 if (relocation->r_offset >= section_start && | 764 if (relocation->r_offset >= section_start && |
| 724 relocation->r_offset < section_end) { | 765 relocation->r_offset < section_end) { |
| 766 // The relocation's target is what it points to in area. | |
| 767 // For relocations without addend, this is what we adjust; for | |
| 768 // relocations with addend, we leave this (it will be zero) | |
| 769 // and instead adjust the addend. | |
| 725 ELF::Addr byte_offset = relocation->r_offset - section_start; | 770 ELF::Addr byte_offset = relocation->r_offset - section_start; |
| 726 ELF::Off* target = reinterpret_cast<ELF::Off*>(area + byte_offset); | 771 ELF::Off* target = reinterpret_cast<ELF::Off*>(area + byte_offset); |
| 727 | 772 AdjustRelocation<Rel>(i, hole_start, hole_size, relocation, target); |
| 728 // Is the relocation's target after the hole's start? | |
| 729 if (*target > hole_start) { | |
| 730 // Copy on first write. Recompute target to point into the newly | |
| 731 // allocated buffer. | |
| 732 if (area == data->d_buf) { | |
| 733 area = new uint8_t[data->d_size]; | |
| 734 memcpy(area, data->d_buf, data->d_size); | |
| 735 target = reinterpret_cast<ELF::Off*>(area + byte_offset); | |
| 736 } | |
| 737 | |
| 738 *target += hole_size; | |
| 739 VLOG(1) << "relocation[" << i << "] target adjusted to " << *target; | |
| 740 } | |
| 741 } | 773 } |
| 742 } | 774 } |
| 743 | 775 |
| 744 // If we applied any relocation to this section, write it back. | 776 // If we altered the data for this section, write it back. |
| 745 if (area != data->d_buf) { | 777 if (memcmp(area, data->d_buf, data->d_size)) { |
| 746 RewriteSectionData(data, area, data->d_size); | 778 RewriteSectionData(data, area, data->d_size); |
| 747 delete [] area; | |
| 748 } | 779 } |
| 780 delete [] area; | |
| 749 } | 781 } |
| 750 } | 782 } |
| 751 | 783 |
| 752 // Pad relocations with a given number of null relocations. | 784 // Pad relocations with a given number of null relocations. |
| 753 template <typename Rel> | 785 template <typename Rel> |
| 754 void PadRelocations(size_t count, std::vector<Rel>* relocations); | 786 void PadRelocations(size_t count, std::vector<Rel>* relocations); |
| 755 | 787 |
| 756 template <> | 788 template <> |
| 757 void PadRelocations<ELF::Rel>(size_t count, | 789 void PadRelocations<ELF::Rel>(size_t count, |
| 758 std::vector<ELF::Rel>* relocations) { | 790 std::vector<ELF::Rel>* relocations) { |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 877 while (hole_size % kPreserveAlignment) | 909 while (hole_size % kPreserveAlignment) |
| 878 hole_size -= sizeof(relative_relocations[0]); | 910 hole_size -= sizeof(relative_relocations[0]); |
| 879 LOG(INFO) << "Compaction : " << hole_size << " bytes"; | 911 LOG(INFO) << "Compaction : " << hole_size << " bytes"; |
| 880 | 912 |
| 881 // Adjusting for alignment may have removed any packing benefit. | 913 // Adjusting for alignment may have removed any packing benefit. |
| 882 if (hole_size == 0) { | 914 if (hole_size == 0) { |
| 883 LOG(INFO) << "Too few relative relocations to pack after alignment"; | 915 LOG(INFO) << "Too few relative relocations to pack after alignment"; |
| 884 return false; | 916 return false; |
| 885 } | 917 } |
| 886 | 918 |
| 919 // Find the padding needed in other_relocations to preserve alignment. | |
| 920 // Ensure that we never completely empty the real relocations section. | |
| 921 size_t padding_bytes = unaligned_hole_size - hole_size; | |
| 922 if (padding_bytes == 0 && other_relocations.size() == 0) { | |
| 923 do { | |
| 924 padding_bytes += sizeof(relative_relocations[0]); | |
| 925 } while (padding_bytes % kPreserveAlignment); | |
| 926 } | |
| 927 CHECK(padding_bytes % sizeof(other_relocations[0]) == 0); | |
| 928 const size_t padding = padding_bytes / sizeof(other_relocations[0]); | |
| 929 | |
| 930 // Padding may have removed any packing benefit. | |
| 931 if (padding >= relative_relocations.size()) { | |
| 932 LOG(INFO) << "Too few relative relocations to pack after padding"; | |
| 933 return false; | |
| 934 } | |
| 935 | |
| 887 // Add null relocations to other_relocations to preserve alignment. | 936 // Add null relocations to other_relocations to preserve alignment. |
| 888 const size_t padding_bytes = unaligned_hole_size - hole_size; | 937 PadRelocations<Rel>(padding, &other_relocations); |
| 889 CHECK(padding_bytes % sizeof(other_relocations[0]) == 0); | 938 LOG(INFO) << "Alignment pad : " << padding << " relocations"; |
| 890 const size_t required = padding_bytes / sizeof(other_relocations[0]); | |
| 891 PadRelocations(required, &other_relocations); | |
| 892 LOG(INFO) << "Alignment pad : " << required << " relocations"; | |
| 893 | 939 |
| 894 // Apply relocations to all relative data to relocate it into the | 940 // Apply relocations to all relative data to relocate it into the |
| 895 // area it will occupy once the hole in the dynamic relocations is removed. | 941 // area it will occupy once the hole in the dynamic relocations is removed. |
| 896 AdjustRelocationTargets<Rel>( | 942 AdjustRelocationTargets<Rel>( |
| 897 elf_, hole_start, -hole_size, relative_relocations); | 943 elf_, hole_start, -hole_size, &relative_relocations); |
| 898 // Relocate the relocations. | 944 // Relocate the relocations. |
| 899 AdjustRelocations<Rel>(hole_start, -hole_size, &relative_relocations); | 945 AdjustRelocations<Rel>(hole_start, -hole_size, &relative_relocations); |
| 900 AdjustRelocations<Rel>(hole_start, -hole_size, &other_relocations); | 946 AdjustRelocations<Rel>(hole_start, -hole_size, &other_relocations); |
| 901 } else { | 947 } else { |
| 902 // If padding, add NONE-type relocations to other_relocations to make it | 948 // If padding, add NONE-type relocations to other_relocations to make it |
| 903 // the same size as the the original relocations we read in. This makes | 949 // the same size as the the original relocations we read in. This makes |
| 904 // the ResizeSection() below a no-op. | 950 // the ResizeSection() below a no-op. |
| 905 const size_t required = relocations.size() - other_relocations.size(); | 951 const size_t padding = relocations.size() - other_relocations.size(); |
| 906 PadRelocations(required, &other_relocations); | 952 PadRelocations<Rel>(padding, &other_relocations); |
| 907 } | 953 } |
| 908 | 954 |
| 909 // Pack relative relocations. | 955 // Pack relative relocations. |
| 910 const size_t initial_bytes = | 956 const size_t initial_bytes = |
| 911 relative_relocations.size() * sizeof(relative_relocations[0]); | 957 relative_relocations.size() * sizeof(relative_relocations[0]); |
| 912 LOG(INFO) << "Unpacked relative: " << initial_bytes << " bytes"; | 958 LOG(INFO) << "Unpacked relative: " << initial_bytes << " bytes"; |
| 913 std::vector<uint8_t> packed; | 959 std::vector<uint8_t> packed; |
| 914 RelocationPacker packer; | 960 RelocationPacker packer; |
| 915 packer.PackRelativeRelocations(relative_relocations, &packed); | 961 packer.PackRelativeRelocations(relative_relocations, &packed); |
| 916 const void* packed_data = &packed[0]; | 962 const void* packed_data = &packed[0]; |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1074 ssize_t hole_size = | 1120 ssize_t hole_size = |
| 1075 relative_relocations.size() * sizeof(relative_relocations[0]); | 1121 relative_relocations.size() * sizeof(relative_relocations[0]); |
| 1076 | 1122 |
| 1077 // Adjust the hole size for the padding added to preserve alignment. | 1123 // Adjust the hole size for the padding added to preserve alignment. |
| 1078 hole_size -= padding * sizeof(other_relocations[0]); | 1124 hole_size -= padding * sizeof(other_relocations[0]); |
| 1079 LOG(INFO) << "Expansion : " << hole_size << " bytes"; | 1125 LOG(INFO) << "Expansion : " << hole_size << " bytes"; |
| 1080 | 1126 |
| 1081 // Apply relocations to all relative data to relocate it into the | 1127 // Apply relocations to all relative data to relocate it into the |
| 1082 // area it will occupy once the hole in dynamic relocations is opened. | 1128 // area it will occupy once the hole in dynamic relocations is opened. |
| 1083 AdjustRelocationTargets<Rel>( | 1129 AdjustRelocationTargets<Rel>( |
| 1084 elf_, hole_start, hole_size, relative_relocations); | 1130 elf_, hole_start, hole_size, &relative_relocations); |
| 1085 // Relocate the relocations. | 1131 // Relocate the relocations. |
| 1086 AdjustRelocations<Rel>(hole_start, hole_size, &relative_relocations); | 1132 AdjustRelocations<Rel>(hole_start, hole_size, &relative_relocations); |
| 1087 AdjustRelocations<Rel>(hole_start, hole_size, &other_relocations); | 1133 AdjustRelocations<Rel>(hole_start, hole_size, &other_relocations); |
| 1088 } | 1134 } |
| 1089 | 1135 |
| 1090 // Rewrite the current dynamic relocations section to be the relative | 1136 // Rewrite the current dynamic relocations section to be the relative |
| 1091 // relocations followed by other relocations. This is the usual order in | 1137 // relocations followed by other relocations. This is the usual order in |
| 1092 // which we find them after linking, so this action will normally put the | 1138 // which we find them after linking, so this action will normally put the |
| 1093 // entire dynamic relocations section back to its pre-split-and-packed state. | 1139 // entire dynamic relocations section back to its pre-split-and-packed state. |
| 1094 relocations.assign(relative_relocations.begin(), relative_relocations.end()); | 1140 relocations.assign(relative_relocations.begin(), relative_relocations.end()); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1140 | 1186 |
| 1141 // Clean up libelf, and truncate the output file to the number of bytes | 1187 // Clean up libelf, and truncate the output file to the number of bytes |
| 1142 // written by elf_update(). | 1188 // written by elf_update(). |
| 1143 elf_end(elf_); | 1189 elf_end(elf_); |
| 1144 elf_ = NULL; | 1190 elf_ = NULL; |
| 1145 const int truncate = ftruncate(fd_, file_bytes); | 1191 const int truncate = ftruncate(fd_, file_bytes); |
| 1146 CHECK(truncate == 0); | 1192 CHECK(truncate == 0); |
| 1147 } | 1193 } |
| 1148 | 1194 |
| 1149 } // namespace relocation_packer | 1195 } // namespace relocation_packer |
| OLD | NEW |