[ELF] Introduce target specific inBranchRange() function

In preparation for range extension thunks introduce a function that will
check whether a branch identified by a relocation type at a source address
can reach a destination.

For targets where range extension thunks are not supported the function will
return true as it is not expected that branches are out of range. An
implementation has been provided for ARM.

Differential Revision: https://reviews.llvm.org/D34690

llvm-svn: 308188
This commit is contained in:
Peter Smith 2017-07-17 16:54:29 +00:00
parent 233d717ec1
commit a49442f323
3 changed files with 53 additions and 0 deletions

View File

@ -40,6 +40,8 @@ public:
void addPltHeaderSymbols(InputSectionBase *ISD) const override;
bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
const SymbolBody &S) const override;
bool inBranchRange(uint32_t RelocType, uint64_t Src,
uint64_t Dst) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
};
} // namespace
@ -218,6 +220,49 @@ bool ARM::needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
return false;
}
bool ARM::inBranchRange(uint32_t RelocType, uint64_t Src, uint64_t Dst) const {
uint64_t Range;
uint64_t InstrSize;
switch (RelocType) {
case R_ARM_PC24:
case R_ARM_PLT32:
case R_ARM_JUMP24:
case R_ARM_CALL:
Range = 0x2000000;
InstrSize = 4;
break;
case R_ARM_THM_JUMP19:
Range = 0x100000;
InstrSize = 2;
break;
case R_ARM_THM_JUMP24:
case R_ARM_THM_CALL:
Range = 0x1000000;
InstrSize = 2;
break;
default:
return true;
}
// PC at Src is 2 instructions ahead, immediate of branch is signed
if (Src > Dst)
Range -= 2 * InstrSize;
else
Range += InstrSize;
if ((Dst & 0x1) == 0)
// Destination is ARM, if ARM caller then Src is already 4-byte aligned.
// If Thumb Caller (BLX) the Src address has bottom 2 bits cleared to ensure
// destination will be 4 byte aligned.
Src &= ~0x3;
else
// Bit 0 == 1 denotes Thumb state, it is not part of the range
Dst &= ~0x1;
uint64_t Distance = (Src > Dst) ? Src - Dst : Dst - Src;
return Distance <= Range;
}
void ARM::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
switch (Type) {
case R_ARM_ABS32:

View File

@ -128,6 +128,11 @@ bool TargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
return false;
}
bool TargetInfo::inBranchRange(uint32_t RelocType, uint64_t Src,
uint64_t Dst) const {
return true;
}
void TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
writeGotPlt(Buf, S);
}

View File

@ -51,6 +51,9 @@ public:
// targeting S.
virtual bool needsThunk(RelExpr Expr, uint32_t RelocType,
const InputFile *File, const SymbolBody &S) const;
// Return true if we can reach Dst from Src with Relocation RelocType
virtual bool inBranchRange(uint32_t RelocType, uint64_t Src,
uint64_t Dst) const;
virtual RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
const uint8_t *Loc) const = 0;
virtual void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const = 0;