Merge "Fix unit tests, and extend for other architectures"

This commit is contained in:
Simon Baldwin 2015-05-27 16:42:37 +00:00 committed by Gerrit Code Review
commit 560aacee84
13 changed files with 113 additions and 10 deletions

View file

@ -95,3 +95,9 @@ $(eval $(call copy-test-library,elf_file_unittest_relocs_arm32.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_arm32_packed.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_arm64.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_arm64_packed.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_ia32.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_ia32_packed.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_x64.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_x64_packed.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_mips32.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_mips32_packed.so))

View file

@ -302,13 +302,75 @@ static void AdjustSectionHeadersForHole(Elf* elf,
}
}
// Helper for ResizeSection(). Adjust the offsets of any program headers
// that have offsets currently beyond the hole start.
// Helpers for ResizeSection(). On packing, reduce p_align for LOAD segments
// to 4kb if larger. On unpacking, restore p_align for LOAD segments if
// packing reduced it to 4kb. Return true if p_align was changed.
template <typename ELF>
static void AdjustProgramHeaderOffsets(typename ELF::Phdr* program_headers,
static bool ClampLoadSegmentAlignment(typename ELF::Phdr* program_header) {
CHECK(program_header->p_type == PT_LOAD);
// If large, reduce p_align for a LOAD segment to page size on packing.
if (program_header->p_align > kPageSize) {
program_header->p_align = kPageSize;
return true;
}
return false;
}
template <typename ELF>
static bool RestoreLoadSegmentAlignment(typename ELF::Phdr* program_headers,
size_t count,
typename ELF::Phdr* program_header) {
CHECK(program_header->p_type == PT_LOAD);
// If p_align was reduced on packing, restore it to its previous value
// on unpacking. We do this by searching for a different LOAD segment
// and setting p_align to that of the other LOAD segment found.
//
// Relies on the following observations:
// - a packable ELF executable has more than one LOAD segment;
// - before packing all LOAD segments have the same p_align;
// - on packing we reduce only one LOAD segment's p_align.
if (program_header->p_align == kPageSize) {
for (size_t i = 0; i < count; ++i) {
typename ELF::Phdr* other_header = &program_headers[i];
if (other_header->p_type == PT_LOAD && other_header != program_header) {
program_header->p_align = other_header->p_align;
return true;
}
}
LOG(WARNING) << "Cannot find a LOAD segment from which to restore p_align";
}
return false;
}
template <typename ELF>
static bool AdjustLoadSegmentAlignment(typename ELF::Phdr* program_headers,
size_t count,
typename ELF::Off hole_start,
typename ELF::Phdr* program_header,
ssize_t hole_size) {
CHECK(program_header->p_type == PT_LOAD);
bool status = false;
if (hole_size < 0) {
status = ClampLoadSegmentAlignment<ELF>(program_header);
} else if (hole_size > 0) {
status = RestoreLoadSegmentAlignment<ELF>(program_headers,
count,
program_header);
}
return status;
}
// Helper for ResizeSection(). Adjust the offsets of any program headers
// that have offsets currently beyond the hole start, and adjust the
// virtual and physical addrs (and perhaps alignment) of the others.
template <typename ELF>
static void AdjustProgramHeaderFields(typename ELF::Phdr* program_headers,
size_t count,
typename ELF::Off hole_start,
ssize_t hole_size) {
int alignment_changes = 0;
for (size_t i = 0; i < count; ++i) {
typename ELF::Phdr* program_header = &program_headers[i];
@ -327,9 +389,20 @@ static void AdjustProgramHeaderOffsets(typename ELF::Phdr* program_headers,
} else {
program_header->p_vaddr -= hole_size;
program_header->p_paddr -= hole_size;
if (program_header->p_align > kPageSize) {
program_header->p_align = kPageSize;
// If packing, clamp LOAD segment alignment to 4kb to prevent strip
// from adjusting it unnecessarily if run on a packed file. If
// unpacking, attempt to restore a reduced alignment to its previous
// value. Ensure that we do this on at most one LOAD segment.
if (program_header->p_type == PT_LOAD) {
alignment_changes += AdjustLoadSegmentAlignment<ELF>(program_headers,
count,
program_header,
hole_size);
LOG_IF(FATAL, alignment_changes > 1)
<< "Changed p_align on more than one LOAD segment";
}
VLOG(1) << "phdr[" << i
<< "] p_vaddr adjusted to "<< program_header->p_vaddr
<< "; p_paddr adjusted to "<< program_header->p_paddr
@ -383,10 +456,10 @@ static void RewriteProgramHeadersForHole(Elf* elf,
target_load_header->p_memsz += hole_size;
// Adjust the offsets and p_vaddrs
AdjustProgramHeaderOffsets<ELF>(elf_program_header,
program_header_count,
hole_start,
hole_size);
AdjustProgramHeaderFields<ELF>(elf_program_header,
program_header_count,
hole_start,
hole_size);
}
// Helper for ResizeSection(). Locate and return the dynamic section.

View file

@ -183,6 +183,18 @@ TEST(ElfFile, PackRelocationsArm64) {
RunPackRelocationsTestFor("arm64");
}
TEST(ElfFile, PackRelocationsMips32) {
RunPackRelocationsTestFor("mips32");
}
TEST(ElfFile, PackRelocationsIa32) {
RunPackRelocationsTestFor("ia32");
}
TEST(ElfFile, PackRelocationsX64) {
RunPackRelocationsTestFor("x64");
}
TEST(ElfFile, UnpackRelocationsArm32) {
RunUnpackRelocationsTestFor("arm32");
}
@ -191,4 +203,16 @@ TEST(ElfFile, UnpackRelocationsArm64) {
RunUnpackRelocationsTestFor("arm64");
}
TEST(ElfFile, UnpackRelocationsMips32) {
RunUnpackRelocationsTestFor("mips32");
}
TEST(ElfFile, UnpackRelocationsIa32) {
RunUnpackRelocationsTestFor("ia32");
}
TEST(ElfFile, UnpackRelocationsX64) {
RunUnpackRelocationsTestFor("x64");
}
} // namespace relocation_packer