Chromium Code Reviews| Index: tools/relocation_packer/src/elf_file.cc |
| diff --git a/tools/relocation_packer/src/elf_file.cc b/tools/relocation_packer/src/elf_file.cc |
| index 8f9b6b7e9e8ad29e69f972852736c595f18cc3a3..c874713396287af513727d90e641587166088a4a 100644 |
| --- a/tools/relocation_packer/src/elf_file.cc |
| +++ b/tools/relocation_packer/src/elf_file.cc |
| @@ -204,10 +204,12 @@ bool ElfFile::Load() { |
| } |
| // Note special sections as we encounter them. |
| - if (name == ".rel.dyn" || name == ".rela.dyn") { |
| + if ((name == ".rel.dyn" || name == ".rela.dyn") && |
| + section_header->sh_size > 0) { |
| found_relocations_section = section; |
| } |
| - if (name == ".android.rel.dyn" || name == ".android.rela.dyn") { |
| + if ((name == ".android.rel.dyn" || name == ".android.rela.dyn") && |
| + section_header->sh_size > 0) { |
| found_android_relocations_section = section; |
| } |
| if (section_header->sh_offset == dynamic_program_header->p_offset) { |
| @@ -231,17 +233,17 @@ bool ElfFile::Load() { |
| // Loading failed if we did not find the required special sections. |
| if (!found_relocations_section) { |
| - LOG(ERROR) << "Missing .rel.dyn or .rela.dyn section"; |
| + LOG(ERROR) << "Missing or empty .rel.dyn or .rela.dyn section"; |
| return false; |
| } |
| - if (!found_dynamic_section) { |
| - LOG(ERROR) << "Missing .dynamic section"; |
| + if (!found_android_relocations_section) { |
| + LOG(ERROR) << "Missing or empty .android.rel.dyn or .android.rela.dyn " |
| + << "section (to fix, run with --help and follow the " |
| + << "pre-packing instructions)"; |
| return false; |
| } |
| - if (!found_android_relocations_section) { |
| - LOG(ERROR) << "Missing .android.rel.dyn or .android.rela.dyn section " |
| - << "(to fix, run with --help and follow the pre-packing " |
| - << "instructions)"; |
| + if (!found_dynamic_section) { |
| + LOG(ERROR) << "Missing .dynamic section"; |
| return false; |
| } |
| @@ -686,14 +688,52 @@ void RemoveDynamicEntry(ELF::Sword tag, |
| CHECK(dynamics->at(dynamics->size() - 1).d_tag == DT_NULL); |
| } |
| -// Apply relative relocations to the file data to which they refer. |
| -// This relocates data into the area it will occupy after the hole in |
| +// Adjust a relocation. For a relocation without addend, we find its target |
| +// in the section and adjust that. For a relocation with addend, the target |
| +// is the relocation addend, and the section data at the target is zero. |
| +template <typename Rel> |
| +void AdjustRelocation(ssize_t index, |
|
rmcilroy
2014/08/04 12:12:50
AdjustRelocationTarget?
|
| + ELF::Addr hole_start, |
| + ssize_t hole_size, |
| + Rel* relocation, |
| + ELF::Off* target); |
| + |
| +template <> |
| +void AdjustRelocation<ELF::Rel>(ssize_t index, |
| + ELF::Addr hole_start, |
| + ssize_t hole_size, |
| + ELF::Rel* relocation, |
| + ELF::Off* target) { |
| + // Adjust the target if after the hole start. |
| + if (*target > hole_start) { |
| + *target += hole_size; |
| + VLOG(1) << "relocation[" << index << "] target adjusted to " << *target; |
| + } |
| +} |
| + |
| +template <> |
| +void AdjustRelocation<ELF::Rela>(ssize_t index, |
| + ELF::Addr hole_start, |
| + ssize_t hole_size, |
| + ELF::Rela* relocation, |
| + ELF::Off* target) { |
| + // The relocation's target is the addend. Adjust if after the hole start. |
| + if (relocation->r_addend > hole_start) { |
| + relocation->r_addend += hole_size; |
| + VLOG(1) << "relocation[" |
| + << index << "] addend adjusted to " << relocation->r_addend; |
| + } |
| +} |
| + |
| +// For relative relocations without addends, adjust the file data to which |
| +// they refer. For relative relocations with addends, adjust the addends. |
| +// This translates data into the area it will occupy after the hole in |
| // the dynamic relocations is added or removed. |
| template <typename Rel> |
| void AdjustRelocationTargets(Elf* elf, |
| ELF::Off hole_start, |
| ssize_t hole_size, |
| - const std::vector<Rel>& relocations) { |
| + std::vector<Rel>* relocations) { |
| Elf_Scn* section = NULL; |
| while ((section = elf_nextscn(elf, section)) != NULL) { |
| const ELF::Shdr* section_header = ELF::getshdr(section); |
| @@ -712,40 +752,32 @@ void AdjustRelocationTargets(Elf* elf, |
| const ELF::Addr section_start = section_header->sh_addr; |
| const ELF::Addr section_end = section_start + section_header->sh_size; |
| - // Create a copy-on-write pointer to the section's data. |
| - uint8_t* area = reinterpret_cast<uint8_t*>(data->d_buf); |
| + // Create a copy of the section's data. |
| + uint8_t* area = new uint8_t[data->d_size]; |
| + memcpy(area, data->d_buf, data->d_size); |
| - for (size_t i = 0; i < relocations.size(); ++i) { |
| - const Rel* relocation = &relocations[i]; |
| + for (size_t i = 0; i < relocations->size(); ++i) { |
| + Rel* relocation = &relocations->at(i); |
| CHECK(ELF_R_TYPE(relocation->r_info) == ELF::kRelativeRelocationCode); |
| // See if this relocation points into the current section. |
| if (relocation->r_offset >= section_start && |
| relocation->r_offset < section_end) { |
| + // The relocation's target is what it points to in area. |
| + // For relocations without addend, this is what we adjust; for |
| + // relocations with addend, we leave this (it will be zero) |
| + // and instead adjust the addend. |
| ELF::Addr byte_offset = relocation->r_offset - section_start; |
| ELF::Off* target = reinterpret_cast<ELF::Off*>(area + byte_offset); |
| - |
| - // Is the relocation's target after the hole's start? |
| - if (*target > hole_start) { |
| - // Copy on first write. Recompute target to point into the newly |
| - // allocated buffer. |
| - if (area == data->d_buf) { |
| - area = new uint8_t[data->d_size]; |
| - memcpy(area, data->d_buf, data->d_size); |
| - target = reinterpret_cast<ELF::Off*>(area + byte_offset); |
| - } |
| - |
| - *target += hole_size; |
| - VLOG(1) << "relocation[" << i << "] target adjusted to " << *target; |
| - } |
| + AdjustRelocation<Rel>(i, hole_start, hole_size, relocation, target); |
| } |
| } |
| - // If we applied any relocation to this section, write it back. |
| - if (area != data->d_buf) { |
| + // If we altered the data for this section, write it back. |
| + if (memcmp(area, data->d_buf, data->d_size)) { |
| RewriteSectionData(data, area, data->d_size); |
| - delete [] area; |
| } |
| + delete [] area; |
| } |
| } |
| @@ -884,17 +916,31 @@ bool ElfFile::PackTypedRelocations(const std::vector<Rel>& relocations, |
| return false; |
| } |
| - // Add null relocations to other_relocations to preserve alignment. |
| - const size_t padding_bytes = unaligned_hole_size - hole_size; |
| + // Find the padding needed in other_relocations to preserve alignment. |
| + // Ensure that we never completely empty the real relocations section. |
| + size_t padding_bytes = unaligned_hole_size - hole_size; |
| + if (padding_bytes == 0 && other_relocations.size() == 0) { |
| + do { |
| + padding_bytes += sizeof(relative_relocations[0]); |
| + } while (padding_bytes % kPreserveAlignment); |
| + } |
| CHECK(padding_bytes % sizeof(other_relocations[0]) == 0); |
| - const size_t required = padding_bytes / sizeof(other_relocations[0]); |
| - PadRelocations(required, &other_relocations); |
| - LOG(INFO) << "Alignment pad : " << required << " relocations"; |
| + const size_t padding = padding_bytes / sizeof(other_relocations[0]); |
| + |
| + // Padding may have removed any packing benefit. |
| + if (padding >= relative_relocations.size()) { |
| + LOG(INFO) << "Too few relative relocations to pack after padding"; |
| + return false; |
| + } |
| + |
| + // Add null relocations to other_relocations to preserve alignment. |
| + PadRelocations<Rel>(padding, &other_relocations); |
| + LOG(INFO) << "Alignment pad : " << padding << " relocations"; |
| // Apply relocations to all relative data to relocate it into the |
| // area it will occupy once the hole in the dynamic relocations is removed. |
| AdjustRelocationTargets<Rel>( |
| - elf_, hole_start, -hole_size, relative_relocations); |
| + elf_, hole_start, -hole_size, &relative_relocations); |
| // Relocate the relocations. |
| AdjustRelocations<Rel>(hole_start, -hole_size, &relative_relocations); |
| AdjustRelocations<Rel>(hole_start, -hole_size, &other_relocations); |
| @@ -902,8 +948,8 @@ bool ElfFile::PackTypedRelocations(const std::vector<Rel>& relocations, |
| // If padding, add NONE-type relocations to other_relocations to make it |
| // the same size as the the original relocations we read in. This makes |
| // the ResizeSection() below a no-op. |
| - const size_t required = relocations.size() - other_relocations.size(); |
| - PadRelocations(required, &other_relocations); |
| + const size_t padding = relocations.size() - other_relocations.size(); |
| + PadRelocations<Rel>(padding, &other_relocations); |
| } |
| // Pack relative relocations. |
| @@ -1081,7 +1127,7 @@ bool ElfFile::UnpackTypedRelocations(const std::vector<uint8_t>& packed, |
| // Apply relocations to all relative data to relocate it into the |
| // area it will occupy once the hole in dynamic relocations is opened. |
| AdjustRelocationTargets<Rel>( |
| - elf_, hole_start, hole_size, relative_relocations); |
| + elf_, hole_start, hole_size, &relative_relocations); |
| // Relocate the relocations. |
| AdjustRelocations<Rel>(hole_start, hole_size, &relative_relocations); |
| AdjustRelocations<Rel>(hole_start, hole_size, &other_relocations); |