Fix unit tests, and extend for other architectures
On unpacking, reinstate any p_align values that packing reduced to page size. Ensures a round-trip pack and unpack is bit-equivalent to the original input. https://android-review.googlesource.com/#/c/148492/ Extend unit tests to include ia32, x64, and mips32. Recreate test data for arm32 and arm64. Generate new test data for ia32, x64, and mips32. Bug: http://b/20687795 Bug: http://b/18051137 Change-Id: Ifbca8e206ef447297ba4f19272b813702be27a35
This commit is contained in:
parent
4fc106d34b
commit
1011e1a402
|
@ -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))
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue