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>