Commit 60319add authored by simonb@chromium.org's avatar simonb@chromium.org

Adjust addends rather than targets for RELA configurations.

Relocations with addend use the addend rather that the location pointed
to by the relocation as the target of the relocations.  For RELA
relocations, ignore the target and instead adjust the addend for the
hole being created in the file.  Change unit test data accordingly.

Ensure that sections we resize are never zero-length when we load the
Elf file, and that we never set either to zero-length on packing.

BUG=385553

Review URL: https://codereview.chromium.org/423393010

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287354 0039d316-1c4b-4281-b951-d872f2087c98
parent 9b092e56
...@@ -204,10 +204,12 @@ bool ElfFile::Load() { ...@@ -204,10 +204,12 @@ bool ElfFile::Load() {
} }
// Note special sections as we encounter them. // 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; 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; found_android_relocations_section = section;
} }
if (section_header->sh_offset == dynamic_program_header->p_offset) { if (section_header->sh_offset == dynamic_program_header->p_offset) {
...@@ -231,17 +233,17 @@ bool ElfFile::Load() { ...@@ -231,17 +233,17 @@ bool ElfFile::Load() {
// Loading failed if we did not find the required special sections. // Loading failed if we did not find the required special sections.
if (!found_relocations_section) { 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; return false;
} }
if (!found_dynamic_section) { if (!found_android_relocations_section) {
LOG(ERROR) << "Missing .dynamic 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; return false;
} }
if (!found_android_relocations_section) { if (!found_dynamic_section) {
LOG(ERROR) << "Missing .android.rel.dyn or .android.rela.dyn section " LOG(ERROR) << "Missing .dynamic section";
<< "(to fix, run with --help and follow the pre-packing "
<< "instructions)";
return false; return false;
} }
...@@ -686,14 +688,52 @@ void RemoveDynamicEntry(ELF::Sword tag, ...@@ -686,14 +688,52 @@ void RemoveDynamicEntry(ELF::Sword tag,
CHECK(dynamics->at(dynamics->size() - 1).d_tag == DT_NULL); CHECK(dynamics->at(dynamics->size() - 1).d_tag == DT_NULL);
} }
// Apply relative relocations to the file data to which they refer. // Adjust a relocation. For a relocation without addend, we find its target
// This relocates data into the area it will occupy after the hole in // 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,
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. // the dynamic relocations is added or removed.
template <typename Rel> template <typename Rel>
void AdjustRelocationTargets(Elf* elf, void AdjustRelocationTargets(Elf* elf,
ELF::Off hole_start, ELF::Off hole_start,
ssize_t hole_size, ssize_t hole_size,
const std::vector<Rel>& relocations) { std::vector<Rel>* relocations) {
Elf_Scn* section = NULL; Elf_Scn* section = NULL;
while ((section = elf_nextscn(elf, section)) != NULL) { while ((section = elf_nextscn(elf, section)) != NULL) {
const ELF::Shdr* section_header = ELF::getshdr(section); const ELF::Shdr* section_header = ELF::getshdr(section);
...@@ -712,40 +752,32 @@ void AdjustRelocationTargets(Elf* elf, ...@@ -712,40 +752,32 @@ void AdjustRelocationTargets(Elf* elf,
const ELF::Addr section_start = section_header->sh_addr; const ELF::Addr section_start = section_header->sh_addr;
const ELF::Addr section_end = section_start + section_header->sh_size; const ELF::Addr section_end = section_start + section_header->sh_size;
// Create a copy-on-write pointer to the section's data. // Create a copy of the section's data.
uint8_t* area = reinterpret_cast<uint8_t*>(data->d_buf); 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) { for (size_t i = 0; i < relocations->size(); ++i) {
const Rel* relocation = &relocations[i]; Rel* relocation = &relocations->at(i);
CHECK(ELF_R_TYPE(relocation->r_info) == ELF::kRelativeRelocationCode); CHECK(ELF_R_TYPE(relocation->r_info) == ELF::kRelativeRelocationCode);
// See if this relocation points into the current section. // See if this relocation points into the current section.
if (relocation->r_offset >= section_start && if (relocation->r_offset >= section_start &&
relocation->r_offset < section_end) { 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::Addr byte_offset = relocation->r_offset - section_start;
ELF::Off* target = reinterpret_cast<ELF::Off*>(area + byte_offset); ELF::Off* target = reinterpret_cast<ELF::Off*>(area + byte_offset);
AdjustRelocation<Rel>(i, hole_start, hole_size, relocation, target);
// 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;
}
} }
} }
// If we applied any relocation to this section, write it back. // If we altered the data for this section, write it back.
if (area != data->d_buf) { if (memcmp(area, data->d_buf, data->d_size)) {
RewriteSectionData(data, area, 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, ...@@ -884,17 +916,31 @@ bool ElfFile::PackTypedRelocations(const std::vector<Rel>& relocations,
return false; return false;
} }
// Add null relocations to other_relocations to preserve alignment. // Find the padding needed in other_relocations to preserve alignment.
const size_t padding_bytes = unaligned_hole_size - hole_size; // 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); CHECK(padding_bytes % sizeof(other_relocations[0]) == 0);
const size_t required = padding_bytes / sizeof(other_relocations[0]); const size_t padding = padding_bytes / sizeof(other_relocations[0]);
PadRelocations(required, &other_relocations);
LOG(INFO) << "Alignment pad : " << required << " relocations"; // 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 // Apply relocations to all relative data to relocate it into the
// area it will occupy once the hole in the dynamic relocations is removed. // area it will occupy once the hole in the dynamic relocations is removed.
AdjustRelocationTargets<Rel>( AdjustRelocationTargets<Rel>(
elf_, hole_start, -hole_size, relative_relocations); elf_, hole_start, -hole_size, &relative_relocations);
// Relocate the relocations. // Relocate the relocations.
AdjustRelocations<Rel>(hole_start, -hole_size, &relative_relocations); AdjustRelocations<Rel>(hole_start, -hole_size, &relative_relocations);
AdjustRelocations<Rel>(hole_start, -hole_size, &other_relocations); AdjustRelocations<Rel>(hole_start, -hole_size, &other_relocations);
...@@ -902,8 +948,8 @@ bool ElfFile::PackTypedRelocations(const std::vector<Rel>& 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 // 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 same size as the the original relocations we read in. This makes
// the ResizeSection() below a no-op. // the ResizeSection() below a no-op.
const size_t required = relocations.size() - other_relocations.size(); const size_t padding = relocations.size() - other_relocations.size();
PadRelocations(required, &other_relocations); PadRelocations<Rel>(padding, &other_relocations);
} }
// Pack relative relocations. // Pack relative relocations.
...@@ -1081,7 +1127,7 @@ bool ElfFile::UnpackTypedRelocations(const std::vector<uint8_t>& packed, ...@@ -1081,7 +1127,7 @@ bool ElfFile::UnpackTypedRelocations(const std::vector<uint8_t>& packed,
// Apply relocations to all relative data to relocate it into the // Apply relocations to all relative data to relocate it into the
// area it will occupy once the hole in dynamic relocations is opened. // area it will occupy once the hole in dynamic relocations is opened.
AdjustRelocationTargets<Rel>( AdjustRelocationTargets<Rel>(
elf_, hole_start, hole_size, relative_relocations); elf_, hole_start, hole_size, &relative_relocations);
// Relocate the relocations. // Relocate the relocations.
AdjustRelocations<Rel>(hole_start, hole_size, &relative_relocations); AdjustRelocations<Rel>(hole_start, hole_size, &relative_relocations);
AdjustRelocations<Rel>(hole_start, hole_size, &other_relocations); AdjustRelocations<Rel>(hole_start, hole_size, &other_relocations);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment