From 77f91c6d99c25fce4fbf9704aa6f7232fb624ff4 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 15 Oct 2015 13:26:03 -0700 Subject: [PATCH] Fix R_AARCH64_ABS/PREL relocations According to specification arm64 relocations should not use *reloc value. See http://infocenter.arm.com/help/topic/com.arm.doc.ihi0056b/IHI0056B_aaelf64.pdf section 4.6.5 Bug: http://b/24977219 Bug: http://b/24527155 Change-Id: I3813255771f408ba957963c6ad56ed08e5110d83 --- linker/linker.cpp | 52 ++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/linker/linker.cpp b/linker/linker.cpp index 406cdee1a..50fbb0b79 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -2165,24 +2165,23 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r count_relocation(kRelocAbsolute); MARK(rel->r_offset); TRACE_TYPE(RELO, "RELO ABS64 %16llx <- %16llx %s\n", - reloc, (sym_addr + addend), sym_name); - *reinterpret_cast(reloc) += (sym_addr + addend); + reloc, sym_addr + addend, sym_name); + *reinterpret_cast(reloc) = sym_addr + addend; break; case R_AARCH64_ABS32: count_relocation(kRelocAbsolute); MARK(rel->r_offset); TRACE_TYPE(RELO, "RELO ABS32 %16llx <- %16llx %s\n", - reloc, (sym_addr + addend), sym_name); + reloc, sym_addr + addend, sym_name); { - const ElfW(Addr) reloc_value = *reinterpret_cast(reloc); const ElfW(Addr) min_value = static_cast(INT32_MIN); const ElfW(Addr) max_value = static_cast(UINT32_MAX); - if ((min_value <= (reloc_value + (sym_addr + addend))) && - ((reloc_value + (sym_addr + addend)) <= max_value)) { - *reinterpret_cast(reloc) += (sym_addr + addend); + if ((min_value <= (sym_addr + addend)) && + ((sym_addr + addend) <= max_value)) { + *reinterpret_cast(reloc) = sym_addr + addend; } else { DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", - (reloc_value + (sym_addr + addend)), min_value, max_value); + sym_addr + addend, min_value, max_value); return false; } } @@ -2191,17 +2190,16 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r count_relocation(kRelocAbsolute); MARK(rel->r_offset); TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n", - reloc, (sym_addr + addend), sym_name); + reloc, sym_addr + addend, sym_name); { - const ElfW(Addr) reloc_value = *reinterpret_cast(reloc); const ElfW(Addr) min_value = static_cast(INT16_MIN); const ElfW(Addr) max_value = static_cast(UINT16_MAX); - if ((min_value <= (reloc_value + (sym_addr + addend))) && - ((reloc_value + (sym_addr + addend)) <= max_value)) { - *reinterpret_cast(reloc) += (sym_addr + addend); + if ((min_value <= (sym_addr + addend)) && + ((sym_addr + addend) <= max_value)) { + *reinterpret_cast(reloc) = (sym_addr + addend); } else { DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", - reloc_value + (sym_addr + addend), min_value, max_value); + sym_addr + addend, min_value, max_value); return false; } } @@ -2210,24 +2208,23 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r count_relocation(kRelocRelative); MARK(rel->r_offset); TRACE_TYPE(RELO, "RELO REL64 %16llx <- %16llx - %16llx %s\n", - reloc, (sym_addr + addend), rel->r_offset, sym_name); - *reinterpret_cast(reloc) += (sym_addr + addend) - rel->r_offset; + reloc, sym_addr + addend, rel->r_offset, sym_name); + *reinterpret_cast(reloc) = sym_addr + addend - rel->r_offset; break; case R_AARCH64_PREL32: count_relocation(kRelocRelative); MARK(rel->r_offset); TRACE_TYPE(RELO, "RELO REL32 %16llx <- %16llx - %16llx %s\n", - reloc, (sym_addr + addend), rel->r_offset, sym_name); + reloc, sym_addr + addend, rel->r_offset, sym_name); { - const ElfW(Addr) reloc_value = *reinterpret_cast(reloc); const ElfW(Addr) min_value = static_cast(INT32_MIN); const ElfW(Addr) max_value = static_cast(UINT32_MAX); - if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) && - ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) { - *reinterpret_cast(reloc) += ((sym_addr + addend) - rel->r_offset); + if ((min_value <= (sym_addr + addend - rel->r_offset)) && + ((sym_addr + addend - rel->r_offset) <= max_value)) { + *reinterpret_cast(reloc) = sym_addr + addend - rel->r_offset; } else { DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", - reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value); + sym_addr + addend - rel->r_offset, min_value, max_value); return false; } } @@ -2236,17 +2233,16 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r count_relocation(kRelocRelative); MARK(rel->r_offset); TRACE_TYPE(RELO, "RELO REL16 %16llx <- %16llx - %16llx %s\n", - reloc, (sym_addr + addend), rel->r_offset, sym_name); + reloc, sym_addr + addend, rel->r_offset, sym_name); { - const ElfW(Addr) reloc_value = *reinterpret_cast(reloc); const ElfW(Addr) min_value = static_cast(INT16_MIN); const ElfW(Addr) max_value = static_cast(UINT16_MAX); - if ((min_value <= (reloc_value + ((sym_addr + addend) - rel->r_offset))) && - ((reloc_value + ((sym_addr + addend) - rel->r_offset)) <= max_value)) { - *reinterpret_cast(reloc) += ((sym_addr + addend) - rel->r_offset); + if ((min_value <= (sym_addr + addend - rel->r_offset)) && + ((sym_addr + addend - rel->r_offset) <= max_value)) { + *reinterpret_cast(reloc) = sym_addr + addend - rel->r_offset; } else { DL_ERR("0x%016llx out of range 0x%016llx to 0x%016llx", - reloc_value + ((sym_addr + addend) - rel->r_offset), min_value, max_value); + sym_addr + addend - rel->r_offset, min_value, max_value); return false; } }