Recommit R274836 Add Thunk support framework for ARM and Mips
The TinyPtrVector of const Thunk<ELFT>* in InputSections.h can cause
build failures on certain compiler/library combinations when Thunk<ELFT>
is not a complete type or is an abstract class. Fixed by making Thunk<ELFT>
non Abstract.
type or is an abstract class
llvm-svn: 274863
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 58f3beb..51d18c3 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -29,6 +29,7 @@
#include "InputFiles.h"
#include "OutputSections.h"
#include "Symbols.h"
+#include "Thunks.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/ELF.h"
@@ -181,6 +182,9 @@
void writePltHeader(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
+ RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType,
+ const InputFile &File,
+ const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
};
@@ -197,8 +201,9 @@
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void writeThunk(uint8_t *Buf, uint64_t S) const override;
- bool needsThunk(uint32_t Type, const InputFile &File,
- const SymbolBody &S) const override;
+ RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType,
+ const InputFile &File,
+ const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
bool usesOnlyLowPageBits(uint32_t Type) const override;
};
@@ -248,9 +253,10 @@
bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; }
-bool TargetInfo::needsThunk(uint32_t Type, const InputFile &File,
- const SymbolBody &S) const {
- return false;
+RelExpr TargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
+ const InputFile &File,
+ const SymbolBody &S) const {
+ return Expr;
}
bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; }
@@ -1483,8 +1489,12 @@
// FIXME: currently B(S) assumed to be .got, this may not hold for all
// platforms.
return R_GOTONLY_PC;
+ case R_ARM_MOVW_PREL_NC:
+ case R_ARM_MOVT_PREL:
case R_ARM_PREL31:
case R_ARM_REL32:
+ case R_ARM_THM_MOVW_PREL_NC:
+ case R_ARM_THM_MOVT_PREL:
return R_PC;
}
}
@@ -1532,6 +1542,34 @@
write32le(Buf + 12, GotEntryAddr - L1 - 8);
}
+RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
+ const InputFile &File,
+ const SymbolBody &S) const {
+ // A state change from ARM to Thumb and vice versa must go through an
+ // interworking thunk if the relocation type is not R_ARM_CALL or
+ // R_ARM_THM_CALL.
+ switch (RelocType) {
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_JUMP24:
+ // Source is ARM, all PLT entries are ARM so no interworking required.
+ // Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
+ if (Expr == R_PC && ((S.getVA<ELF32LE>() & 1) == 1))
+ return R_THUNK_PC;
+ break;
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ // Source is Thumb, all PLT entries are ARM so interworking is required.
+ // Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
+ if (Expr == R_PLT_PC)
+ return R_THUNK_PLT_PC;
+ if ((S.getVA<ELF32LE>() & 1) == 0)
+ return R_THUNK_PC;
+ break;
+ }
+ return Expr;
+}
+
void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
switch (Type) {
@@ -1615,17 +1653,20 @@
((Val >> 1) & 0x07ff)); // imm11
break;
case R_ARM_MOVW_ABS_NC:
+ case R_ARM_MOVW_PREL_NC:
write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) |
(Val & 0x0fff));
break;
case R_ARM_MOVT_ABS:
- checkUInt<32>(Val, Type);
+ case R_ARM_MOVT_PREL:
+ checkInt<32>(Val, Type);
write32le(Loc, (read32le(Loc) & ~0x000f0fff) |
(((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff));
break;
case R_ARM_THM_MOVT_ABS:
+ case R_ARM_THM_MOVT_PREL:
// Encoding T1: A = imm4:i:imm3:imm8
- checkUInt<32>(Val, Type);
+ checkInt<32>(Val, Type);
write16le(Loc,
0xf2c0 | // opcode
((Val >> 17) & 0x0400) | // i
@@ -1636,6 +1677,7 @@
((Val >> 16) & 0x00ff)); // imm8
break;
case R_ARM_THM_MOVW_ABS_NC:
+ case R_ARM_THM_MOVW_PREL_NC:
// Encoding T3: A = imm4:i:imm3:imm8
write16le(Loc,
0xf240 | // opcode
@@ -1682,8 +1724,8 @@
((Hi & 0x003f) << 12) | // imm6
((Lo & 0x07ff) << 1)); // imm11:0
}
- case R_ARM_THM_JUMP24:
- case R_ARM_THM_CALL: {
+ case R_ARM_THM_CALL:
+ case R_ARM_THM_JUMP24: {
// Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0
// I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S)
// FIXME: I1 and I2 require v6T2ops
@@ -1698,12 +1740,16 @@
// ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and
// MOVT is in the range -32768 <= A < 32768
case R_ARM_MOVW_ABS_NC:
- case R_ARM_MOVT_ABS: {
+ case R_ARM_MOVT_ABS:
+ case R_ARM_MOVW_PREL_NC:
+ case R_ARM_MOVT_PREL: {
uint64_t Val = read32le(Buf) & 0x000f0fff;
return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff));
}
case R_ARM_THM_MOVW_ABS_NC:
- case R_ARM_THM_MOVT_ABS: {
+ case R_ARM_THM_MOVT_ABS:
+ case R_ARM_THM_MOVW_PREL_NC:
+ case R_ARM_THM_MOVT_PREL: {
// Encoding T3: A = imm4:i:imm3:imm8
uint16_t Hi = read16le(Buf);
uint16_t Lo = read16le(Buf + 2);
@@ -1720,7 +1766,6 @@
PageSize = 65536;
PltEntrySize = 16;
PltHeaderSize = 32;
- ThunkSize = 16;
CopyRel = R_MIPS_COPY;
PltRel = R_MIPS_JUMP_SLOT;
if (ELFT::Is64Bits) {
@@ -1887,28 +1932,31 @@
}
template <class ELFT>
-bool MipsTargetInfo<ELFT>::needsThunk(uint32_t Type, const InputFile &File,
- const SymbolBody &S) const {
+RelExpr MipsTargetInfo<ELFT>::getThunkExpr(RelExpr Expr, uint32_t Type,
+ const InputFile &File,
+ const SymbolBody &S) const {
// Any MIPS PIC code function is invoked with its address in register $t9.
// So if we have a branch instruction from non-PIC code to the PIC one
// we cannot make the jump directly and need to create a small stubs
// to save the target function address.
// See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
if (Type != R_MIPS_26)
- return false;
+ return Expr;
auto *F = dyn_cast<ELFFileBase<ELFT>>(&File);
if (!F)
- return false;
+ return Expr;
// If current file has PIC code, LA25 stub is not required.
if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
- return false;
+ return Expr;
auto *D = dyn_cast<DefinedRegular<ELFT>>(&S);
if (!D || !D->Section)
- return false;
+ return Expr;
// LA25 is required if target file has PIC code
// or target symbol is a PIC symbol.
- return (D->Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC) ||
- (D->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC;
+ const ELFFile<ELFT> &DefFile = D->Section->getFile()->getObj();
+ bool PicFile = DefFile.getHeader()->e_flags & EF_MIPS_PIC;
+ bool PicSym = (D->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC;
+ return (PicFile || PicSym) ? R_THUNK_ABS : Expr;
}
template <class ELFT>