Remove broken arm64 PREL/ABS relocations

Specifically, remove:

 - R_AARCH64_ABS32
 - R_AARCH64_ABS16
 - R_AARCH64_PREL64
 - R_AARCH64_PREL32
 - R_AARCH64_PREL16

These relocations never currently appear in dynamic ELF files, and the
linker didn't handle them correctly. The AArch64 ELF ABI document
classifies them as "static relocations", which dynamic linkers don't need
to handle. (The document also classifies R_AARCH64_ABS64 as static,
though, and that relocation is common in DSOs. Perhaps static linkers
can't use R_AARCH64_GLOB_DAT to relocate data outside the GOT.)

Previously, for {ABS,PREL}{32,16}, Bionic always failed with an
out-of-range error. e.g. For {ABS,PREL}16, the value had to satisfy two
conditions:
 - be at least (Elf64_Addr)INT16_MIN, i.e. 0xffff_ffff_ffff_8000
 - be at most (Elf64_Addr)UINT16_MAX, i.e. 0xffff

The PREL relocations should have used sym_addr + addend - reloc, not
sym_addr + addend - rel->r_offset.

Bug: http://b/19197129
Test: bionic unit tests
Change-Id: I791da8ac471b3fb108cf77405c222f6e4bd34ae4
This commit is contained in:
Ryan Prichard 2019-10-16 16:11:58 -07:00
parent 2ab4e0f999
commit 9ef61a287a

View file

@ -3065,8 +3065,6 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
case R_GENERIC_TLSDESC:
#if defined(__aarch64__)
case R_AARCH64_ABS64:
case R_AARCH64_ABS32:
case R_AARCH64_ABS16:
#elif defined(__x86_64__)
case R_X86_64_32:
case R_X86_64_64:
@ -3304,86 +3302,6 @@ bool soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& r
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);
{
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 <= (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",
sym_addr + addend, min_value, max_value);
return false;
}
}
break;
case R_AARCH64_ABS16:
count_relocation(kRelocAbsolute);
MARK(rel->r_offset);
TRACE_TYPE(RELO, "RELO ABS16 %16llx <- %16llx %s\n",
reloc, sym_addr + addend, sym_name);
{
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 <= (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",
sym_addr + addend, min_value, max_value);
return false;
}
}
break;
case R_AARCH64_PREL64:
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;
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);
{
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 <= (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",
sym_addr + addend - rel->r_offset, min_value, max_value);
return false;
}
}
break;
case R_AARCH64_PREL16:
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);
{
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 <= (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",
sym_addr + addend - rel->r_offset, min_value, max_value);
return false;
}
}
break;
case R_AARCH64_COPY:
/*
* ET_EXEC is not supported so this should not happen.