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 |