Start adding target abstractions.

This is just enough to get PLT working on 32 bit x86.

The idea behind using a virtual interface is that it should be easy to
convert any of the functions to template parameters if any turns out to be
performance critical.

llvm-svn: 248308
diff --git a/lld/ELF/CMakeLists.txt b/lld/ELF/CMakeLists.txt
index 12ae12a..3f98a9c 100644
--- a/lld/ELF/CMakeLists.txt
+++ b/lld/ELF/CMakeLists.txt
@@ -11,6 +11,7 @@
   OutputSections.cpp
   SymbolTable.cpp
   Symbols.cpp
+  Target.cpp
   Writer.cpp
 
   LINK_COMPONENTS
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 04dc1eb..e938e17 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -11,6 +11,7 @@
 #include "Error.h"
 #include "InputFiles.h"
 #include "OutputSections.h"
+#include "Target.h"
 
 #include "llvm/Support/raw_ostream.h"
 
@@ -114,12 +115,12 @@
         break;
       }
       case SymbolBody::SharedKind:
-        if (relocNeedsPLT(Type)) {
+        if (Target->relocNeedsPlt(Type)) {
           SymVA = PltSec.getEntryAddr(*Body);
-          Type = R_X86_64_PC32;
-        } else if (relocNeedsGOT(Type)) {
+          Type = Target->getPCRelReloc();
+        } else if (Target->relocNeedsGot(Type)) {
           SymVA = GotSec.getEntryAddr(*Body);
-          Type = R_X86_64_PC32;
+          Type = Target->getPCRelReloc();
         } else {
           continue;
         }
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 4640d98..014503b 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -10,6 +10,7 @@
 #include "OutputSections.h"
 #include "Config.h"
 #include "SymbolTable.h"
+#include "Target.h"
 
 using namespace llvm;
 using namespace llvm::object;
@@ -42,21 +43,11 @@
   uintptr_t Start = reinterpret_cast<uintptr_t>(Buf);
   ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpq *val(%rip)
   for (const SymbolBody *E : Entries) {
+    uint64_t GotEntryAddr = GotSec.getEntryAddr(*E);
     uintptr_t InstPos = reinterpret_cast<uintptr_t>(Buf);
-
-    memcpy(Buf, Jmp.data(), Jmp.size());
-    Buf += Jmp.size();
-
-    uintptr_t OffsetInPLT = (InstPos + 6) - Start;
-    intptr_t Delta = GotSec.getEntryAddr(*E) - (this->getVA() + OffsetInPLT);
-    assert(isInt<32>(Delta));
-    support::endian::write32le(Buf, Delta);
-    Buf += 4;
-
-    *Buf = 0x90; // nop
-    ++Buf;
-    *Buf = 0x90; // nop
-    ++Buf;
+    uint64_t PltEntryAddr = (InstPos - Start) + this->getVA();
+    Target->writePltEntry(Buf, GotEntryAddr, PltEntryAddr);
+    Buf += 8;
   }
 }
 
@@ -71,26 +62,6 @@
   return this->getVA() + B.getPltIndex() * EntrySize;
 }
 
-bool lld::elf2::relocNeedsPLT(uint32_t Type) {
-  switch (Type) {
-  default:
-    return false;
-  case R_X86_64_PLT32:
-    return true;
-  }
-}
-
-bool lld::elf2::relocNeedsGOT(uint32_t Type) {
-  if (relocNeedsPLT(Type))
-    return true;
-  switch (Type) {
-  default:
-    return false;
-  case R_X86_64_GOTPCREL:
-    return true;
-  }
-}
-
 template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
   const unsigned EntrySize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
   bool IsMips64EL = Relocs[0].C.getFile()->getObj()->isMips64EL();
@@ -104,7 +75,7 @@
     uint32_t SymIndex = RI.getSymbol(IsMips64EL);
     const SymbolBody *Body = C.getFile()->getSymbolBody(SymIndex);
     uint32_t Type = RI.getType(IsMips64EL);
-    if (relocNeedsGOT(Type)) {
+    if (Target->relocNeedsGot(Type)) {
       P->r_offset = GotSec.getEntryAddr(*Body);
       P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), R_X86_64_GLOB_DAT,
                           IsMips64EL);
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index d23d379..da25c75 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -29,9 +29,6 @@
 template <class ELFT> class ObjectFile;
 template <class ELFT> class DefinedRegular;
 
-bool relocNeedsPLT(uint32_t Type);
-bool relocNeedsGOT(uint32_t Type);
-
 template <class ELFT>
 typename llvm::object::ELFFile<ELFT>::uintX_t
 getSymVA(const DefinedRegular<ELFT> *DR);
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index 43b82d6..ffebf10 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -11,9 +11,11 @@
 #include "Config.h"
 #include "Error.h"
 #include "Symbols.h"
+#include "Target.h"
 
 using namespace llvm;
 using namespace llvm::object;
+using namespace llvm::ELF;
 
 using namespace lld;
 using namespace lld::elf2;
@@ -37,7 +39,11 @@
   addELFFile(cast<ELFFileBase>(FileP));
 }
 
-template <class ELFT> void SymbolTable::init() {
+template <class ELFT> void SymbolTable::init(uint16_t EMachine) {
+  if (EMachine == EM_X86_64)
+    Target.reset(new X86_64TargetInfo());
+  else
+    Target.reset(new X86TargetInfo());
   if (Config->Shared)
     return;
   EntrySym = new (Alloc) Undefined<ELFT>("_start", Undefined<ELFT>::Synthetic);
@@ -49,7 +55,7 @@
     if (!Old->isCompatibleWith(*File))
       error(Twine(Old->getName() + " is incompatible with " + File->getName()));
   } else {
-    init<ELFT>();
+    init<ELFT>(File->getEMachine());
   }
 
   if (auto *O = dyn_cast<ObjectFileBase>(File)) {
diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h
index be7c324..bd69290 100644
--- a/lld/ELF/SymbolTable.h
+++ b/lld/ELF/SymbolTable.h
@@ -68,7 +68,7 @@
   void addLazy(Lazy *New);
   void addMemberFile(Lazy *Body);
 
-  template <class ELFT> void init();
+  template <class ELFT> void init(uint16_t EMachine);
   template <class ELFT> void resolve(SymbolBody *Body);
 
   std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles;
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
new file mode 100644
index 0000000..a951a81
--- /dev/null
+++ b/lld/ELF/Target.cpp
@@ -0,0 +1,100 @@
+//===- Target.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Target.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ELF.h"
+
+using namespace llvm;
+using namespace llvm::ELF;
+
+namespace lld {
+namespace elf2 {
+
+std::unique_ptr<TargetInfo> Target;
+
+TargetInfo::~TargetInfo() {}
+
+X86TargetInfo::X86TargetInfo() { PCRelReloc = R_386_PC32; }
+
+void X86TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
+                                  uint64_t PltEntryAddr) const {
+  ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpl *val
+  memcpy(Buf, Jmp.data(), Jmp.size());
+  Buf += Jmp.size();
+
+  assert(isUInt<32>(GotEntryAddr));
+  support::endian::write32le(Buf, GotEntryAddr);
+  Buf += 4;
+
+  ArrayRef<uint8_t> Nops = {0x90, 0x90};
+  memcpy(Buf, Nops.data(), Nops.size());
+}
+
+bool X86TargetInfo::relocNeedsGot(uint32_t Type) const {
+  if (relocNeedsPlt(Type))
+    return true;
+  switch (Type) {
+  default:
+    return false;
+  case R_386_GOT32:
+    return true;
+  }
+}
+
+bool X86TargetInfo::relocNeedsPlt(uint32_t Type) const {
+  switch (Type) {
+  default:
+    return false;
+  case R_386_PLT32:
+    return true;
+  }
+}
+
+X86_64TargetInfo::X86_64TargetInfo() { PCRelReloc = R_X86_64_PC32; }
+
+void X86_64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
+                                     uint64_t PltEntryAddr) const {
+  ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpq *val(%rip)
+  memcpy(Buf, Jmp.data(), Jmp.size());
+  Buf += Jmp.size();
+
+  uintptr_t NextPC = PltEntryAddr + 6;
+  uintptr_t Delta = GotEntryAddr - NextPC;
+  assert(isInt<32>(Delta));
+  support::endian::write32le(Buf, Delta);
+  Buf += 4;
+
+  ArrayRef<uint8_t> Nops = {0x90, 0x90};
+  memcpy(Buf, Nops.data(), Nops.size());
+}
+
+bool X86_64TargetInfo::relocNeedsGot(uint32_t Type) const {
+  if (relocNeedsPlt(Type))
+    return true;
+  switch (Type) {
+  default:
+    return false;
+  case R_X86_64_GOTPCREL:
+    return true;
+  }
+}
+
+bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type) const {
+  switch (Type) {
+  default:
+    return false;
+  case R_X86_64_PLT32:
+    return true;
+  }
+}
+}
+}
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
new file mode 100644
index 0000000..d45e88c
--- /dev/null
+++ b/lld/ELF/Target.h
@@ -0,0 +1,54 @@
+//===- Target.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_TARGET_H
+#define LLD_ELF_TARGET_H
+
+#include <memory>
+
+namespace lld {
+namespace elf2 {
+class SymbolBody;
+
+class TargetInfo {
+public:
+  unsigned getPCRelReloc() const { return PCRelReloc; }
+  virtual void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
+                             uint64_t PltEntryAddr) const = 0;
+  virtual bool relocNeedsGot(uint32_t Type) const = 0;
+  virtual bool relocNeedsPlt(uint32_t Type) const = 0;
+  virtual ~TargetInfo();
+
+protected:
+  unsigned PCRelReloc;
+};
+
+class X86TargetInfo final : public TargetInfo {
+public:
+  X86TargetInfo();
+  void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
+                     uint64_t PltEntryAddr) const override;
+  bool relocNeedsGot(uint32_t Type) const override;
+  bool relocNeedsPlt(uint32_t Type) const override;
+};
+
+class X86_64TargetInfo final : public TargetInfo {
+public:
+  X86_64TargetInfo();
+  void writePltEntry(uint8_t *Buf, uint64_t GotEntryAddr,
+                     uint64_t PltEntryAddr) const override;
+  bool relocNeedsGot(uint32_t Type) const override;
+  bool relocNeedsPlt(uint32_t Type) const override;
+};
+
+extern std::unique_ptr<TargetInfo> Target;
+}
+}
+
+#endif
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 9ba202d..b467ef3 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -11,6 +11,7 @@
 #include "Config.h"
 #include "OutputSections.h"
 #include "SymbolTable.h"
+#include "Target.h"
 
 #include "llvm/Support/FileOutputBuffer.h"
 
@@ -256,12 +257,12 @@
     if (!S)
       continue;
     uint32_t Type = RI.getType(IsMips64EL);
-    if (relocNeedsPLT(Type)) {
+    if (Target->relocNeedsPlt(Type)) {
       if (Body->isInPlt())
         continue;
       PltSec.addEntry(Body);
     }
-    if (relocNeedsGOT(Type)) {
+    if (Target->relocNeedsGot(Type)) {
       if (Body->isInGot())
         continue;
       GotSec.addEntry(Body);