diff options
author | Dmitriy Ivanov <dimitry@google.com> | 2015-10-15 13:26:03 -0700 |
---|---|---|
committer | Dmitriy Ivanov <dimitry@google.com> | 2015-10-16 10:42:16 -0700 |
commit | 77f91c6d99c25fce4fbf9704aa6f7232fb624ff4 (patch) | |
tree | d10dc214af563d8081bcf72af4ef9e5bdbeb614a | |
parent | 198d13e8c25e69f7dbda3f5e1a3258b13fe8db5d (diff) | |
download | bionic-77f91c6d99c25fce4fbf9704aa6f7232fb624ff4.tar.gz |
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
-rw-r--r-- | linker/linker.cpp | 52 |
1 files 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<ElfW(Addr)*>(reloc) += (sym_addr + addend); + reloc, sym_addr + addend, sym_name); + *reinterpret_cast<ElfW(Addr)*>(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<ElfW(Addr)*>(reloc); const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN); const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT32_MAX); - if ((min_value <= (reloc_value + (sym_addr + addend))) && - ((reloc_value + (sym_addr + addend)) <= max_value)) { - *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend); + if ((min_value <= (sym_addr + addend)) && + ((sym_addr + addend) <= max_value)) { + *reinterpret_cast<ElfW(Addr)*>(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<ElfW(Addr)*>(reloc); const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN); const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(UINT16_MAX); - if ((min_value <= (reloc_value + (sym_addr + addend))) && - ((reloc_value + (sym_addr + addend)) <= max_value)) { - *reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr + addend); + if ((min_value <= (sym_addr + addend)) && + ((sym_addr + addend) <= max_value)) { + *reinterpret_cast<ElfW(Addr)*>(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<ElfW(Addr)*>(reloc) += (sym_addr + addend) - rel->r_offset; + reloc, sym_addr + addend, rel->r_offset, sym_name); + *reinterpret_cast<ElfW(Addr)*>(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<ElfW(Addr)*>(reloc); const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT32_MIN); const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(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<ElfW(Addr)*>(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<ElfW(Addr)*>(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<ElfW(Addr)*>(reloc); const ElfW(Addr) min_value = static_cast<ElfW(Addr)>(INT16_MIN); const ElfW(Addr) max_value = static_cast<ElfW(Addr)>(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<ElfW(Addr)*>(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<ElfW(Addr)*>(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; } } |