diff --git a/lld/ELF/Arch/ARM.cpp b/lld/ELF/Arch/ARM.cpp --- a/lld/ELF/Arch/ARM.cpp +++ b/lld/ELF/Arch/ARM.cpp @@ -42,6 +42,8 @@ uint64_t branchAddr, const Symbol &s) const override; uint32_t getThunkSectionSpacing() const override; bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; + bool inBranchRangeBeforePCBias(RelType type, uint64_t src, + uint64_t dst) const override; void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override; }; } // namespace @@ -375,6 +377,21 @@ return distance <= range; } +bool ARM::inBranchRangeBeforePCBias(RelType type, uint64_t src, + uint64_t dst) const { + switch (type) { + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + case R_ARM_THM_CALL: + dst += 4; + break; + default: + dst += 8; + break; + } + return inBranchRange(type, src, dst); +} + void ARM::relocateOne(uint8_t *loc, RelType type, uint64_t val) const { switch (type) { case R_ARM_ABS32: diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1770,7 +1770,8 @@ for (Thunk *t : *thunkVec) if (isThunkSectionCompatible(isec, t->getThunkTargetSym()->section) && t->isCompatibleWith(*isec, rel) && - target->inBranchRange(rel.type, src, t->getThunkTargetSym()->getVA())) + target->inBranchRangeBeforePCBias( + rel.type, src, t->getThunkTargetSym()->getVA(rel.addend))) return std::make_pair(t, false); // No existing compatible Thunk in range, create a new one @@ -1785,7 +1786,8 @@ // relocation back to its original non-Thunk target. bool ThunkCreator::normalizeExistingThunk(Relocation &rel, uint64_t src) { if (Thunk *t = thunks.lookup(rel.sym)) { - if (target->inBranchRange(rel.type, src, rel.sym->getVA())) + if (target->inBranchRangeBeforePCBias(rel.type, src, + rel.sym->getVA(rel.addend))) return true; rel.sym = &t->destination; if (rel.sym->isInPlt()) diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -73,10 +73,18 @@ virtual bool adjustPrologueForCrossSplitStack(uint8_t *loc, uint8_t *end, uint8_t stOther) const; - // Return true if we can reach dst from src with RelType type. + // Return true if we can reach dst from src with RelType type. PC-bias + // compensation has been added to dst. virtual bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const; + // PC-bias compensation has not been added to dst. This is identical to + // inBranchRange on all targets except ARM. + virtual bool inBranchRangeBeforePCBias(RelType type, uint64_t src, + uint64_t dst) const { + return inBranchRange(type, src, dst); + } + virtual void relocateOne(uint8_t *loc, RelType type, uint64_t val) const = 0; virtual ~TargetInfo();