forked from OSchip/llvm-project
RuntimeDyldELF: don't create thunk if not needed
This patch doesn't create thunk for branch operation when following conditions are met: - Architecture is AArch64 - Relocation target is in the same object file - Relocation target is close enough to be encoded in immediate offset In such case we branch directly to the target instead of branching to thunk Differential revision: https://reviews.llvm.org/D28108 llvm-svn: 291431
This commit is contained in:
parent
3d57457298
commit
be2d68f774
|
@ -896,6 +896,49 @@ uint32_t RuntimeDyldELF::getMatchingLoRelocation(uint32_t RelType,
|
|||
return ELF::R_MIPS_NONE;
|
||||
}
|
||||
|
||||
// Sometimes we don't need to create thunk for a branch.
|
||||
// This typically happens when branch target is located
|
||||
// in the same object file. In such case target is either
|
||||
// a weak symbol or symbol in a different executable section.
|
||||
// This function checks if branch target is located in the
|
||||
// same object file and if distance between source and target
|
||||
// fits R_AARCH64_CALL26 relocation. If both conditions are
|
||||
// met, it emits direct jump to the target and returns true.
|
||||
// Otherwise false is returned and thunk is created.
|
||||
bool RuntimeDyldELF::resolveAArch64ShortBranch(
|
||||
unsigned SectionID, relocation_iterator RelI,
|
||||
const RelocationValueRef &Value) {
|
||||
uint64_t Address;
|
||||
if (Value.SymbolName) {
|
||||
auto Loc = GlobalSymbolTable.find(Value.SymbolName);
|
||||
|
||||
// Don't create direct branch for external symbols.
|
||||
if (Loc == GlobalSymbolTable.end())
|
||||
return false;
|
||||
|
||||
const auto &SymInfo = Loc->second;
|
||||
Address = reinterpret_cast<uint64_t>(
|
||||
Sections[SymInfo.getSectionID()].getLoadAddressWithOffset(
|
||||
SymInfo.getOffset()));
|
||||
} else {
|
||||
Address =
|
||||
reinterpret_cast<uint64_t>(Sections[Value.SectionID].getLoadAddress());
|
||||
}
|
||||
uint64_t Offset = RelI->getOffset();
|
||||
uint64_t SourceAddress = Sections[SectionID].getLoadAddressWithOffset(Offset);
|
||||
|
||||
// R_AARCH64_CALL26 requires immediate to be in range -2^27 <= imm < 2^27
|
||||
// If distance between source and target is out of range then we should
|
||||
// create thunk.
|
||||
if (!isInt<28>(Address + Value.Addend - SourceAddress))
|
||||
return false;
|
||||
|
||||
resolveRelocation(Sections[SectionID], Offset, Address, RelI->getType(),
|
||||
Value.Addend);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Expected<relocation_iterator>
|
||||
RuntimeDyldELF::processRelocationRef(
|
||||
unsigned SectionID, relocation_iterator RelI, const ObjectFile &O,
|
||||
|
@ -1003,7 +1046,7 @@ RuntimeDyldELF::processRelocationRef(
|
|||
(uint64_t)Section.getAddressWithOffset(i->second),
|
||||
RelType, 0);
|
||||
DEBUG(dbgs() << " Stub function found\n");
|
||||
} else {
|
||||
} else if (!resolveAArch64ShortBranch(SectionID, RelI, Value)) {
|
||||
// Create a new stub function.
|
||||
DEBUG(dbgs() << " Create a new stub function\n");
|
||||
Stubs[Value] = Section.getStubOffset();
|
||||
|
|
|
@ -40,6 +40,9 @@ class RuntimeDyldELF : public RuntimeDyldImpl {
|
|||
void resolveAArch64Relocation(const SectionEntry &Section, uint64_t Offset,
|
||||
uint64_t Value, uint32_t Type, int64_t Addend);
|
||||
|
||||
bool resolveAArch64ShortBranch(unsigned SectionID, relocation_iterator RelI,
|
||||
const RelocationValueRef &Value);
|
||||
|
||||
void resolveARMRelocation(const SectionEntry &Section, uint64_t Offset,
|
||||
uint32_t Value, uint32_t Type, int32_t Addend);
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# RUN: llvm-mc -triple=arm64-none-linux-gnu -filetype=obj -o %T/branch.o %s
|
||||
# RUN: llvm-rtdyld -triple=arm64-none-linux-gnu -verify -check=%s %T/branch.o
|
||||
|
||||
.globl _main
|
||||
.weak _label1
|
||||
|
||||
.section .text.1,"ax"
|
||||
_label1:
|
||||
nop
|
||||
_main:
|
||||
b _label1
|
||||
|
||||
## Branch 1 instruction back from _main
|
||||
# rtdyld-check: *{4}(_main) = 0x17ffffff
|
Loading…
Reference in New Issue