diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-09 21:23:09 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-09 21:23:09 +0000 | 
| commit | 909545a822eef491158f831688066f0ec2866938 (patch) | |
| tree | 5b0bf0e81294007a9b462b21031b3df272c655c3 /lib/ExecutionEngine | |
| parent | 7e7b6700743285c0af506ac6299ddf82ebd434b9 (diff) | |
Diffstat (limited to 'lib/ExecutionEngine')
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp | 44 | ||||
| -rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h | 3 | 
2 files changed, 46 insertions, 1 deletions
| diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index a5a30fab5b69..8f6b1849169a 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -896,6 +896,48 @@ 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 = +        uint64_t(Sections[SymInfo.getSectionID()].getLoadAddressWithOffset( +            SymInfo.getOffset())); +  } else { +    Address = 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 +1045,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(); diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h index 796127ab92bd..d1867d091fe2 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -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); | 
