[mach-o] refactor KindHandler into ArchHandler and simplify passes.
authorNick Kledzik <kledzik@apple.com>
Wed, 16 Jul 2014 19:49:02 +0000 (19:49 +0000)
committerNick Kledzik <kledzik@apple.com>
Wed, 16 Jul 2014 19:49:02 +0000 (19:49 +0000)
All architecture specific handling is now done in the appropriate
ArchHandler subclass.

The StubsPass and GOTPass have been simplified.  All architecture specific
variations in stubs are now encoded in a table which is vended by the
current ArchHandler.

llvm-svn: 213187

33 files changed:
lld/include/lld/ReaderWriter/MachOLinkingContext.h
lld/include/lld/ReaderWriter/Reader.h
lld/lib/Driver/DarwinLdDriver.cpp
lld/lib/ReaderWriter/MachO/ArchHandler.cpp [new file with mode: 0644]
lld/lib/ReaderWriter/MachO/ArchHandler.h [new file with mode: 0644]
lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp [new file with mode: 0644]
lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp [new file with mode: 0644]
lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp [new file with mode: 0644]
lld/lib/ReaderWriter/MachO/CMakeLists.txt
lld/lib/ReaderWriter/MachO/ExecutableAtoms.hpp
lld/lib/ReaderWriter/MachO/File.h
lld/lib/ReaderWriter/MachO/GOTPass.cpp
lld/lib/ReaderWriter/MachO/GOTPass.hpp
lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp
lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp
lld/lib/ReaderWriter/MachO/MachOPasses.h
lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp [deleted file]
lld/lib/ReaderWriter/MachO/ReferenceKinds.h [deleted file]
lld/lib/ReaderWriter/MachO/StubAtoms.hpp [deleted file]
lld/lib/ReaderWriter/MachO/StubAtoms_x86.hpp [deleted file]
lld/lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp [deleted file]
lld/lib/ReaderWriter/MachO/StubsPass.cpp
lld/lib/ReaderWriter/MachO/StubsPass.hpp [deleted file]
lld/test/darwin/hello-world.objtxt [deleted file]
lld/test/darwin/native-and-mach-o.objtxt
lld/test/mach-o/exe-offsets.yaml
lld/test/mach-o/exe-segment-overlap.yaml
lld/test/mach-o/hello-world-x86.yaml
lld/test/mach-o/hello-world-x86_64.yaml [new file with mode: 0644]
lld/test/mach-o/write-final-sections.yaml

index 99ae4e0..82c7821 100644 (file)
@@ -24,7 +24,7 @@ using llvm::MachO::HeaderFileType;
 namespace lld {
 
 namespace mach_o {
-class KindHandler; // defined in lib. this header is in include.
+class ArchHandler; 
 }
 
 class MachOLinkingContext : public LinkingContext {
@@ -68,7 +68,7 @@ public:
   virtual uint64_t pageZeroSize() const { return _pageZeroSize; }
   virtual uint64_t pageSize() const { return _pageSize; }
 
-  mach_o::KindHandler &kindHandler() const;
+  mach_o::ArchHandler &archHandler() const;
 
   HeaderFileType outputMachOType() const { return _outputMachOType; }
 
@@ -168,6 +168,15 @@ public:
 
   StringRef dyldPath() const { return "/usr/lib/dyld"; }
 
+  /// Stub creation Pass should be run.
+  bool needsStubsPass() const;
+
+  // GOT createion Pass should be run.
+  bool needsGOTPass() const;
+
+  /// Magic symbol name stubs will need to help lazy bind.
+  StringRef binderSymbolName() const;
+
   static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
   static Arch archFromName(StringRef archName);
   static StringRef nameFromArch(Arch arch);
@@ -211,7 +220,7 @@ private:
   bool _printAtoms;
   bool _testingLibResolution;
   StringRef _bundleLoader;
-  mutable std::unique_ptr<mach_o::KindHandler> _kindHandler;
+  mutable std::unique_ptr<mach_o::ArchHandler> _archHandler;
   mutable std::unique_ptr<Writer> _writer;
 };
 
index 0bfe2ad..694b302 100644 (file)
@@ -33,6 +33,7 @@ class File;
 class LinkingContext;
 class PECOFFLinkingContext;
 class TargetHandlerBase;
+class MachOLinkingContext;
 
 /// \brief An abstract class for reading object files, library files, and
 /// executable files.
@@ -122,7 +123,7 @@ public:
   void addSupportNativeObjects();
   void addSupportCOFFObjects(PECOFFLinkingContext &);
   void addSupportCOFFImportLibraries();
-  void addSupportMachOObjects(StringRef archName);
+  void addSupportMachOObjects(const MachOLinkingContext &);
   void addSupportELFObjects(bool atomizeStrings, TargetHandlerBase *handler);
   void addSupportELFDynamicSharedObjects(bool useShlibUndefines,
                                          TargetHandlerBase *handler);
index 27946a7..64a7fd4 100644 (file)
@@ -79,7 +79,7 @@ bool DarwinLdDriver::linkMachO(int argc, const char *argv[],
     return true;
 
   // Register possible input file parsers.
-  ctx.registry().addSupportMachOObjects(ctx.archName());
+  ctx.registry().addSupportMachOObjects(ctx);
   ctx.registry().addSupportArchives(ctx.logInputFiles());
   ctx.registry().addSupportNativeObjects();
   ctx.registry().addSupportYamlFiles();
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler.cpp
new file mode 100644 (file)
index 0000000..8dfafc6
--- /dev/null
@@ -0,0 +1,109 @@
+//===- lib/FileFormat/MachO/ArchHandler.cpp -------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+
+ArchHandler::ArchHandler() {
+}
+
+ArchHandler::~ArchHandler() {
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create(
+                                               MachOLinkingContext::Arch arch) {
+  switch (arch) {
+  case MachOLinkingContext::arch_x86_64:
+    return create_x86_64();
+  case MachOLinkingContext::arch_x86:
+    return create_x86();
+  case MachOLinkingContext::arch_armv6:
+  case MachOLinkingContext::arch_armv7:
+  case MachOLinkingContext::arch_armv7s:
+    return create_arm();
+  default:
+    llvm_unreachable("Unknown arch");
+  }
+}
+
+
+bool ArchHandler::isLazyPointer(const Reference &ref) {
+  // A lazy bind entry is needed for a lazy pointer.
+  const StubInfo &info = stubInfo();
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  if (ref.kindArch() != info.lazyPointerReferenceToFinal.arch)
+    return false;
+  return (ref.kindValue() == info.lazyPointerReferenceToFinal.kind);
+}
+
+
+ArchHandler::RelocPattern ArchHandler::relocPattern(const Relocation &reloc) {
+  assert((reloc.type & 0xFFF0) == 0);
+  uint16_t result = reloc.type;
+  if (reloc.scattered)
+    result |= rScattered;
+  if (reloc.pcRel)
+    result |= rPcRel;
+  if (reloc.isExtern)
+    result |= rExtern;
+  switch(reloc.length) {
+  case 0:
+    break;
+  case 1:
+    result |= rLength2;
+    break;
+  case 2:
+    result |= rLength4;
+    break;
+  case 3:
+    result |= rLength8;
+    break;
+  default:
+    llvm_unreachable("bad r_length");
+  }
+  return result;
+}
+
+int16_t ArchHandler::readS16(bool swap, const uint8_t *addr) {
+  return read16(swap, *reinterpret_cast<const uint16_t*>(addr));
+}
+
+int32_t ArchHandler::readS32(bool swap, const uint8_t *addr) {
+  return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
+}
+
+uint32_t ArchHandler::readU32(bool swap, const uint8_t *addr) {
+  return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
+}
+
+int64_t ArchHandler::readS64(bool swap, const uint8_t *addr) {
+  return read64(swap, *reinterpret_cast<const uint64_t*>(addr));
+}
+
+} // namespace mach_o
+} // namespace lld
+
+
+
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler.h b/lld/lib/ReaderWriter/MachO/ArchHandler.h
new file mode 100644 (file)
index 0000000..8a097a0
--- /dev/null
@@ -0,0 +1,175 @@
+//===- lib/FileFormat/MachO/ArchHandler.h ---------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MachONormalizedFile.h"
+
+#include "lld/Core/LLVM.h"
+#include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
+#include "llvm/ADT/Triple.h"
+
+#ifndef LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+#define LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
+
+namespace lld {
+namespace mach_o {
+
+///
+/// The ArchHandler class handles all architecture specific aspects of
+/// mach-o linking.
+///
+class ArchHandler {
+public:
+  virtual ~ArchHandler();
+  
+  /// There is no public interface to subclasses of ArchHandler, so this
+  /// is the only way to instantiate an ArchHandler.
+  static std::unique_ptr<ArchHandler> create(MachOLinkingContext::Arch arch);
+
+  /// Get (arch specific) kind strings used by Registry.
+  virtual const Registry::KindStrings *kindStrings() = 0;
+  
+  /// Convert mach-o Arch to Reference::KindArch. 
+  virtual Reference::KindArch kindArch() = 0;
+
+  /// Used by StubPass to update References to shared library functions
+  /// to be references to a stub.
+  virtual bool isCallSite(const Reference &) = 0;
+
+  /// Used by GOTPass to locate GOT References
+  virtual bool isGOTAccess(const Reference &, bool &canBypassGOT) {
+    return false;
+  }
+
+  /// Used by GOTPass to update GOT References
+  virtual void updateReferenceToGOT(const Reference *, bool targetIsNowGOT) {}
+
+  /// Used by normalizedFromAtoms() to know where to generated rebasing and 
+  /// binding info in final executables.
+  virtual bool isPointer(const Reference &) = 0;
+  
+  /// Used by normalizedFromAtoms() to know where to generated lazy binding 
+  /// info in final executables.
+  virtual bool isLazyPointer(const Reference &);
+
+  /// Returns true if the specified relocation is paired to the next relocation.
+  virtual bool isPairedReloc(const normalized::Relocation &) = 0;
+
+  /// Prototype for a helper function.  Given a sectionIndex and address, 
+  /// finds the atom and offset with that atom of that address. 
+  typedef std::function<std::error_code (uint32_t sectionIndex, uint64_t addr, 
+                        const lld::Atom **, Reference::Addend *)> 
+                        FindAtomBySectionAndAddress;
+  
+  /// Prototype for a helper function.  Given a symbolIndex, finds the atom
+  /// representing that symbol.
+  typedef std::function<std::error_code (uint32_t symbolIndex, 
+                        const lld::Atom **)> FindAtomBySymbolIndex;
+
+  /// Analyzes a relocation from a .o file and returns the info
+  /// (kind, target, addend) needed to instantiate a Reference.
+  /// Two helper functions are passed as parameters to find the target atom
+  /// given a symbol index or address.
+  virtual std::error_code 
+          getReferenceInfo(const normalized::Relocation &reloc,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool swap,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind, 
+                           const lld::Atom **target, 
+                           Reference::Addend *addend) = 0;
+
+  /// Analyzes a pair of relocations from a .o file and returns the info
+  /// (kind, target, addend) needed to instantiate a Reference.
+  /// Two helper functions are passed as parameters to find the target atom
+  /// given a symbol index or address.
+  virtual std::error_code 
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool swap,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind, 
+                           const lld::Atom **target, 
+                           Reference::Addend *addend) = 0;
+
+  /// Fixup an atom when generating a final linked binary.
+  virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
+                          Reference::KindValue kindValue, uint64_t addend,
+                          uint8_t *location, uint64_t fixupAddress,
+                          uint64_t targetAddress, uint64_t inAtomAddress) = 0;
+
+  struct ReferenceInfo {
+    Reference::KindArch arch;
+    uint16_t            kind;
+    uint32_t            offset;
+    int32_t             addend;
+  };
+
+  /// Table of architecture specific information for creating stubs.
+  struct StubInfo {
+    const char*     binderSymbolName;
+    ReferenceInfo   lazyPointerReferenceToHelper;
+    ReferenceInfo   lazyPointerReferenceToFinal;
+    ReferenceInfo   nonLazyPointerReferenceToBinder;
+    uint8_t         codeAlignment;
+    
+    uint32_t        stubSize;
+    uint8_t         stubBytes[16];
+    ReferenceInfo   stubReferenceToLP;
+    
+    uint32_t        stubHelperSize;
+    uint8_t         stubHelperBytes[16];
+    ReferenceInfo   stubHelperReferenceToImm;
+    ReferenceInfo   stubHelperReferenceToHelperCommon;
+    
+    uint32_t        stubHelperCommonSize;
+    uint8_t         stubHelperCommonBytes[36];
+    ReferenceInfo   stubHelperCommonReferenceToCache;
+    ReferenceInfo   stubHelperCommonReferenceToBinder;
+  };
+
+  virtual const StubInfo &stubInfo() = 0;
+
+protected:
+  ArchHandler();
+
+  static std::unique_ptr<mach_o::ArchHandler> create_x86_64();
+  static std::unique_ptr<mach_o::ArchHandler> create_x86();
+  static std::unique_ptr<mach_o::ArchHandler> create_arm();
+
+  // Handy way to pack mach-o r_type and other bit fields into one 16-bit value.
+  typedef uint16_t RelocPattern;
+  enum {
+    rScattered = 0x8000,
+    rPcRel     = 0x4000,
+    rExtern    = 0x2000,
+    rLength1   = 0x0000,
+    rLength2   = 0x0100,
+    rLength4   = 0x0200,
+    rLength8   = 0x0300
+  };
+  static RelocPattern relocPattern(const normalized::Relocation &reloc);
+
+  static int16_t  readS16(bool swap, const uint8_t *addr);
+  static int32_t  readS32(bool swap, const uint8_t *addr);
+  static uint32_t readU32(bool swap, const uint8_t *addr);
+  static int64_t  readS64(bool swap, const uint8_t *addr);
+};
+
+} // namespace mach_o
+} // namespace lld
+
+#endif // LLD_READER_WRITER_MACHO_ARCH_HANDLER_H
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_arm.cpp
new file mode 100644 (file)
index 0000000..a1e6b83
--- /dev/null
@@ -0,0 +1,662 @@
+//===- lib/FileFormat/MachO/ArchHandler_arm.cpp ---------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+class ArchHandler_arm : public ArchHandler {
+public:
+           ArchHandler_arm();
+  virtual ~ArchHandler_arm();
+
+  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+  Reference::KindArch kindArch() override { return Reference::KindArch::ARM; }
+
+  const ArchHandler::StubInfo &stubInfo() override;
+  bool isCallSite(const Reference &) override;
+  bool isPointer(const Reference &) override;
+  bool isPairedReloc(const normalized::Relocation &) override;
+  std::error_code getReferenceInfo(const normalized::Relocation &reloc,
+                                   const DefinedAtom *inAtom,
+                                   uint32_t offsetInAtom,
+                                   uint64_t fixupAddress, bool swap,
+                                   FindAtomBySectionAndAddress atomFromAddress,
+                                   FindAtomBySymbolIndex atomFromSymbolIndex,
+                                   Reference::KindValue *kind,
+                                   const lld::Atom **target,
+                                   Reference::Addend *addend) override;
+  std::error_code
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool swap,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) override;
+
+  void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
+                  Reference::KindValue kindValue, uint64_t addend,
+                  uint8_t *location, uint64_t fixupAddress,
+                  uint64_t targetAddress, uint64_t inAtomAddress) 
+                  override;
+
+private:
+  static const Registry::KindStrings _sKindStrings[];
+  static const StubInfo              _sStubInfoArmPIC;
+
+  enum : Reference::KindValue {
+    invalid,               /// for error condition
+
+    // Kinds found in mach-o .o files:
+    thumb_b22,             /// ex: bl _foo
+    thumb_movw,            /// ex: movw        r1, :lower16:_foo
+    thumb_movt,            /// ex: movt        r1, :lower16:_foo
+    thumb_movw_funcRel,    /// ex: movw        r1, :lower16:(_foo-(L1+4))
+    thumb_movt_funcRel,    /// ex: movt r1, :upper16:(_foo-(L1+4))
+    arm_b24,               /// ex: bl _foo
+    arm_movw,              /// ex: movw        r1, :lower16:_foo
+    arm_movt,              /// ex: movt        r1, :lower16:_foo
+    arm_movw_funcRel,      /// ex: movw        r1, :lower16:(_foo-(L1+4))
+    arm_movt_funcRel,      /// ex: movt r1, :upper16:(_foo-(L1+4))
+    pointer32,             /// ex: .long _foo
+    delta32,               /// ex: .long _foo - .
+
+    // Kinds introduced by Passes:
+    lazyPointer,           /// Location contains a lazy pointer.
+    lazyImmediateLocation, /// Location contains immediate value used in stub.
+  };
+
+  int32_t getDisplacementFromThumbBranch(uint32_t instruction);
+  int32_t getDisplacementFromArmBranch(uint32_t instruction);
+  uint16_t getWordFromThumbMov(uint32_t instruction);
+  uint16_t getWordFromArmMov(uint32_t instruction);
+  uint32_t clearThumbBit(uint32_t value, const Atom *target);
+  uint32_t setDisplacementInArmBranch(uint32_t instruction, int32_t disp);
+  
+  
+  const bool _swap;
+};
+
+//===----------------------------------------------------------------------===//
+//  ArchHandler_arm
+//===----------------------------------------------------------------------===//
+
+ArchHandler_arm::ArchHandler_arm() :
+  _swap(!MachOLinkingContext::isHostEndian(MachOLinkingContext::arch_armv7)) {}
+
+ArchHandler_arm::~ArchHandler_arm() { }
+
+const Registry::KindStrings ArchHandler_arm::_sKindStrings[] = {
+  LLD_KIND_STRING_ENTRY(thumb_b22),
+  LLD_KIND_STRING_ENTRY(thumb_movw),
+  LLD_KIND_STRING_ENTRY(thumb_movt),
+  LLD_KIND_STRING_ENTRY(thumb_movw_funcRel),
+  LLD_KIND_STRING_ENTRY(thumb_movt_funcRel),
+  LLD_KIND_STRING_ENTRY(arm_b24),
+  LLD_KIND_STRING_ENTRY(arm_movw),
+  LLD_KIND_STRING_ENTRY(arm_movt),
+  LLD_KIND_STRING_ENTRY(arm_movw_funcRel),
+  LLD_KIND_STRING_ENTRY(arm_movt_funcRel),
+  LLD_KIND_STRING_ENTRY(pointer32),
+  LLD_KIND_STRING_ENTRY(delta32),
+  LLD_KIND_STRING_ENTRY(lazyPointer),
+  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+  LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_arm::_sStubInfoArmPIC = {
+  "dyld_stub_binder",
+
+  // References in lazy pointer  
+  { Reference::KindArch::ARM, pointer32, 0, 0 },
+  { Reference::KindArch::ARM, lazyPointer, 0, 0 },
+  
+  // GOT pointer to dyld_stub_binder
+  { Reference::KindArch::ARM, pointer32, 0, 0 },
+
+  // arm code alignment 2^2
+  2, 
+  
+  // Stub size and code
+  16, 
+  { 0x04, 0xC0, 0x9F, 0xE5,       //   ldr ip, pc + 12
+    0x0C, 0xC0, 0x8F, 0xE0,       //  add ip, pc, ip
+    0x00, 0xF0, 0x9C, 0xE5,       //   ldr pc, [ip]
+    0x00, 0x00, 0x00, 0x00 },     //   .long L_foo$lazy_ptr - (L1$scv + 8)
+  { Reference::KindArch::ARM, delta32, 12, 0 },
+  
+  // Stub Helper size and code
+  12,
+  { 0x00, 0xC0, 0x9F, 0xE5,       // ldr   ip, [pc, #0]
+    0x00, 0x00, 0x00, 0xEA,       // b      _helperhelper
+    0x00, 0x00, 0x00, 0x00 },     // .long  lazy-info-offset
+  { Reference::KindArch::ARM, lazyImmediateLocation, 8, 0 },
+  { Reference::KindArch::ARM, arm_b24, 4, 0 },
+  
+  // Stub Helper-Common size and code
+  36,
+       { // push lazy-info-offset
+    0x04, 0xC0, 0x2D, 0xE5,       // str ip, [sp, #-4]!
+               // push address of dyld_mageLoaderCache
+    0x10, 0xC0, 0x9F, 0xE5,       // ldr       ip, L1
+    0x0C, 0xC0, 0x8F, 0xE0,       // add       ip, pc, ip
+    0x04, 0xC0, 0x2D, 0xE5,       // str ip, [sp, #-4]!
+               // jump through dyld_stub_binder
+    0x08, 0xC0, 0x9F, 0xE5,       // ldr       ip, L2
+    0x0C, 0xC0, 0x8F, 0xE0,       // add       ip, pc, ip
+    0x00, 0xF0, 0x9C, 0xE5,       // ldr       pc, [ip]
+    0x00, 0x00, 0x00, 0x00,       // L1: .long fFastStubGOTAtom - (helper+16)
+    0x00, 0x00, 0x00, 0x00 },     // L2: .long dyld_stub_binder - (helper+28)
+  { Reference::KindArch::ARM, delta32, 28, 0 },
+  { Reference::KindArch::ARM, delta32, 32, 0 }
+};
+
+const ArchHandler::StubInfo &ArchHandler_arm::stubInfo() {
+  // If multiple kinds of stubs are supported, select which StubInfo here.
+  return _sStubInfoArmPIC;
+}
+
+bool ArchHandler_arm::isCallSite(const Reference &ref) {
+  return (ref.kindValue() == thumb_b22) || (ref.kindValue() == arm_b24);
+}
+
+bool ArchHandler_arm::isPointer(const Reference &ref) {
+  return (ref.kindValue() == pointer32);
+}
+
+bool ArchHandler_arm::isPairedReloc(const Relocation &reloc) {
+  switch (reloc.type) {
+  case ARM_RELOC_SECTDIFF:
+  case ARM_RELOC_LOCAL_SECTDIFF:
+  case ARM_RELOC_HALF_SECTDIFF:
+  case ARM_RELOC_HALF:
+    return true;
+  default:
+    return false;
+  }
+}
+
+int32_t ArchHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction) {
+  uint32_t s = (instruction >> 10) & 0x1;
+  uint32_t j1 = (instruction >> 29) & 0x1;
+  uint32_t j2 = (instruction >> 27) & 0x1;
+  uint32_t imm10 = instruction & 0x3FF;
+  uint32_t imm11 = (instruction >> 16) & 0x7FF;
+  uint32_t i1 = (j1 == s);
+  uint32_t i2 = (j2 == s);
+  uint32_t dis =
+      (s << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | (imm11 << 1);
+  int32_t sdis = dis;
+  if (s)
+    return (sdis | 0xFE000000);
+  else
+    return sdis;
+}
+
+int32_t ArchHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) {
+  // Sign-extend imm24
+  int32_t displacement = (instruction & 0x00FFFFFF) << 2;
+  if ((displacement & 0x02000000) != 0)
+    displacement |= 0xFC000000;
+  // If this is BLX and H bit set, add 2.
+  if ((instruction & 0xFF000000) == 0xFB000000)
+    displacement += 2;
+  return displacement;
+}
+
+uint32_t ArchHandler_arm::setDisplacementInArmBranch(uint32_t instruction,
+                                                     int32_t displacement) {
+  // FIXME: handle BLX and out-of-range.
+  uint32_t newInstruction = (instruction & 0xFF000000);
+  newInstruction |= ((displacement >> 2) & 0x00FFFFFF);
+  return newInstruction;
+}
+
+uint16_t ArchHandler_arm::getWordFromThumbMov(uint32_t instruction) {
+  uint32_t i = ((instruction & 0x00000400) >> 10);
+  uint32_t imm4 = (instruction & 0x0000000F);
+  uint32_t imm3 = ((instruction & 0x70000000) >> 28);
+  uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
+  return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+}
+
+uint16_t ArchHandler_arm::getWordFromArmMov(uint32_t instruction) {
+  uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
+  uint32_t imm12 = (instruction & 0x00000FFF);
+  return (imm4 << 12) | imm12;
+}
+
+uint32_t ArchHandler_arm::clearThumbBit(uint32_t value, const Atom *target) {
+  // The assembler often adds one to the address of a thumb function.
+  // We need to undo that so it does not look like an addend.
+  if (value & 1) {
+    if (isa<DefinedAtom>(target)) {
+      const MachODefinedAtom *machoTarget =
+          reinterpret_cast<const MachODefinedAtom *>(target);
+      if (machoTarget->isThumb())
+        value &= -2; // mask off thumb-bit
+    }
+  }
+  return value;
+}
+
+std::error_code ArchHandler_arm::getReferenceInfo(
+    const Relocation &reloc, const DefinedAtom *inAtom, uint32_t offsetInAtom,
+    uint64_t fixupAddress, bool swap,
+    FindAtomBySectionAndAddress atomFromAddress,
+    FindAtomBySymbolIndex atomFromSymbolIndex, Reference::KindValue *kind,
+    const lld::Atom **target, Reference::Addend *addend) {
+  typedef std::error_code E;
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint64_t targetAddress;
+  uint32_t instruction = readU32(swap, fixupContent);
+  int32_t displacement;
+  switch (relocPattern(reloc)) {
+  case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4:
+    // ex: bl _foo (and _foo is undefined)
+    *kind = thumb_b22;
+    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    // Instruction contains branch to addend.
+    displacement = getDisplacementFromThumbBranch(instruction);
+    *addend = fixupAddress + 4 + displacement;
+    return std::error_code();
+  case ARM_THUMB_RELOC_BR22 | rPcRel | rLength4:
+    // ex: bl _foo (and _foo is defined)
+    *kind = thumb_b22;
+    displacement = getDisplacementFromThumbBranch(instruction);
+    targetAddress = fixupAddress + 4 + displacement;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4:
+    // ex: bl _foo+4 (and _foo is defined)
+    *kind = thumb_b22;
+    displacement = getDisplacementFromThumbBranch(instruction);
+    targetAddress = fixupAddress + 4 + displacement;
+    if (E ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    // reloc.value is target atom's address.  Instruction contains branch
+    // to atom+addend.
+    *addend += (targetAddress - reloc.value);
+    return std::error_code();
+  case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
+    // ex: bl _foo (and _foo is undefined)
+    *kind = arm_b24;
+    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    // Instruction contains branch to addend.
+    displacement = getDisplacementFromArmBranch(instruction);
+    *addend = fixupAddress + 8 + displacement;
+    return std::error_code();
+  case ARM_RELOC_BR24 | rPcRel | rLength4:
+    // ex: bl _foo (and _foo is defined)
+    *kind = arm_b24;
+    displacement = getDisplacementFromArmBranch(instruction);
+    targetAddress = fixupAddress + 8 + displacement;
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4:
+    // ex: bl _foo+4 (and _foo is defined)
+    *kind = arm_b24;
+    displacement = getDisplacementFromArmBranch(instruction);
+    targetAddress = fixupAddress + 8 + displacement;
+    if (E ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    // reloc.value is target atom's address.  Instruction contains branch
+    // to atom+addend.
+    *addend += (targetAddress - reloc.value);
+    return std::error_code();
+  case ARM_RELOC_VANILLA | rExtern | rLength4:
+    // ex: .long _foo (and _foo is undefined)
+    *kind = pointer32;
+    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = instruction;
+    return std::error_code();
+  case ARM_RELOC_VANILLA | rLength4:
+    // ex: .long _foo (and _foo is defined)
+    *kind = pointer32;
+    if (E ec = atomFromAddress(reloc.symbol, instruction, target, addend))
+      return ec;
+    *addend = clearThumbBit((uint32_t) * addend, *target);
+    return std::error_code();
+  case ARM_RELOC_VANILLA | rScattered | rLength4:
+    // ex: .long _foo+a (and _foo is defined)
+    *kind = pointer32;
+    if (E ec = atomFromAddress(0, reloc.value, target, addend))
+      return ec;
+    *addend += (clearThumbBit(instruction, *target) - reloc.value);
+    return std::error_code();
+  default:
+    return make_dynamic_error_code(Twine("unsupported arm relocation type"));
+  }
+  return std::error_code();
+}
+
+std::error_code
+ArchHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
+                                     const normalized::Relocation &reloc2,
+                                     const DefinedAtom *inAtom,
+                                     uint32_t offsetInAtom,
+                                     uint64_t fixupAddress, bool swap,
+                                     FindAtomBySectionAndAddress atomFromAddr,
+                                     FindAtomBySymbolIndex atomFromSymbolIndex,
+                                     Reference::KindValue *kind,
+                                     const lld::Atom **target,
+                                     Reference::Addend *addend) {
+  bool pointerDiff = false;
+  bool funcRel;
+  bool top;
+  bool thumbReloc;
+  switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLength4) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLength4):
+    // ex: movw        r1, :lower16:(_x-L1) [thumb mode]
+    *kind = thumb_movw_funcRel;
+    funcRel = true;
+    top = false;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLength8) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLength8):
+    // ex: movt        r1, :upper16:(_x-L1) [thumb mode]
+    *kind = thumb_movt_funcRel;
+    funcRel = true;
+    top = true;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLength1) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLength1):
+    // ex: movw        r1, :lower16:(_x-L1) [arm mode]
+    *kind = arm_movw_funcRel;
+    funcRel = true;
+    top = false;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLength2) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLength2):
+    // ex: movt        r1, :upper16:(_x-L1) [arm mode]
+    *kind = arm_movt_funcRel;
+    funcRel = true;
+    top = true;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF     | rLength4) << 16 |
+         ARM_RELOC_PAIR     | rLength4):
+    // ex: movw        r1, :lower16:_x [thumb mode]
+    *kind = thumb_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF     | rLength8) << 16 |
+         ARM_RELOC_PAIR     | rLength8):
+    // ex: movt        r1, :upper16:_x [thumb mode]
+    *kind = thumb_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF     | rLength1) << 16 |
+         ARM_RELOC_PAIR     | rLength1):
+    // ex: movw        r1, :lower16:_x [arm mode]
+    *kind = arm_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF     | rLength2) << 16 |
+         ARM_RELOC_PAIR     | rLength2):
+    // ex: movt        r1, :upper16:_x [arm mode]
+    *kind = arm_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF | rScattered  | rLength4) << 16 |
+         ARM_RELOC_PAIR               | rLength4):
+    // ex: movw        r1, :lower16:_x+a [thumb mode]
+    *kind = thumb_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF | rScattered  | rLength8) << 16 |
+         ARM_RELOC_PAIR               | rLength8):
+    // ex: movt        r1, :upper16:_x+a [thumb mode]
+    *kind = thumb_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF | rScattered  | rLength1) << 16 |
+         ARM_RELOC_PAIR               | rLength1):
+    // ex: movw        r1, :lower16:_x+a [arm mode]
+    *kind = arm_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF | rScattered  | rLength2) << 16 |
+         ARM_RELOC_PAIR               | rLength2):
+    // ex: movt        r1, :upper16:_x+a [arm mode]
+    *kind = arm_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF | rExtern   | rLength4) << 16 |
+         ARM_RELOC_PAIR             | rLength4):
+    // ex: movw        r1, :lower16:_undef [thumb mode]
+    *kind = thumb_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF | rExtern   | rLength8) << 16 |
+         ARM_RELOC_PAIR             | rLength8):
+    // ex: movt        r1, :upper16:_undef [thumb mode]
+    *kind = thumb_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = true;
+    break;
+  case ((ARM_RELOC_HALF | rExtern   | rLength1) << 16 |
+         ARM_RELOC_PAIR             | rLength1):
+    // ex: movw        r1, :lower16:_undef [arm mode]
+    *kind = arm_movw;
+    funcRel = false;
+    top = false;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_HALF | rExtern   | rLength2) << 16 |
+         ARM_RELOC_PAIR             | rLength2):
+    // ex: movt        r1, :upper16:_undef [arm mode]
+    *kind = arm_movt;
+    funcRel = false;
+    top = true;
+    thumbReloc = false;
+    break;
+  case ((ARM_RELOC_SECTDIFF       | rScattered | rLength4) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLength4):
+  case ((ARM_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
+         ARM_RELOC_PAIR           | rScattered | rLength4):
+    // ex: .long _foo - .
+    pointerDiff = true;
+    break;
+  default:
+    return make_dynamic_error_code(Twine("unsupported arm relocation pair"));
+  }
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  std::error_code ec;
+  uint32_t instruction = readU32(swap, fixupContent);
+  uint32_t value;
+  uint32_t fromAddress;
+  uint32_t toAddress;
+  uint16_t instruction16;
+  uint16_t other16;
+  const lld::Atom *fromTarget;
+  Reference::Addend offsetInTo;
+  Reference::Addend offsetInFrom;
+  if (pointerDiff) {
+    toAddress = reloc1.value;
+    fromAddress = reloc2.value;
+    ec = atomFromAddr(0, toAddress, target, &offsetInTo);
+    if (ec)
+      return ec;
+    ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
+    if (ec)
+      return ec;
+    if (fromTarget != inAtom)
+      return make_dynamic_error_code(Twine("SECTDIFF relocation where "
+                                           "subtrahend label is not in atom"));
+    *kind = delta32;
+    value = clearThumbBit(instruction, *target);
+    *addend = value - (toAddress - fromAddress);
+  } else if (funcRel) {
+    toAddress = reloc1.value;
+    fromAddress = reloc2.value;
+    ec = atomFromAddr(0, toAddress, target, &offsetInTo);
+    if (ec)
+      return ec;
+    ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
+    if (ec)
+      return ec;
+    if (fromTarget != inAtom)
+      return make_dynamic_error_code(
+          Twine("ARM_RELOC_HALF_SECTDIFF relocation "
+                "where subtrahend label is not in atom"));
+    other16 = (reloc2.offset & 0xFFFF);
+    if (thumbReloc)
+      instruction16 = getWordFromThumbMov(instruction);
+    else
+      instruction16 = getWordFromArmMov(instruction);
+    if (top)
+      value = (instruction16 << 16) | other16;
+    else
+      value = (other16 << 16) | instruction16;
+    value = clearThumbBit(value, *target);
+    int64_t ta = (int64_t) value - (toAddress - fromAddress);
+    *addend = ta - offsetInFrom;
+    return std::error_code();
+  } else {
+    uint32_t sectIndex;
+    if (thumbReloc)
+      instruction16 = getWordFromThumbMov(instruction);
+    else
+      instruction16 = getWordFromArmMov(instruction);
+    other16 = (reloc2.offset & 0xFFFF);
+    if (top)
+      value = (instruction16 << 16) | other16;
+    else
+      value = (other16 << 16) | instruction16;
+    if (reloc1.isExtern) {
+      ec = atomFromSymbolIndex(reloc1.symbol, target);
+      if (ec)
+        return ec;
+      *addend = value;
+    } else {
+      if (reloc1.scattered) {
+        toAddress = reloc1.value;
+        sectIndex = 0;
+      } else {
+        toAddress = value;
+        sectIndex = reloc1.symbol;
+      }
+      ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo);
+      if (ec)
+        return ec;
+      *addend = value - toAddress;
+    }
+  }
+
+  return std::error_code();
+}
+
+void ArchHandler_arm::applyFixup(Reference::KindNamespace ns,
+                                 Reference::KindArch arch,
+                                 Reference::KindValue kindValue,
+                                 uint64_t addend, uint8_t *location,
+                                 uint64_t fixupAddress, uint64_t targetAddress,
+                                 uint64_t inAtomAddress) {
+  if (ns != Reference::KindNamespace::mach_o)
+    return;
+  assert(arch == Reference::KindArch::ARM);
+  int32_t *loc32 = reinterpret_cast<int32_t *>(location);
+  int32_t displacement;
+  // FIXME: these writes may need a swap.
+  switch (kindValue) {
+  case thumb_b22:
+    // FIXME
+    break;
+  case thumb_movw:
+    // FIXME
+    break;
+  case thumb_movt:
+    // FIXME
+    break;
+  case thumb_movw_funcRel:
+    // FIXME
+    break;
+  case thumb_movt_funcRel:
+    // FIXME
+    break;
+  case arm_b24:
+    displacement = (targetAddress - (fixupAddress + 8)) + addend;
+    *loc32 = setDisplacementInArmBranch(*loc32, displacement);
+    break;
+  case arm_movw:
+    // FIXME
+    break;
+  case arm_movt:
+    // FIXME
+    break;
+  case arm_movw_funcRel:
+    // FIXME
+    break;
+  case arm_movt_funcRel:
+    // FIXME
+    break;
+  case pointer32:
+    // FIXME
+    break;
+  case delta32:
+    // FIXME
+    break;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    // do nothing
+    break;
+  case invalid:
+    llvm_unreachable("invalid ARM Reference Kind");
+    break;
+  }
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_arm() {
+  return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_arm());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86.cpp
new file mode 100644 (file)
index 0000000..db7d036
--- /dev/null
@@ -0,0 +1,331 @@
+//===- lib/FileFormat/MachO/ArchHandler_x86.cpp ---------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+class ArchHandler_x86 : public ArchHandler {
+public:
+           ArchHandler_x86();
+  virtual ~ArchHandler_x86();
+
+  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+  Reference::KindArch kindArch() override { return Reference::KindArch::x86; }
+
+  const StubInfo &stubInfo() override { return _sStubInfo; }
+  bool isCallSite(const Reference &) override;
+  bool isPointer(const Reference &) override;
+  bool isPairedReloc(const normalized::Relocation &) override;
+  std::error_code getReferenceInfo(const normalized::Relocation &reloc,
+                                   const DefinedAtom *inAtom,
+                                   uint32_t offsetInAtom,
+                                   uint64_t fixupAddress, bool swap,
+                                   FindAtomBySectionAndAddress atomFromAddress,
+                                   FindAtomBySymbolIndex atomFromSymbolIndex,
+                                   Reference::KindValue *kind,
+                                   const lld::Atom **target,
+                                   Reference::Addend *addend) override;
+  std::error_code
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool swap,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind,
+                           const lld::Atom **target,
+                           Reference::Addend *addend) override;
+
+  void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
+                          Reference::KindValue kindValue, uint64_t addend,
+                          uint8_t *location, uint64_t fixupAddress,
+                          uint64_t targetAddress, uint64_t inAtomAddress) 
+                          override;
+
+private:
+  static const Registry::KindStrings _sKindStrings[];
+  static const StubInfo              _sStubInfo;
+
+  enum : Reference::KindValue {
+    invalid,               /// for error condition
+
+    // Kinds found in mach-o .o files:
+    branch32,              /// ex: call _foo
+    branch16,              /// ex: callw _foo
+    abs32,                 /// ex: movl _foo, %eax
+    funcRel32,             /// ex: movl _foo-L1(%eax), %eax
+    pointer32,             /// ex: .long _foo
+    delta32,               /// ex: .long _foo - .
+
+    // Kinds introduced by Passes:
+    lazyPointer,           /// Location contains a lazy pointer.
+    lazyImmediateLocation, /// Location contains immediate value used in stub.
+  };
+  
+  const bool _swap;
+};
+
+//===----------------------------------------------------------------------===//
+//  ArchHandler_x86
+//===----------------------------------------------------------------------===//
+
+ArchHandler_x86::ArchHandler_x86() :
+  _swap(!MachOLinkingContext::isHostEndian(MachOLinkingContext::arch_x86)) {}
+  
+ArchHandler_x86::~ArchHandler_x86() { }
+  
+const Registry::KindStrings ArchHandler_x86::_sKindStrings[] = {
+  LLD_KIND_STRING_ENTRY(invalid),
+  LLD_KIND_STRING_ENTRY(branch32),
+  LLD_KIND_STRING_ENTRY(branch16),
+  LLD_KIND_STRING_ENTRY(abs32),
+  LLD_KIND_STRING_ENTRY(funcRel32),
+  LLD_KIND_STRING_ENTRY(pointer32),
+  LLD_KIND_STRING_ENTRY(delta32),
+  LLD_KIND_STRING_ENTRY(lazyPointer),
+  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+  LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_x86::_sStubInfo = {
+  "dyld_stub_binder",
+
+  // Lazy pointer references 
+  { Reference::KindArch::x86, pointer32, 0, 0 },
+  { Reference::KindArch::x86, lazyPointer, 0, 0 },
+  
+  // GOT pointer to dyld_stub_binder
+  { Reference::KindArch::x86, pointer32, 0, 0 },
+
+  // x86 code alignment
+  1, 
+  
+  // Stub size and code
+  6, 
+  { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 },       // jmp *lazyPointer
+  { Reference::KindArch::x86, abs32, 2, 0 },
+  
+  // Stub Helper size and code
+  10,
+  { 0x68, 0x00, 0x00, 0x00, 0x00,               // pushl $lazy-info-offset
+    0xE9, 0x00, 0x00, 0x00, 0x00 },             // jmp helperhelper
+  { Reference::KindArch::x86, lazyImmediateLocation, 1, 0 },
+  { Reference::KindArch::x86, branch32, 6, 0 },
+  
+  // Stub Helper-Common size and code
+  12,
+  { 0x68, 0x00, 0x00, 0x00, 0x00,               // pushl $dyld_ImageLoaderCache
+    0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,         // jmp *_fast_lazy_bind
+    0x90 },                                     // nop
+  { Reference::KindArch::x86, abs32, 1, 0 },
+  { Reference::KindArch::x86, abs32, 7, 0 }
+};
+
+bool ArchHandler_x86::isCallSite(const Reference &ref) {
+  return (ref.kindValue() == branch32);
+}
+
+bool ArchHandler_x86::isPointer(const Reference &ref) {
+  return (ref.kindValue() == pointer32);
+}
+
+bool ArchHandler_x86::isPairedReloc(const Relocation &reloc) {
+  if (!reloc.scattered)
+    return false;
+  return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) ||
+         (reloc.type == GENERIC_RELOC_SECTDIFF);
+}
+
+std::error_code
+ArchHandler_x86::getReferenceInfo(const Relocation &reloc,
+                                  const DefinedAtom *inAtom,
+                                  uint32_t offsetInAtom,
+                                  uint64_t fixupAddress, bool swap,
+                                  FindAtomBySectionAndAddress atomFromAddress,
+                                  FindAtomBySymbolIndex atomFromSymbolIndex,
+                                  Reference::KindValue *kind,
+                                  const lld::Atom **target,
+                                  Reference::Addend *addend) {
+  typedef std::error_code E;
+  DefinedAtom::ContentPermissions perms;
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint64_t targetAddress;
+  switch (relocPattern(reloc)) {
+  case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
+    // ex: call _foo (and _foo undefined)
+    *kind = branch32;
+    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = fixupAddress + 4 + readS32(swap, fixupContent);
+    break;
+  case GENERIC_RELOC_VANILLA | rPcRel | rLength4:
+    // ex: call _foo (and _foo defined)
+    *kind = branch32;
+    targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+    break;
+  case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
+    // ex: callw _foo (and _foo undefined)
+    *kind = branch16;
+    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = fixupAddress + 2 + readS16(swap, fixupContent);
+    break;
+  case GENERIC_RELOC_VANILLA | rPcRel | rLength2:
+    // ex: callw _foo (and _foo defined)
+    *kind = branch16;
+    targetAddress = fixupAddress + 2 + readS16(swap, fixupContent);
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+    break;
+  case GENERIC_RELOC_VANILLA | rExtern | rLength4:
+    // ex: movl        _foo, %eax   (and _foo undefined)
+    // ex: .long _foo        (and _foo undefined)
+    perms = inAtom->permissions();
+    *kind =
+        ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
+                                                                 : pointer32;
+    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = readU32(swap, fixupContent);
+    break;
+  case GENERIC_RELOC_VANILLA | rLength4:
+    // ex: movl        _foo, %eax   (and _foo defined)
+    // ex: .long _foo        (and _foo defined)
+    perms = inAtom->permissions();
+    *kind =
+        ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? abs32
+                                                                 : pointer32;
+    targetAddress = readU32(swap, fixupContent);
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+    break;
+  default:
+    return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
+  }
+  return std::error_code();
+}
+
+std::error_code
+ArchHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
+                                      const normalized::Relocation &reloc2,
+                                      const DefinedAtom *inAtom,
+                                      uint32_t offsetInAtom,
+                                      uint64_t fixupAddress, bool swap,
+                                      FindAtomBySectionAndAddress atomFromAddr,
+                                      FindAtomBySymbolIndex atomFromSymbolIndex,
+                                      Reference::KindValue *kind,
+                                      const lld::Atom **target,
+                                      Reference::Addend *addend) {
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  std::error_code ec;
+  DefinedAtom::ContentPermissions perms = inAtom->permissions();
+  uint32_t fromAddress;
+  uint32_t toAddress;
+  uint32_t value;
+  const lld::Atom *fromTarget;
+  Reference::Addend offsetInTo;
+  Reference::Addend offsetInFrom;
+  switch (relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+  case((GENERIC_RELOC_SECTDIFF | rScattered | rLength4) << 16 |
+       GENERIC_RELOC_PAIR | rScattered | rLength4)
+      :
+  case((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
+       GENERIC_RELOC_PAIR | rScattered | rLength4)
+      :
+    toAddress = reloc1.value;
+    fromAddress = reloc2.value;
+    value = readS32(swap, fixupContent);
+    ec = atomFromAddr(0, toAddress, target, &offsetInTo);
+    if (ec)
+      return ec;
+    ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
+    if (ec)
+      return ec;
+    if (fromTarget != inAtom)
+      return make_dynamic_error_code(Twine("SECTDIFF relocation where "
+                                           "subtrahend label is not in atom"));
+    *kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X) ? funcRel32
+                                                                     : delta32;
+    if (*kind == funcRel32) {
+      // SECTDIFF relocations are used in i386 codegen where the function
+      // prolog does a CALL to the next instruction which POPs the return
+      // address into EBX which becomes the pic-base register.  The POP
+      // instruction is label the used for the subtrahend in expressions.
+      // The funcRel32 kind represents the 32-bit delta to some symbol from
+      // the start of the function (atom) containing the funcRel32.
+      uint32_t ta = fromAddress + value - toAddress;
+      *addend = ta - offsetInFrom;
+    } else {
+      *addend = fromAddress + value - toAddress;
+    }
+    return std::error_code();
+    break;
+  default:
+    return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
+  }
+}
+
+void ArchHandler_x86::applyFixup(Reference::KindNamespace ns,
+                                 Reference::KindArch arch,
+                                 Reference::KindValue kindValue,
+                                 uint64_t addend, uint8_t *location,
+                                 uint64_t fixupAddress, uint64_t targetAddress,
+                                 uint64_t inAtomAddress) {
+  if (ns != Reference::KindNamespace::mach_o)
+    return;
+  assert(arch == Reference::KindArch::x86);
+  int32_t *loc32 = reinterpret_cast<int32_t *>(location);
+  int16_t *loc16 = reinterpret_cast<int16_t *>(location);
+  switch (kindValue) {
+  case branch32:
+    write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend);
+    break;
+  case branch16:
+    write16(*loc16, _swap, (targetAddress - (fixupAddress + 4)) + addend);
+    break;
+  case pointer32:
+  case abs32:
+    write32(*loc32, _swap, targetAddress + addend);
+    break;
+  case funcRel32:
+    write32(*loc32, _swap, targetAddress - inAtomAddress + addend); // FIXME
+    break;
+  case delta32:
+    write32(*loc32, _swap, targetAddress - fixupAddress + addend);
+    break;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    // do nothing
+    break;
+  default:
+    llvm_unreachable("invalid x86 Reference Kind");
+    break;
+  }
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86() {
+  return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86());
+}
+
+} // namespace mach_o
+} // namespace lld
diff --git a/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
new file mode 100644 (file)
index 0000000..5f1cddb
--- /dev/null
@@ -0,0 +1,421 @@
+//===- lib/FileFormat/MachO/ArchHandler_x86_64.cpp ------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ArchHandler.h"
+#include "Atoms.h"
+#include "MachONormalizedFileBinaryUtils.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
+
+namespace lld {
+namespace mach_o {
+
+class ArchHandler_x86_64 : public ArchHandler {
+public:
+           ArchHandler_x86_64();
+  virtual ~ArchHandler_x86_64();
+
+  const Registry::KindStrings *kindStrings() override { return _sKindStrings; }
+
+  Reference::KindArch kindArch() override {
+    return Reference::KindArch::x86_64;
+  }
+
+  /// Used by GOTPass to locate GOT References
+  bool isGOTAccess(const Reference &ref, bool &canBypassGOT) override {
+    if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+      return false;
+    assert(ref.kindArch() == Reference::KindArch::x86_64);
+    switch (ref.kindValue()) {
+    case ripRel32GotLoad:
+      canBypassGOT = true;
+      return true;
+    case ripRel32Got:
+      canBypassGOT = false;
+      return true;
+    default:
+      return false;
+    }
+  }
+
+  /// Used by GOTPass to update GOT References
+  void updateReferenceToGOT(const Reference *ref, bool targetNowGOT) override {
+    assert(ref->kindNamespace() == Reference::KindNamespace::mach_o);
+    assert(ref->kindArch() == Reference::KindArch::x86_64);
+    const_cast<Reference *>(ref)
+        ->setKindValue(targetNowGOT ? ripRel32 : ripRel32GotLoadNowLea);
+  }
+
+  const StubInfo &stubInfo() override { return _sStubInfo; }
+
+  bool isCallSite(const Reference &) override;
+  bool isPointer(const Reference &) override;
+  bool isPairedReloc(const normalized::Relocation &) override;
+  std::error_code getReferenceInfo(const normalized::Relocation &reloc,
+                                   const DefinedAtom *inAtom,
+                                   uint32_t offsetInAtom,
+                                   uint64_t fixupAddress, bool swap,
+                                   FindAtomBySectionAndAddress atomFromAddress,
+                                   FindAtomBySymbolIndex atomFromSymbolIndex,
+                                   Reference::KindValue *kind, 
+                                   const lld::Atom **target, 
+                                   Reference::Addend *addend) override;
+  std::error_code 
+      getPairReferenceInfo(const normalized::Relocation &reloc1,
+                           const normalized::Relocation &reloc2,
+                           const DefinedAtom *inAtom,
+                           uint32_t offsetInAtom,
+                           uint64_t fixupAddress, bool swap,
+                           FindAtomBySectionAndAddress atomFromAddress,
+                           FindAtomBySymbolIndex atomFromSymbolIndex,
+                           Reference::KindValue *kind, 
+                           const lld::Atom **target, 
+                           Reference::Addend *addend) override;
+                           
+  virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
+                          Reference::KindValue kindValue, uint64_t addend,
+                          uint8_t *location, uint64_t fixupAddress,
+                          uint64_t targetAddress, uint64_t inAtomAddress) 
+                          override;
+
+private:
+  static const Registry::KindStrings _sKindStrings[];
+  static const StubInfo              _sStubInfo;
+
+  enum : Reference::KindValue {
+    invalid,               /// for error condition
+    
+    // Kinds found in mach-o .o files:
+    branch32,              /// ex: call _foo
+    ripRel32,              /// ex: movq _foo(%rip), %rax
+    ripRel32Minus1,        /// ex: movb $0x12, _foo(%rip)
+    ripRel32Minus2,        /// ex: movw $0x1234, _foo(%rip)
+    ripRel32Minus4,        /// ex: movl $0x12345678, _foo(%rip)
+    ripRel32Anon,          /// ex: movq L1(%rip), %rax
+    ripRel32GotLoad,       /// ex: movq  _foo@GOTPCREL(%rip), %rax
+    ripRel32Got,           /// ex: pushq _foo@GOTPCREL(%rip)
+    pointer64,             /// ex: .quad _foo
+    pointer64Anon,         /// ex: .quad L1
+    delta64,               /// ex: .quad _foo - .
+    delta32,               /// ex: .long _foo - .
+    delta64Anon,           /// ex: .quad L1 - .
+    delta32Anon,           /// ex: .long L1 - .
+    
+    // Kinds introduced by Passes:
+    ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so 
+                           ///  "movq  _foo@GOTPCREL(%rip), %rax" can be changed
+                           /// to "leaq _foo(%rip), %rax
+    lazyPointer,           /// Location contains a lazy pointer.
+    lazyImmediateLocation, /// Location contains immediate value used in stub.
+  };
+
+  Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
+  Reference::KindValue kindFromRelocPair(const normalized::Relocation &reloc1,
+                                         const normalized::Relocation &reloc2);
+
+  const bool _swap;
+};
+
+
+ArchHandler_x86_64::ArchHandler_x86_64() :
+  _swap(!MachOLinkingContext::isHostEndian(MachOLinkingContext::arch_x86_64)) {}
+
+ArchHandler_x86_64::~ArchHandler_x86_64() { }
+
+const Registry::KindStrings ArchHandler_x86_64::_sKindStrings[] = {
+  LLD_KIND_STRING_ENTRY(invalid), LLD_KIND_STRING_ENTRY(branch32),
+  LLD_KIND_STRING_ENTRY(ripRel32), LLD_KIND_STRING_ENTRY(ripRel32Minus1),
+  LLD_KIND_STRING_ENTRY(ripRel32Minus2), LLD_KIND_STRING_ENTRY(ripRel32Minus4),
+  LLD_KIND_STRING_ENTRY(ripRel32Anon), LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
+  LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
+  LLD_KIND_STRING_ENTRY(ripRel32Got), LLD_KIND_STRING_ENTRY(lazyPointer),
+  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+  LLD_KIND_STRING_ENTRY(pointer64), LLD_KIND_STRING_ENTRY(pointer64Anon),
+  LLD_KIND_STRING_ENTRY(delta32), LLD_KIND_STRING_ENTRY(delta64),
+  LLD_KIND_STRING_ENTRY(delta32Anon), LLD_KIND_STRING_ENTRY(delta64Anon),
+  LLD_KIND_STRING_END
+};
+
+const ArchHandler::StubInfo ArchHandler_x86_64::_sStubInfo = {
+  "dyld_stub_binder",
+
+  // Lazy pointer references 
+  { Reference::KindArch::x86_64, pointer64, 0, 0 },
+  { Reference::KindArch::x86_64, lazyPointer, 0, 0 },
+  
+  // GOT pointer to dyld_stub_binder
+  { Reference::KindArch::x86_64, pointer64, 0, 0 },
+
+  // x86_64 code alignment 2^1
+  1, 
+  
+  // Stub size and code
+  6, 
+  { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00 },       // jmp *lazyPointer
+  { Reference::KindArch::x86_64, ripRel32, 2, 0 },
+  
+  // Stub Helper size and code
+  10,
+  { 0x68, 0x00, 0x00, 0x00, 0x00,               // pushq $lazy-info-offset
+    0xE9, 0x00, 0x00, 0x00, 0x00 },             // jmp helperhelper
+  { Reference::KindArch::x86_64, lazyImmediateLocation, 1, 0 },
+  { Reference::KindArch::x86_64, branch32, 6, 0 },
+  
+  // Stub Helper-Common size and code
+  16,
+  { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00,   // leaq cache(%rip),%r11
+    0x41, 0x53,                                 // push %r11
+    0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,         // jmp *binder(%rip)
+    0x90 },                                     // nop
+  { Reference::KindArch::x86_64, ripRel32, 3, 0 },
+  { Reference::KindArch::x86_64, ripRel32, 11, 0 }
+  
+};
+
+bool ArchHandler_x86_64::isCallSite(const Reference &ref) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  assert(ref.kindArch() == Reference::KindArch::x86_64);
+  return (ref.kindValue() == branch32);
+}
+
+bool ArchHandler_x86_64::isPointer(const Reference &ref) {
+  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+    return false;
+  assert(ref.kindArch() == Reference::KindArch::x86_64);
+  Reference::KindValue kind = ref.kindValue();
+  return (kind == pointer64 || kind == pointer64Anon);
+}
+
+bool ArchHandler_x86_64::isPairedReloc(const Relocation &reloc) {
+  return (reloc.type == X86_64_RELOC_SUBTRACTOR);
+}
+
+Reference::KindValue
+ArchHandler_x86_64::kindFromReloc(const Relocation &reloc) {
+  switch(relocPattern(reloc)) {
+  case X86_64_RELOC_BRANCH   | rPcRel | rExtern | rLength4:
+    return branch32;
+  case X86_64_RELOC_SIGNED   | rPcRel | rExtern | rLength4:
+    return ripRel32;
+  case X86_64_RELOC_SIGNED   | rPcRel |           rLength4:
+    return ripRel32Anon;
+  case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4:
+    return ripRel32Minus1;
+  case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4:
+    return ripRel32Minus2;
+  case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
+    return ripRel32Minus4;
+  case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4:
+    return ripRel32GotLoad;
+  case X86_64_RELOC_GOT      | rPcRel | rExtern | rLength4:
+    return ripRel32Got;
+  case X86_64_RELOC_UNSIGNED          | rExtern | rLength8:
+    return pointer64;
+  case X86_64_RELOC_UNSIGNED                    | rLength8:
+    return pointer64Anon;
+  default:
+    return invalid;
+  }
+}
+
+std::error_code 
+ArchHandler_x86_64::getReferenceInfo(const Relocation &reloc,
+                                    const DefinedAtom *inAtom,
+                                    uint32_t offsetInAtom,
+                                    uint64_t fixupAddress, bool swap,
+                                    FindAtomBySectionAndAddress atomFromAddress,
+                                    FindAtomBySymbolIndex atomFromSymbolIndex,
+                                    Reference::KindValue *kind, 
+                                    const lld::Atom **target, 
+                                    Reference::Addend *addend) {
+  typedef std::error_code E;
+  *kind = kindFromReloc(reloc);
+  if (*kind == invalid)
+    return make_dynamic_error_code(Twine("unknown type"));
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  uint64_t targetAddress;
+  switch (*kind) {
+  case branch32:
+  case ripRel32:
+    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = readS32(swap, fixupContent);
+    return std::error_code();
+  case ripRel32Minus1:
+    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = readS32(swap, fixupContent) + 1;
+    return std::error_code();
+  case ripRel32Minus2:
+    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = readS32(swap, fixupContent) + 2;
+    return std::error_code();
+  case ripRel32Minus4:
+    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = readS32(swap, fixupContent) + 4;
+    return std::error_code();
+  case ripRel32Anon:
+    targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  case ripRel32GotLoad:
+  case ripRel32Got:
+    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = 0;
+    return std::error_code();
+  case pointer64:
+    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+      return ec;
+    *addend = readS64(swap, fixupContent);
+    return std::error_code();
+  case pointer64Anon:
+    targetAddress = readS64(swap, fixupContent);
+    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+  default:
+    llvm_unreachable("bad reloc kind");
+  }
+}
+
+Reference::KindValue
+ArchHandler_x86_64::kindFromRelocPair(const normalized::Relocation &reloc1,
+                                      const normalized::Relocation &reloc2) {
+  switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+        X86_64_RELOC_UNSIGNED    | rExtern | rLength8):
+    return delta64;
+  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+        X86_64_RELOC_UNSIGNED    | rExtern | rLength4):
+    return delta32;
+  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+        X86_64_RELOC_UNSIGNED              | rLength8):
+    return delta64Anon;
+  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+        X86_64_RELOC_UNSIGNED              | rLength4):
+    return delta32Anon;
+  default:
+    llvm_unreachable("bad reloc pairs");
+  }
+}
+
+std::error_code
+ArchHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
+                                   const normalized::Relocation &reloc2,
+                                   const DefinedAtom *inAtom,
+                                   uint32_t offsetInAtom,
+                                   uint64_t fixupAddress, bool swap,
+                                   FindAtomBySectionAndAddress atomFromAddress,
+                                   FindAtomBySymbolIndex atomFromSymbolIndex,
+                                   Reference::KindValue *kind, 
+                                   const lld::Atom **target, 
+                                   Reference::Addend *addend) {
+  *kind = kindFromRelocPair(reloc1, reloc2);
+  if (*kind == invalid)
+    return make_dynamic_error_code(Twine("unknown pair"));
+  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+  typedef std::error_code E;
+  uint64_t targetAddress;
+  const lld::Atom *fromTarget;
+  if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
+    return ec;
+  if (fromTarget != inAtom)
+    return make_dynamic_error_code(Twine("pointer diff not in base atom"));
+  switch (*kind) {
+  case delta64:
+    if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    *addend = readS64(swap, fixupContent) + offsetInAtom;
+    return std::error_code();
+  case delta32:
+    if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+      return ec;
+    *addend = readS32(swap, fixupContent) + offsetInAtom;
+    return std::error_code();
+  case delta64Anon:
+    targetAddress = offsetInAtom + readS64(swap, fixupContent);
+    return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+  case delta32Anon:
+    targetAddress = offsetInAtom + readS32(swap, fixupContent);
+    return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+  default:
+    llvm_unreachable("bad reloc pair kind");
+  }
+}
+
+void ArchHandler_x86_64::applyFixup(Reference::KindNamespace ns,
+                                    Reference::KindArch arch,
+                                    Reference::KindValue kindValue,
+                                    uint64_t addend, uint8_t *location,
+                                    uint64_t fixupAddress,
+                                    uint64_t targetAddress,
+                                    uint64_t inAtomAddress) {
+  if (ns != Reference::KindNamespace::mach_o)
+    return;
+  assert(arch == Reference::KindArch::x86_64);
+  int32_t *loc32 = reinterpret_cast<int32_t *>(location);
+  uint64_t *loc64 = reinterpret_cast<uint64_t *>(location);
+  switch (kindValue) {
+  case branch32:
+  case ripRel32:
+  case ripRel32Got:
+  case ripRel32GotLoad:
+    write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend);
+    break;
+  case pointer64:
+  case pointer64Anon:
+    write64(*loc64, _swap, targetAddress + addend);
+    break;
+  case ripRel32Minus1:
+    write32(*loc32, _swap, (targetAddress - (fixupAddress + 5)) + addend);
+    break;
+  case ripRel32Minus2:
+    write32(*loc32, _swap, (targetAddress - (fixupAddress + 6)) + addend);
+    break;
+  case ripRel32Minus4:
+    write32(*loc32, _swap, (targetAddress - (fixupAddress + 8)) + addend);
+    break;
+  case delta32:
+  case delta32Anon:
+    write32(*loc32, _swap, (targetAddress - fixupAddress) + addend);
+    break;
+  case delta64:
+  case delta64Anon:
+    write64(*loc64, _swap, (targetAddress - fixupAddress) + addend);
+    break;
+  case ripRel32GotLoadNowLea:
+    // Change MOVQ to LEA
+    assert(location[-2] == 0x8B);
+    location[-2] = 0x8D;
+    write32(*loc32, _swap, (targetAddress - (fixupAddress + 4)) + addend);
+    break;
+  case lazyPointer:
+  case lazyImmediateLocation:
+    // do nothing
+    break;
+  default:
+    llvm_unreachable("invalid x86_64 Reference Kind");
+    break;
+  }
+}
+
+std::unique_ptr<mach_o::ArchHandler> ArchHandler::create_x86_64() {
+  return std::unique_ptr<mach_o::ArchHandler>(new ArchHandler_x86_64());
+}
+
+} // namespace mach_o
+} // namespace lld
index 51a1f20..d0076c9 100644 (file)
@@ -1,4 +1,8 @@
 add_lld_library(lldMachO
+  ArchHandler.cpp
+  ArchHandler_arm.cpp
+  ArchHandler_x86.cpp
+  ArchHandler_x86_64.cpp
   GOTPass.cpp
   MachOLinkingContext.cpp
   MachONormalizedFileBinaryReader.cpp
@@ -6,7 +10,6 @@ add_lld_library(lldMachO
   MachONormalizedFileFromAtoms.cpp
   MachONormalizedFileToAtoms.cpp
   MachONormalizedFileYAML.cpp
-  ReferenceKinds.cpp
   StubsPass.cpp
   WriterMachO.cpp
   )
index 94d4fad..e12b881 100644 (file)
@@ -31,15 +31,22 @@ namespace mach_o {
 class CRuntimeFile : public SimpleFile {
 public:
   CRuntimeFile(const MachOLinkingContext &context)
-      : SimpleFile("C runtime"), _undefMain(*this, context.entrySymbolName()) {
+      : SimpleFile("C runtime"), 
+       _undefMain(*this, context.entrySymbolName()),
+       _undefBinder(*this, context.binderSymbolName()) {
       // only main executables need _main
       if (context.outputMachOType() == llvm::MachO::MH_EXECUTE) {
         this->addAtom(_undefMain);
       }
+      // only dynamic binaries use stubs
+      if (context.needsStubsPass()) {
+        this->addAtom(_undefBinder);
+      }
    }
 
 private:
   SimpleUndefinedAtom   _undefMain;
+  SimpleUndefinedAtom   _undefBinder;
 };
 
 } // namespace mach_o
index 0cafc4c..dffc149 100644 (file)
 #ifndef LLD_READER_WRITER_MACHO_FILE_H
 #define LLD_READER_WRITER_MACHO_FILE_H
 
-#include "llvm/ADT/StringMap.h"
-
 #include "Atoms.h"
+#include "MachONormalizedFile.h"
 
 #include "lld/Core/Simple.h"
 #include "lld/Core/SharedLibraryFile.h"
 
+#include "llvm/ADT/StringMap.h"
+
 #include <unordered_map>
 
 namespace lld {
@@ -138,6 +139,8 @@ public:
     return pos->second;
   }
   
+  llvm::BumpPtrAllocator &allocator() { return _allocator; }
+  
 private:
   struct SectionOffsetAndAtom { uint64_t offset;  MachODefinedAtom *atom; };
 
index 1d5c6ee..d4cbaf0 100644 (file)
 ///
 //===----------------------------------------------------------------------===//
 
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+
 #include "lld/Core/DefinedAtom.h"
 #include "lld/Core/File.h"
 #include "lld/Core/LLVM.h"
 #include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+
 #include "llvm/ADT/DenseMap.h"
 
-#include "MachOPasses.h"
 
 namespace lld {
+namespace mach_o {
+
+
+//
+//  GOT Entry Atom created by the GOT pass.
+//
+class GOTEntryAtom : public SimpleDefinedAtom {
+public:
+  GOTEntryAtom(const File &file, bool is64) 
+    : SimpleDefinedAtom(file), _is64(is64) { }
 
-static bool shouldReplaceTargetWithGOTAtom(const Atom *target,
-                                           bool canBypassGOT) {
-  // Accesses to shared library symbols must go through GOT.
-  if (target->definition() == Atom::definitionSharedLibrary)
-    return true;
-  // Accesses to interposable symbols in same linkage unit must also go
-  // through GOT.
-  const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
-  if (defTarget != nullptr &&
-      defTarget->interposable() != DefinedAtom::interposeNo) {
-    assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
-    return true;
+  ContentType contentType() const override {
+    return DefinedAtom::typeGOT;
   }
-  // Target does not require indirection.  So, if instruction allows GOT to be
-  // by-passed, do that optimization and don't create GOT entry.
-  return !canBypassGOT;
-}
 
-static const DefinedAtom *
-findGOTAtom(const Atom *target,
-            llvm::DenseMap<const Atom *, const DefinedAtom *> &targetToGOT) {
-  auto pos = targetToGOT.find(target);
-  return (pos == targetToGOT.end()) ? nullptr : pos->second;
-}
+  Alignment alignment() const override {
+    return Alignment(_is64 ? 3 : 2);
+  }
 
-void GOTPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
-  // Use map so all pointers to same symbol use same GOT entry.
-  llvm::DenseMap<const Atom*, const DefinedAtom*> targetToGOT;
-
-  // Scan all references in all atoms.
-  for (const DefinedAtom *atom : mergedFile->defined()) {
-    for (const Reference *ref : *atom) {
-      // Look at instructions accessing the GOT.
-      bool canBypassGOT;
-      if (!isGOTAccess(*ref, canBypassGOT))
-        continue;
-      const Atom *target = ref->target();
-      assert(target != nullptr);
-
-      if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) {
-        // Update reference kind to reflect that target is a direct accesss.
-        updateReferenceToGOT(ref, false);
-        continue;
-      }
-      // Replace the target with a reference to a GOT entry.
-      const DefinedAtom *gotEntry = findGOTAtom(target, targetToGOT);
-      if (!gotEntry) {
-        gotEntry = makeGOTEntry(*target);
-        assert(gotEntry != nullptr);
-        assert(gotEntry->contentType() == DefinedAtom::typeGOT);
-        targetToGOT[target] = gotEntry;
+  uint64_t size() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permRW_;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t zeros[] =
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return llvm::makeArrayRef(zeros, size());
+  }
+
+private:
+  const bool _is64;
+};
+
+
+/// Pass for instantiating and optimizing GOT slots.
+/// 
+class GOTPass : public Pass {
+public:
+  GOTPass(const MachOLinkingContext &context)
+    : _context(context), _archHandler(_context.archHandler()),
+      _file("<mach-o GOT Pass>") { } 
+
+private:
+
+  void perform(std::unique_ptr<MutableFile> &mergedFile) override {
+    // Scan all references in all atoms.
+    for (const DefinedAtom *atom : mergedFile->defined()) {
+      for (const Reference *ref : *atom) {
+        // Look at instructions accessing the GOT.
+        bool canBypassGOT;
+        if (!_archHandler.isGOTAccess(*ref, canBypassGOT))
+          continue;
+        const Atom *target = ref->target();
+        assert(target != nullptr);
+
+        if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) {
+          // Update reference kind to reflect that target is a direct accesss.
+          _archHandler.updateReferenceToGOT(ref, false);
+        } else {
+          // Replace the target with a reference to a GOT entry.
+          const DefinedAtom *gotEntry = makeGOTEntry(target);
+          const_cast<Reference *>(ref)->setTarget(gotEntry);
+          // Update reference kind to reflect that target is now a GOT entry.
+          _archHandler.updateReferenceToGOT(ref, true);
+        }
       }
-      const_cast<Reference *>(ref)->setTarget(gotEntry);
-      // Update reference kind to reflect that target is now a GOT entry.
-      updateReferenceToGOT(ref, true);
     }
+
+    // add all created GOT Atoms to master file
+    for (auto &it : _targetToGOT)
+      mergedFile->addAtom(*it.second);
+  }
+
+  bool shouldReplaceTargetWithGOTAtom(const Atom *target, bool canBypassGOT) {
+    // Accesses to shared library symbols must go through GOT.
+    if (target->definition() == Atom::definitionSharedLibrary)
+      return true;
+    // Accesses to interposable symbols in same linkage unit must also go
+    // through GOT.
+    const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
+    if (defTarget != nullptr &&
+        defTarget->interposable() != DefinedAtom::interposeNo) {
+      assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+      return true;
+    }
+    // Target does not require indirection.  So, if instruction allows GOT to be
+    // by-passed, do that optimization and don't create GOT entry.
+    return !canBypassGOT;
+  }
+  
+  const DefinedAtom *makeGOTEntry(const Atom *target) {
+    auto pos = _targetToGOT.find(target);
+    if (pos == _targetToGOT.end()) {
+      GOTEntryAtom *gotEntry = new (_file.allocator()) 
+                                        GOTEntryAtom(_file, _context.is64Bit());
+      _targetToGOT[target] = gotEntry;
+      const ArchHandler::ReferenceInfo &nlInfo = _archHandler.stubInfo().
+                                                nonLazyPointerReferenceToBinder;
+      gotEntry->addReference(Reference::KindNamespace::mach_o, nlInfo.arch,
+                             nlInfo.kind, 0, target, 0);
+      return gotEntry;
+    }
+    return pos->second;
   }
 
-  // add all created GOT Atoms to master file
-  for (auto &it : targetToGOT)
-    mergedFile->addAtom(*it.second);
+  
+  const MachOLinkingContext                       &_context;
+  mach_o::ArchHandler                             &_archHandler;
+  MachOFile                                        _file;
+  llvm::DenseMap<const Atom*, const GOTEntryAtom*> _targetToGOT;
+};
+
+
+
+void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  assert(ctx.needsGOTPass());
+  pm.add(std::unique_ptr<Pass>(new GOTPass(ctx)));
 }
+  
 
+} // end namesapce mach_o
 } // end namesapce lld
index a7ab254..be3a789 100644 (file)
@@ -24,27 +24,6 @@ namespace lld {
 namespace mach_o {
 
 
-class GOTPass : public lld::GOTPass {
-public:
-  bool noTextRelocs() override {
-    return true;
-  }
-
-  bool isGOTAccess(const Reference &, bool &canBypassGOT) override {
-    return false;
-  }
-
-  void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) override {
-
-  }
-
-  const DefinedAtom* makeGOTEntry(const Atom&) override {
-    return nullptr;
-  }
-
-};
-
-
 } // namespace mach_o
 } // namespace lld
 
index 379d621..c05772b 100644 (file)
@@ -8,9 +8,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "lld/ReaderWriter/MachOLinkingContext.h"
-#include "GOTPass.hpp"
-#include "StubsPass.hpp"
-#include "ReferenceKinds.h"
+
+#include "ArchHandler.h"
+#include "MachOPasses.h"
 
 #include "lld/Core/PassManager.h"
 #include "lld/ReaderWriter/Reader.h"
@@ -25,7 +25,7 @@
 #include "llvm/Support/MachO.h"
 #include "llvm/Support/Path.h"
 
-using lld::mach_o::KindHandler;
+using lld::mach_o::ArchHandler;
 using namespace llvm::MachO;
 
 namespace lld {
@@ -125,7 +125,7 @@ MachOLinkingContext::MachOLinkingContext()
       _doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),
       _pageZeroSize(0), _pageSize(4096), _compatibilityVersion(0),
       _currentVersion(0), _deadStrippableDylib(false), _printAtoms(false),
-      _testingLibResolution(false), _kindHandler(nullptr) {}
+      _testingLibResolution(false), _archHandler(nullptr) {}
 
 MachOLinkingContext::~MachOLinkingContext() {}
 
@@ -223,6 +223,33 @@ bool MachOLinkingContext::outputTypeHasEntry() const {
   }
 }
 
+bool MachOLinkingContext::needsStubsPass() const {
+  switch (_outputMachOType) {
+  case MH_EXECUTE:
+    return !_outputMachOTypeStatic;
+  case MH_DYLIB:
+  case MH_BUNDLE:
+    return true;
+  default:
+    return false;
+  }
+}
+
+bool MachOLinkingContext::needsGOTPass() const {
+  // Only x86_64 uses GOT pass but not in -r mode.
+  if (_arch != arch_x86_64)
+    return false;
+  return (_outputMachOType != MH_OBJECT);
+}
+
+
+StringRef MachOLinkingContext::binderSymbolName() const {
+  return archHandler().stubInfo().binderSymbolName;
+}
+
+
+
+
 bool MachOLinkingContext::minOS(StringRef mac, StringRef iOS) const {
   uint32_t parsedVersion;
   switch (_os) {
@@ -375,11 +402,11 @@ bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
 }
 
 void MachOLinkingContext::addPasses(PassManager &pm) {
-  if (outputMachOType() != MH_OBJECT) {
-    pm.add(std::unique_ptr<Pass>(new mach_o::GOTPass));
-    pm.add(std::unique_ptr<Pass>(new mach_o::StubsPass(*this)));
-  }
   pm.add(std::unique_ptr<Pass>(new LayoutPass(registry())));
+  if (needsStubsPass())
+    mach_o::addStubsPass(pm, *this);
+  if (needsGOTPass())
+    mach_o::addGOTPass(pm, *this);
 }
 
 Writer &MachOLinkingContext::writer() const {
@@ -388,10 +415,10 @@ Writer &MachOLinkingContext::writer() const {
   return *_writer;
 }
 
-KindHandler &MachOLinkingContext::kindHandler() const {
-  if (!_kindHandler)
-    _kindHandler = KindHandler::create(_arch);
-  return *_kindHandler;
+ArchHandler &MachOLinkingContext::archHandler() const {
+  if (!_archHandler)
+    _archHandler = ArchHandler::create(_arch);
+  return *_archHandler;
 }
 
 
index 7c59915..c96f325 100644 (file)
 ///                  +------------+
 
 #include "MachONormalizedFile.h"
+
+#include "ArchHandler.h"
 #include "MachONormalizedFileBinaryUtils.h"
-#include "ReferenceKinds.h"
+
 #include "lld/Core/Error.h"
 #include "lld/Core/LLVM.h"
 #include "llvm/ADT/SmallString.h"
@@ -442,27 +444,11 @@ private:
 } // namespace normalized
 } // namespace mach_o
 
-void Registry::addSupportMachOObjects(StringRef archName) {
-  MachOLinkingContext::Arch arch = MachOLinkingContext::archFromName(archName);
+void Registry::addSupportMachOObjects(const MachOLinkingContext &ctx) {
+  MachOLinkingContext::Arch arch = ctx.arch();
   add(std::unique_ptr<Reader>(new mach_o::normalized::MachOReader(arch)));
-  switch (arch) {
-  case MachOLinkingContext::arch_x86_64:
-    addKindTable(Reference::KindNamespace::mach_o, Reference::KindArch::x86_64,
-                 mach_o::KindHandler_x86_64::kindStrings);
-    break;
-  case MachOLinkingContext::arch_x86:
-    addKindTable(Reference::KindNamespace::mach_o, Reference::KindArch::x86,
-                 mach_o::KindHandler_x86::kindStrings);
-    break;
-  case MachOLinkingContext::arch_armv6:
-  case MachOLinkingContext::arch_armv7:
-  case MachOLinkingContext::arch_armv7s:
-    addKindTable(Reference::KindNamespace::mach_o, Reference::KindArch::ARM,
-                 mach_o::KindHandler_arm::kindStrings);
-    break;
-  default:
-    llvm_unreachable("mach-o arch not supported");
-  }
+  addKindTable(Reference::KindNamespace::mach_o, ctx.archHandler().kindArch(), 
+               ctx.archHandler().kindStrings());
   add(std::unique_ptr<YamlIOTaggedDocumentHandler>(
                            new mach_o::MachOYamlIOTaggedDocumentHandler(arch)));
 }
index 5a61314..fcc1879 100644 (file)
@@ -194,7 +194,17 @@ inline uint64_t read64(bool swap, uint64_t value) {
     return (swap ? getSwappedBytes(value) : value);
 }
 
+inline void write16(int16_t &loc, bool swap, int16_t value) {
+    loc = (swap ? getSwappedBytes(value) : value);
+}
+
+inline void write32(int32_t &loc, bool swap, int32_t value) {
+    loc = (swap ? getSwappedBytes(value) : value);
+}
 
+inline void write64(uint64_t &loc, bool swap, uint64_t value) {
+    loc = (swap ? getSwappedBytes(value) : value);
+}
 
 inline uint32_t
 bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit,
index 3befd6a..0a30680 100644 (file)
 ///                    +-------+
 
 #include "MachONormalizedFile.h"
+
+#include "ArchHandler.h"
 #include "MachONormalizedFileBinaryUtils.h"
-#include "ReferenceKinds.h"
+
 #include "lld/Core/Error.h"
 #include "lld/Core/LLVM.h"
 #include "llvm/ADT/StringRef.h"
@@ -542,7 +544,7 @@ void Util::appendSection(SectionInfo *si, NormalizedFile &file) {
         // FIXME: Need a handler method to update content for .o file
         // output and any needed section relocations.
       } else {
-        _context.kindHandler().applyFixup(
+        _context.archHandler().applyFixup(
           ref->kindNamespace(), ref->kindArch(), ref->kindValue(),
           ref->addend(), &atomContent[offset], fixupAddress, targetAddress,
           atomAddress);
@@ -713,7 +715,7 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
 
 const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) {
   for (const Reference *ref : *lpAtom) {
-    if (_context.kindHandler().isLazyTarget(*ref)) {
+    if (_context.archHandler().isLazyPointer(*ref)) {
       return ref->target();
     }
   }
@@ -871,7 +873,7 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
         uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom()
                                 - segmentStartAddr;
         const Atom* targ = ref->target();
-        if (_context.kindHandler().isPointer(*ref)) {
+        if (_context.archHandler().isPointer(*ref)) {
           // A pointer to a DefinedAtom requires rebasing.
           if (dyn_cast<DefinedAtom>(targ)) {
             RebaseLocation rebase;
@@ -893,7 +895,7 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
             nFile.bindingInfo.push_back(bind);
           }
         }
-        if (_context.kindHandler().isLazyTarget(*ref)) {
+        if (_context.archHandler().isLazyPointer(*ref)) {
             BindLocation bind;
             bind.segIndex = segmentIndex;
             bind.segOffset = segmentOffset;
index 7e8f6c3..cc0289e 100644 (file)
 ///                    +-------+
 
 #include "MachONormalizedFile.h"
-#include "MachONormalizedFileBinaryUtils.h"
-#include "File.h"
+
+#include "ArchHandler.h"
 #include "Atoms.h"
-#include "ReferenceKinds.h"
+#include "File.h"
+#include "MachONormalizedFileBinaryUtils.h"
 
 #include "lld/Core/Error.h"
 #include "lld/Core/LLVM.h"
@@ -431,8 +432,8 @@ std::error_code processSection(DefinedAtom::ContentType atomType,
 std::error_code convertRelocs(const Section &section,
                               const NormalizedFile &normalizedFile,
                               MachOFile &file,
-                              KindHandler &handler) {
-  // Utility function for KindHandler to find atom by its address.
+                              ArchHandler &handler) {
+  // Utility function for ArchHandler to find atom by its address.
   auto atomByAddr = [&] (uint32_t sectIndex, uint64_t addr,
                          const lld::Atom **atom, Reference::Addend *addend)
                          -> std::error_code {
@@ -462,7 +463,7 @@ std::error_code convertRelocs(const Section &section,
     return std::error_code();
   };
 
-  // Utility function for KindHandler to find atom by its symbol index.
+  // Utility function for ArchHandler to find atom by its symbol index.
   auto atomBySymbol = [&] (uint32_t symbolIndex, const lld::Atom **result)
                            -> std::error_code {
     // Find symbol from index.
@@ -536,7 +537,7 @@ std::error_code convertRelocs(const Section &section,
                                                &target, &addend);
     }
     else {
-      // Use KindHandler to convert relocation record into information
+      // Use ArchHandler to convert relocation record into information
       // needed to instantiate an lld::Reference object.
       relocErr = handler.getReferenceInfo(reloc, inAtom, offsetInAtom,
                                           fixupAddress,swap, atomByAddr,
@@ -558,27 +559,8 @@ std::error_code convertRelocs(const Section &section,
          + ")" );
     } else {
       // Instantiate an lld::Reference object and add to its atom.
-      Reference::KindArch arch = Reference::KindArch::all;
-      switch (normalizedFile.arch ) {
-      case lld::MachOLinkingContext::arch_x86_64:
-        arch = Reference::KindArch::x86_64;
-        break;
-      case lld::MachOLinkingContext::arch_x86:
-        arch = Reference::KindArch::x86;
-        break;
-      case lld::MachOLinkingContext::arch_ppc:
-        arch = Reference::KindArch::PowerPC;
-        break;
-      case lld::MachOLinkingContext::arch_armv6:
-      case lld::MachOLinkingContext::arch_armv7:
-      case lld::MachOLinkingContext::arch_armv7s:
-        arch = Reference::KindArch::ARM;
-        break;
-      case lld::MachOLinkingContext::arch_unknown:
-        return make_dynamic_error_code(Twine("unknown architecture"));
-      }
-      
-      inAtom->addReference(offsetInAtom, kind, target, addend, arch);
+      inAtom->addReference(offsetInAtom, kind, target, addend, 
+                           handler.kindArch());
     }
   }
   return std::error_code();
@@ -616,8 +598,8 @@ normalizedObjectToAtoms(const NormalizedFile &normalizedFile, StringRef path,
   }
 
   // Convert mach-o relocations to References
-  std::unique_ptr<mach_o::KindHandler> handler
-                                     = KindHandler::create(normalizedFile.arch);
+  std::unique_ptr<mach_o::ArchHandler> handler
+                                     = ArchHandler::create(normalizedFile.arch);
   for (auto &sect : normalizedFile.sections) {
     if (isDebugInfoSection(sect))
       continue;
index d55fdf5..116563b 100644 (file)
 #ifndef LLD_READER_WRITER_MACHO_PASSES_H
 #define LLD_READER_WRITER_MACHO_PASSES_H
 
-#include "lld/Core/Atom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/range.h"
-#include "lld/Core/Reference.h"
-
-#include <vector>
+#include "lld/Core/PassManager.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
 
 namespace lld {
-class DefinedAtom;
-class MutableFile;
-
-
-/// Pass for adding stubs (PLT entries) for calls to functions
-/// outside the linkage unit.  This class is subclassed by each
-/// file format Writer which implements the pure virtual methods.
-class StubsPass : public Pass {
-public:
-  StubsPass() : Pass() {}
-
-  /// Scans all Atoms looking for call-site uses of SharedLibraryAtoms
-  /// and transfroms the call-site to call a stub instead using the
-  /// helper methods below.
-  void perform(std::unique_ptr<MutableFile> &mergedFile) override;
-
-  /// If true, the pass should use stubs for references
-  /// to shared library symbols. If false, the pass
-  /// will generate relocations on the text segment which the
-  /// runtime loader will use to patch the program at runtime.
-  virtual bool noTextRelocs() = 0;
-
-  /// Returns whether the Reference kind is for a call site.  The pass
-  /// uses this to find calls that need to be indirected through a stub.
-  virtual bool isCallSite(const Reference &) = 0;
-
-  /// Returns a file format specific atom for a stub/PLT entry which contains
-  /// instructions which jump to the specified atom.  May be called multiple
-  /// times for the same target atom, in which case this method should return
-  /// the same stub atom.
-  virtual const DefinedAtom *getStub(const Atom &target) = 0;
-
-  /// After the default implementation of perform() is done calling getStub(),
-  /// it will call this method to add all the stub (and support) atoms to the
-  /// master file object.
-  virtual void addStubAtoms(MutableFile &masterFile) = 0;
-
-private:
-  void replaceCalleeWithStub(const Atom *target, const Reference *ref);
-};
-
-/// Pass for adding GOT entries for pointers to functions/data
-/// outside the linkage unit. This class is subclassed by each
-/// file format Writer which implements the pure virtual methods.
-class GOTPass : public Pass {
-public:
-  GOTPass() : Pass() {}
-
-  /// Scans all Atoms looking for pointer to SharedLibraryAtoms
-  /// and transfroms them to a pointer to a GOT entry using the
-  /// helper methods below.
-  void perform(std::unique_ptr<MutableFile> &mergedFile) override;
-
-  /// If true, the pass will use GOT entries for references
-  /// to shared library symbols. If false, the pass
-  /// will generate relocations on the text segment which the
-  /// runtime loader will use to patch the program at runtime.
-  virtual bool noTextRelocs() = 0;
-
-  /// Returns whether the Reference kind is a pre-instantiated GOT access.
-  /// The default implementation of perform() uses this to figure out
-  /// what GOT entries to instantiate.
-  virtual bool isGOTAccess(const Reference &, bool &canBypassGOT) = 0;
-
-  /// The file format Writer needs to alter the reference kind from a
-  /// pre-instantiated GOT access to an actual access.  If targetIsNowGOT is
-  /// true, the pass has instantiated a GOT atom and altered the reference's
-  /// target to point to that atom.  If targetIsNowGOT is false, the pass
-  /// determined a GOT entry is not needed because the reference site can
-  /// directly access the target.
-  virtual void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) = 0;
+namespace mach_o {
 
-  /// Returns a file format specific atom for a GOT entry targeting
-  /// the specified atom.
-  virtual const DefinedAtom *makeGOTEntry(const Atom &target) = 0;
-};
+void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx);
+void addGOTPass(PassManager &pm, const MachOLinkingContext &ctx);
 
+} // namespace mach_o
 } // namespace lld
 
 #endif // LLD_READER_WRITER_MACHO_PASSES_H
diff --git a/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp b/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp
deleted file mode 100644 (file)
index da15cfe..0000000
+++ /dev/null
@@ -1,1100 +0,0 @@
-//===- lib/FileFormat/MachO/ReferenceKinds.cpp ----------------------===//
-//
-//                             The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-
-#include "ReferenceKinds.h"
-#include "MachONormalizedFileBinaryUtils.h"
-#include "Atoms.h"
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
-
-#include "llvm/Support/ErrorHandling.h"
-
-using namespace llvm::MachO;
-using namespace lld::mach_o::normalized;
-
-namespace lld {
-namespace mach_o {
-
-//===----------------------------------------------------------------------===//
-//  KindHandler
-//===----------------------------------------------------------------------===//
-
-KindHandler::KindHandler() {
-}
-
-KindHandler::~KindHandler() {
-}
-
-std::unique_ptr<mach_o::KindHandler>
-KindHandler::create(MachOLinkingContext::Arch arch) {
-  switch (arch) {
-  case MachOLinkingContext::arch_x86_64:
-    return std::unique_ptr<mach_o::KindHandler>(new KindHandler_x86_64());
-  case MachOLinkingContext::arch_x86:
-    return std::unique_ptr<mach_o::KindHandler>(new KindHandler_x86());
-    case MachOLinkingContext::arch_armv6:
-    case MachOLinkingContext::arch_armv7:
-    case MachOLinkingContext::arch_armv7s:
-      return std::unique_ptr<mach_o::KindHandler>(new KindHandler_arm());
-    default:
-      llvm_unreachable("Unknown arch");
-  }
-}
-
-KindHandler::RelocPattern KindHandler::relocPattern(const Relocation &reloc) {
-  assert((reloc.type & 0xFFF0) == 0);
-  uint16_t result = reloc.type;
-  if (reloc.scattered)
-    result |= rScattered;
-  if (reloc.pcRel)
-    result |= rPcRel;
-  if (reloc.isExtern)
-    result |= rExtern;
-  switch(reloc.length) {
-  case 0:
-    break;
-  case 1:
-    result |= rLength2;
-    break;
-  case 2:
-    result |= rLength4;
-    break;
-  case 3:
-    result |= rLength8;
-    break;
-  default:
-    llvm_unreachable("bad r_length");
-  }
-  return result;
-}
-
-int16_t KindHandler::readS16(bool swap, const uint8_t *addr) {
-  return read16(swap, *reinterpret_cast<const uint16_t*>(addr));
-}
-
-int32_t KindHandler::readS32(bool swap, const uint8_t *addr) {
-  return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
-}
-
-uint32_t KindHandler::readU32(bool swap, const uint8_t *addr) {
-  return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
-}
-
-int64_t KindHandler::readS64(bool swap, const uint8_t *addr) {
-  return read64(swap, *reinterpret_cast<const uint64_t*>(addr));
-}
-
-
-//===----------------------------------------------------------------------===//
-//  KindHandler_x86_64
-//===----------------------------------------------------------------------===//
-
-KindHandler_x86_64::~KindHandler_x86_64() {
-}
-
-const Registry::KindStrings KindHandler_x86_64::kindStrings[] = {
-  LLD_KIND_STRING_ENTRY(invalid),
-  LLD_KIND_STRING_ENTRY(branch32),
-  LLD_KIND_STRING_ENTRY(ripRel32),
-  LLD_KIND_STRING_ENTRY(ripRel32Minus1),
-  LLD_KIND_STRING_ENTRY(ripRel32Minus2),
-  LLD_KIND_STRING_ENTRY(ripRel32Minus4),
-  LLD_KIND_STRING_ENTRY(ripRel32Anon),
-  LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
-  LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
-  LLD_KIND_STRING_ENTRY(ripRel32Got),
-  LLD_KIND_STRING_ENTRY(lazyPointer),
-  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
-  LLD_KIND_STRING_ENTRY(pointer64),
-  LLD_KIND_STRING_ENTRY(pointer64Anon),
-  LLD_KIND_STRING_ENTRY(delta32),
-  LLD_KIND_STRING_ENTRY(delta64),
-  LLD_KIND_STRING_ENTRY(delta32Anon),
-  LLD_KIND_STRING_ENTRY(delta64Anon),
-  LLD_KIND_STRING_END
-};
-
-bool KindHandler_x86_64::isCallSite(const Reference &ref) {
-  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
-    return false;
-  assert(ref.kindArch() == Reference::KindArch::x86_64);
-  return (ref.kindValue() == branch32);
-}
-
-bool KindHandler_x86_64::isPointer(const Reference &ref) {
-  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
-    return false;
-  assert(ref.kindArch() == Reference::KindArch::x86_64);
-  Reference::KindValue kind = ref.kindValue();
-  return (kind == pointer64 || kind == pointer64Anon);
-}
-
-bool KindHandler_x86_64::isLazyImmediate(const Reference &ref) {
-  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
-    return false;
-  assert(ref.kindArch() == Reference::KindArch::x86_64);
-  return (ref.kindValue() == lazyImmediateLocation);
-}
-
-bool KindHandler_x86_64::isLazyTarget(const Reference &ref) {
-  if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
-    return false;
-  assert(ref.kindArch() == Reference::KindArch::x86_64);
-  return (ref.kindValue() == lazyPointer);
-}
-
-bool KindHandler_x86_64::isPairedReloc(const Relocation &reloc) {
-  return (reloc.type == X86_64_RELOC_SUBTRACTOR);
-}
-
-
-Reference::KindValue 
-KindHandler_x86_64::kindFromReloc(const Relocation &reloc) {
-  switch(relocPattern(reloc)) {
-  case X86_64_RELOC_BRANCH   | rPcRel | rExtern | rLength4:
-    return branch32;
-  case X86_64_RELOC_SIGNED   | rPcRel | rExtern | rLength4:
-    return ripRel32;
-  case X86_64_RELOC_SIGNED   | rPcRel |           rLength4:
-    return ripRel32Anon;
-  case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4:
-    return ripRel32Minus1;
-  case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4:
-    return ripRel32Minus2;
-  case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
-    return ripRel32Minus4;
-  case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4:
-    return ripRel32GotLoad;
-  case X86_64_RELOC_GOT      | rPcRel | rExtern | rLength4:
-    return ripRel32Got;
-  case X86_64_RELOC_UNSIGNED          | rExtern | rLength8:
-    return pointer64;
-  case X86_64_RELOC_UNSIGNED                    | rLength8:
-    return pointer64Anon;
-  default:
-    return invalid;
-  }
-
-}
-
-
-std::error_code 
-KindHandler_x86_64::getReferenceInfo(const Relocation &reloc,
-                                    const DefinedAtom *inAtom,
-                                    uint32_t offsetInAtom,
-                                    uint64_t fixupAddress, bool swap,
-                                    FindAtomBySectionAndAddress atomFromAddress,
-                                    FindAtomBySymbolIndex atomFromSymbolIndex,
-                                    Reference::KindValue *kind, 
-                                    const lld::Atom **target, 
-                                    Reference::Addend *addend) {
-  typedef std::error_code E;
-  *kind = kindFromReloc(reloc);
-  if (*kind == invalid)
-    return make_dynamic_error_code(Twine("unknown type"));
-  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
-  uint64_t targetAddress;
-  switch (*kind) {
-  case branch32:
-  case ripRel32:
-    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
-      return ec;
-    *addend = readS32(swap, fixupContent);
-    return std::error_code();
-  case ripRel32Minus1:
-    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
-      return ec;
-    *addend = readS32(swap, fixupContent) + 1;
-    return std::error_code();
-  case ripRel32Minus2:
-    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
-      return ec;
-    *addend = readS32(swap, fixupContent) + 2;
-    return std::error_code();
-  case ripRel32Minus4:
-    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
-      return ec;
-    *addend = readS32(swap, fixupContent) + 4;
-    return std::error_code();
-  case ripRel32Anon:
-    targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
-    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
-  case ripRel32GotLoad:
-  case ripRel32Got:
-    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
-      return ec;
-    *addend = 0;
-    return std::error_code();
-  case pointer64:
-    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
-      return ec;
-    *addend = readS64(swap, fixupContent);
-    return std::error_code();
-  case pointer64Anon:
-    targetAddress = readS64(swap, fixupContent);
-    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
-  default:
-    llvm_unreachable("bad reloc kind");
-  }
-}
-
-
-Reference::KindValue 
-KindHandler_x86_64::kindFromRelocPair(const normalized::Relocation &reloc1,
-                                      const normalized::Relocation &reloc2) {
-  switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
-  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
-        X86_64_RELOC_UNSIGNED    | rExtern | rLength8):
-    return delta64;
-  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
-        X86_64_RELOC_UNSIGNED    | rExtern | rLength4):
-    return delta32;
-  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
-        X86_64_RELOC_UNSIGNED              | rLength8):
-    return delta64Anon;
-  case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
-        X86_64_RELOC_UNSIGNED              | rLength4):
-    return delta32Anon;
-  default:
-    llvm_unreachable("bad reloc pairs");
-  }
-}
-
-
-std::error_code 
-KindHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
-                                   const normalized::Relocation &reloc2,
-                                   const DefinedAtom *inAtom,
-                                   uint32_t offsetInAtom,
-                                   uint64_t fixupAddress, bool swap,
-                                   FindAtomBySectionAndAddress atomFromAddress,
-                                   FindAtomBySymbolIndex atomFromSymbolIndex,
-                                   Reference::KindValue *kind, 
-                                   const lld::Atom **target, 
-                                   Reference::Addend *addend) {
-  *kind = kindFromRelocPair(reloc1, reloc2);
-  if (*kind == invalid)
-    return make_dynamic_error_code(Twine("unknown pair"));
-  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
-  typedef std::error_code E;
-  uint64_t targetAddress;
-  const lld::Atom *fromTarget;
-  if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
-    return ec;
-  if (fromTarget != inAtom)
-    return make_dynamic_error_code(Twine("pointer diff not in base atom"));
-  switch (*kind) {
-  case delta64:
-    if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
-      return ec;
-    *addend = readS64(swap, fixupContent) + offsetInAtom;
-    return std::error_code();
-  case delta32:
-    if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
-      return ec;
-    *addend = readS32(swap, fixupContent) + offsetInAtom;
-    return std::error_code();
-  case delta64Anon:
-    targetAddress = offsetInAtom + readS64(swap, fixupContent);
-    return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
-  case delta32Anon:
-    targetAddress = offsetInAtom + readS32(swap, fixupContent);
-    return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
-  default:
-    llvm_unreachable("bad reloc pair kind");
-  }
-}
-
-
-
-void KindHandler_x86_64::applyFixup(Reference::KindNamespace ns,
-                                    Reference::KindArch arch,
-                                    Reference::KindValue kindValue,
-                                    uint64_t addend, uint8_t *location,
-                                    uint64_t fixupAddress,
-                                    uint64_t targetAddress,
-                                    uint64_t inAtomAddress) {
-  if (ns != Reference::KindNamespace::mach_o)
-    return;
-  assert(arch == Reference::KindArch::x86_64);
-  int32_t *loc32 = reinterpret_cast<int32_t*>(location);
-  uint64_t* loc64 = reinterpret_cast<uint64_t*>(location);
-  switch (kindValue) {
-  case branch32:
-  case ripRel32:
-  case ripRel32Got:
-  case ripRel32GotLoad:
-    *loc32 = (targetAddress - (fixupAddress+4)) + addend;
-    break;
-  case pointer64:
-  case pointer64Anon:
-    *loc64 = targetAddress + addend;
-    break;
-  case ripRel32Minus1:
-    *loc32 = (targetAddress - (fixupAddress+5)) + addend;
-    break;
-  case ripRel32Minus2:
-    *loc32 = (targetAddress - (fixupAddress+6)) + addend;
-    break;
-  case ripRel32Minus4:
-    *loc32 = (targetAddress - (fixupAddress+8)) + addend;
-    break;
-  case delta32:
-  case delta32Anon:
-   *loc32 = (targetAddress - fixupAddress) + addend;
-    break;
-  case delta64:
-  case delta64Anon:
-    *loc64 = (targetAddress - fixupAddress) + addend;
-    break;
-  case ripRel32GotLoadNowLea:
-    // Change MOVQ to LEA
-    assert(location[-2] == 0x8B);
-    location[-2] = 0x8D;
-    *loc32 = (targetAddress - (fixupAddress+4)) + addend;
-    break;
-  case lazyPointer:
-  case lazyImmediateLocation:
-    // do nothing
-    break;
-  default:
-    llvm_unreachable("invalid x86_64 Reference Kind");
-      break;
-  }
-}
-
-
-//===----------------------------------------------------------------------===//
-//  KindHandler_x86
-//===----------------------------------------------------------------------===//
-
-KindHandler_x86::~KindHandler_x86() {
-}
-
-const Registry::KindStrings KindHandler_x86::kindStrings[] = {
-  LLD_KIND_STRING_ENTRY(invalid),
-  LLD_KIND_STRING_ENTRY(branch32),
-  LLD_KIND_STRING_ENTRY(branch16),
-  LLD_KIND_STRING_ENTRY(abs32),
-  LLD_KIND_STRING_ENTRY(funcRel32),
-  LLD_KIND_STRING_ENTRY(pointer32),
-  LLD_KIND_STRING_ENTRY(delta32),
-  LLD_KIND_STRING_ENTRY(lazyPointer),
-  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
-  LLD_KIND_STRING_END
-};
-
-bool KindHandler_x86::isCallSite(const Reference &ref) {
-  return (ref.kindValue() == branch32);
-}
-
-bool KindHandler_x86::isPointer(const Reference &ref) {
-  return (ref.kindValue() == pointer32);
-}
-
-bool KindHandler_x86::isLazyImmediate(const Reference &ref) {
-  return (ref.kindValue() == lazyImmediateLocation);
-}
-
-bool KindHandler_x86::isLazyTarget(const Reference &ref) {
-  return (ref.kindValue() == lazyPointer);
-}
-
-
-bool KindHandler_x86::isPairedReloc(const Relocation &reloc) {
-  if (!reloc.scattered)
-    return false;
-  return (reloc.type == GENERIC_RELOC_LOCAL_SECTDIFF) || 
-         (reloc.type == GENERIC_RELOC_SECTDIFF);
-}
-
-
-std::error_code
-KindHandler_x86::getReferenceInfo(const Relocation &reloc,
-                                  const DefinedAtom *inAtom,
-                                  uint32_t offsetInAtom,
-                                  uint64_t fixupAddress, bool swap,
-                                  FindAtomBySectionAndAddress atomFromAddress,
-                                  FindAtomBySymbolIndex atomFromSymbolIndex,
-                                  Reference::KindValue *kind,
-                                  const lld::Atom **target,
-                                  Reference::Addend *addend) {
-  typedef std::error_code E;
-  DefinedAtom::ContentPermissions perms;
-  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
-  uint64_t targetAddress;
-  switch (relocPattern(reloc)) {
-  case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength4:
-    // ex: call _foo (and _foo undefined)
-    *kind = branch32;
-    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
-      return ec;
-    *addend = fixupAddress + 4 + readS32(swap, fixupContent);
-    break;
-  case GENERIC_RELOC_VANILLA | rPcRel  | rLength4:
-    // ex: call _foo (and _foo defined)
-    *kind = branch32;
-    targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
-    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
-    break;
-  case GENERIC_RELOC_VANILLA | rPcRel | rExtern | rLength2:
-    // ex: callw _foo (and _foo undefined)
-    *kind = branch16;
-    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
-      return ec;
-    *addend = fixupAddress + 2 + readS16(swap, fixupContent);
-    break;
-  case GENERIC_RELOC_VANILLA | rPcRel  | rLength2:
-    // ex: callw _foo (and _foo defined)
-    *kind = branch16;
-    targetAddress = fixupAddress + 2 + readS16(swap, fixupContent);
-    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
-    break;
-  case GENERIC_RELOC_VANILLA  | rExtern | rLength4:
-    // ex: movl        _foo, %eax   (and _foo undefined)
-    // ex: .long _foo        (and _foo undefined)
-    perms = inAtom->permissions();
-    *kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
-                                                            ? abs32 : pointer32;
-    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
-      return ec;
-    *addend = readU32(swap, fixupContent);
-    break;
-  case GENERIC_RELOC_VANILLA  | rLength4:
-    // ex: movl        _foo, %eax   (and _foo defined)
-    // ex: .long _foo        (and _foo defined)
-    perms = inAtom->permissions();
-    *kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
-                                                            ? abs32 : pointer32;
-    targetAddress = readU32(swap, fixupContent);
-    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
-    break;
-  default:
-    return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
-  }
-  return std::error_code();
-}
-
-
-std::error_code
-KindHandler_x86::getPairReferenceInfo(const normalized::Relocation &reloc1,
-                                     const normalized::Relocation &reloc2,
-                                     const DefinedAtom *inAtom,
-                                     uint32_t offsetInAtom,
-                                     uint64_t fixupAddress, bool swap,
-                                     FindAtomBySectionAndAddress atomFromAddr,
-                                     FindAtomBySymbolIndex atomFromSymbolIndex,
-                                     Reference::KindValue *kind,
-                                     const lld::Atom **target,
-                                     Reference::Addend *addend) {
-  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
-  std::error_code ec;
-  DefinedAtom::ContentPermissions perms = inAtom->permissions();
-  uint32_t fromAddress;
-  uint32_t toAddress;
-  uint32_t value;
-  const lld::Atom *fromTarget;
-  Reference::Addend offsetInTo;
-  Reference::Addend offsetInFrom;
-  switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
-  case ((GENERIC_RELOC_SECTDIFF       | rScattered | rLength4) << 16 |
-         GENERIC_RELOC_PAIR           | rScattered | rLength4):
-  case ((GENERIC_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
-         GENERIC_RELOC_PAIR           | rScattered | rLength4):
-    toAddress = reloc1.value;
-    fromAddress = reloc2.value;
-    value = readS32(swap, fixupContent);
-    ec = atomFromAddr(0, toAddress, target, &offsetInTo);
-    if (ec)
-      return ec;
-    ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
-    if (ec)
-      return ec;
-    if (fromTarget != inAtom)
-      return make_dynamic_error_code(Twine("SECTDIFF relocation where "
-                                     "subtrahend label is not in atom"));
-    *kind = ((perms & DefinedAtom::permR_X) == DefinedAtom::permR_X)
-                                                          ? funcRel32 : delta32;
-    if (*kind == funcRel32) {
-      // SECTDIFF relocations are used in i386 codegen where the function
-      // prolog does a CALL to the next instruction which POPs the return
-      // address into EBX which becomes the pic-base register.  The POP 
-      // instruction is label the used for the subtrahend in expressions.
-      // The funcRel32 kind represents the 32-bit delta to some symbol from
-      // the start of the function (atom) containing the funcRel32.
-      uint32_t ta = fromAddress + value - toAddress;
-      *addend = ta - offsetInFrom;
-    } else {
-      *addend = fromAddress + value - toAddress;
-    }
-    return std::error_code();
-    break;
-  default:
-    return make_dynamic_error_code(Twine("unsupported i386 relocation type"));
-  }
-}
-
-void KindHandler_x86::applyFixup(Reference::KindNamespace ns,
-                                 Reference::KindArch arch,
-                                 Reference::KindValue kindValue,
-                                 uint64_t addend, uint8_t *location,
-                                 uint64_t fixupAddress,
-                                 uint64_t targetAddress,
-                                 uint64_t inAtomAddress) {
-  if (ns != Reference::KindNamespace::mach_o)
-    return;
-  assert(arch == Reference::KindArch::x86);
-  int32_t *loc32 = reinterpret_cast<int32_t*>(location);
-  int16_t *loc16 = reinterpret_cast<int16_t*>(location);
-  // FIXME: these writes may need a swap.
-  switch (kindValue) {
-  case branch32:
-      *loc32 = (targetAddress - (fixupAddress+4)) + addend;
-      break;
-  case branch16:
-      *loc16 = (targetAddress - (fixupAddress+4)) + addend;
-      break;
-  case pointer32:
-  case abs32:
-      *loc32 = targetAddress + addend;
-      break;
-  case funcRel32:
-      *loc32 = targetAddress - inAtomAddress + addend; // FIXME
-      break;
-  case delta32:
-      *loc32 = targetAddress - fixupAddress + addend;
-      break;
-  case lazyPointer:
-  case lazyImmediateLocation:
-      // do nothing
-      break;
-  default:
-    llvm_unreachable("invalid x86 Reference Kind");
-      break;
-  }
-}
-
-
-//===----------------------------------------------------------------------===//
-//  KindHandler_arm
-//===----------------------------------------------------------------------===//
-
-KindHandler_arm::~KindHandler_arm() {
-}
-
-const Registry::KindStrings KindHandler_arm::kindStrings[] = {
-  LLD_KIND_STRING_ENTRY(thumb_b22),
-  LLD_KIND_STRING_ENTRY(thumb_movw),
-  LLD_KIND_STRING_ENTRY(thumb_movt),
-  LLD_KIND_STRING_ENTRY(thumb_movw_funcRel),
-  LLD_KIND_STRING_ENTRY(thumb_movt_funcRel),
-  LLD_KIND_STRING_ENTRY(arm_b24),
-  LLD_KIND_STRING_ENTRY(arm_movw),
-  LLD_KIND_STRING_ENTRY(arm_movt),
-  LLD_KIND_STRING_ENTRY(arm_movw_funcRel),
-  LLD_KIND_STRING_ENTRY(arm_movt_funcRel),
-  LLD_KIND_STRING_ENTRY(pointer32),
-  LLD_KIND_STRING_ENTRY(delta32),
-  LLD_KIND_STRING_ENTRY(lazyPointer),
-  LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
-  LLD_KIND_STRING_END
-};
-
-bool KindHandler_arm::isCallSite(const Reference &ref) {
-  return (ref.kindValue() == thumb_b22) ||
-         (ref.kindValue() == arm_b24);
-}
-
-bool KindHandler_arm::isPointer(const Reference &ref) {
-  return (ref.kindValue() == pointer32);
-}
-
-bool KindHandler_arm::isLazyImmediate(const Reference &ref) {
-  return (ref.kindValue() == lazyImmediateLocation);
-}
-
-bool KindHandler_arm::isLazyTarget(const Reference &ref) {
-  return (ref.kindValue() == lazyPointer);
-}
-
-bool KindHandler_arm::isPairedReloc(const Relocation &reloc) {
-  switch (reloc.type) {
-  case ARM_RELOC_SECTDIFF:
-  case ARM_RELOC_LOCAL_SECTDIFF:
-  case ARM_RELOC_HALF_SECTDIFF:
-  case ARM_RELOC_HALF:
-    return true;
-  default:
-    return false;
-  }
-}
-
-
-int32_t KindHandler_arm::getDisplacementFromThumbBranch(uint32_t instruction) {
-  uint32_t s = (instruction >> 10) & 0x1;
-  uint32_t j1 = (instruction >> 29) & 0x1;
-  uint32_t j2 = (instruction >> 27) & 0x1;
-  uint32_t imm10 = instruction & 0x3FF;
-  uint32_t imm11 = (instruction >> 16) & 0x7FF;
-  uint32_t i1 = (j1 == s);
-  uint32_t i2 = (j2 == s);
-  uint32_t dis = (s << 24) | (i1 << 23) | (i2 << 22) 
-               | (imm10 << 12) | (imm11 << 1);
-  int32_t sdis = dis;
-  if (s)
-    return (sdis | 0xFE000000);
-  else
-    return sdis;
-}
-
-int32_t KindHandler_arm::getDisplacementFromArmBranch(uint32_t instruction) {
-  // Sign-extend imm24
-  int32_t displacement = (instruction & 0x00FFFFFF) << 2;
-  if ( (displacement & 0x02000000) != 0 )
-    displacement |= 0xFC000000;
-  // If this is BLX and H bit set, add 2.
-  if ((instruction & 0xFF000000) == 0xFB000000)
-    displacement += 2;
-  return displacement;
-}
-
-
-uint16_t KindHandler_arm::getWordFromThumbMov(uint32_t instruction) {
-  uint32_t i =    ((instruction & 0x00000400) >> 10);
-  uint32_t imm4 =  (instruction & 0x0000000F);
-  uint32_t imm3 = ((instruction & 0x70000000) >> 28);
-  uint32_t imm8 = ((instruction & 0x00FF0000) >> 16);
-  return (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
-}
-
-uint16_t KindHandler_arm::getWordFromArmMov(uint32_t instruction) {
-  uint32_t imm4 = ((instruction & 0x000F0000) >> 16);
-  uint32_t imm12 = (instruction & 0x00000FFF);
-  return (imm4 << 12) | imm12;
-}
-
-uint32_t KindHandler_arm::clearThumbBit(uint32_t value, const Atom* target) {
-  // The assembler often adds one to the address of a thumb function.
-  // We need to undo that so it does not look like an addend.
-  if (value & 1) {
-    if (isa<DefinedAtom>(target)) {
-      const MachODefinedAtom *machoTarget = reinterpret_cast<
-                                              const MachODefinedAtom*>(target);
-      if (machoTarget->isThumb())
-        value &= -2;  // mask off thumb-bit
-    }
-  }
-  return value;
-}
-
-std::error_code
-KindHandler_arm::getReferenceInfo(const Relocation &reloc,
-                                  const DefinedAtom *inAtom,
-                                  uint32_t offsetInAtom,
-                                  uint64_t fixupAddress, bool swap,
-                                  FindAtomBySectionAndAddress atomFromAddress,
-                                  FindAtomBySymbolIndex atomFromSymbolIndex,
-                                  Reference::KindValue *kind,
-                                  const lld::Atom **target,
-                                  Reference::Addend *addend) {
-  typedef std::error_code E;
-  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
-  uint64_t targetAddress;
-  uint32_t instruction = readU32(swap, fixupContent);
-  int32_t displacement;
-  switch (relocPattern(reloc)) {
-  case ARM_THUMB_RELOC_BR22 | rPcRel | rExtern | rLength4:
-    // ex: bl _foo (and _foo is undefined)
-    *kind = thumb_b22;
-    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
-      return ec;
-    // Instruction contains branch to addend.
-    displacement = getDisplacementFromThumbBranch(instruction);
-    *addend = fixupAddress + 4 + displacement;
-    return std::error_code();
-  case ARM_THUMB_RELOC_BR22 | rPcRel           | rLength4:
-    // ex: bl _foo (and _foo is defined)
-    *kind = thumb_b22;
-    displacement = getDisplacementFromThumbBranch(instruction);
-    targetAddress = fixupAddress + 4 + displacement;
-    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
-  case ARM_THUMB_RELOC_BR22 | rScattered | rPcRel | rLength4:
-    // ex: bl _foo+4 (and _foo is defined)
-    *kind = thumb_b22;
-    displacement = getDisplacementFromThumbBranch(instruction);
-    targetAddress = fixupAddress + 4 + displacement;
-    if (E ec = atomFromAddress(0, reloc.value, target, addend))
-      return ec;
-    // reloc.value is target atom's address.  Instruction contains branch
-    // to atom+addend.
-    *addend += (targetAddress - reloc.value);
-    return std::error_code();
-  case ARM_RELOC_BR24 | rPcRel | rExtern | rLength4:
-    // ex: bl _foo (and _foo is undefined)
-    *kind = arm_b24;
-    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
-      return ec;
-    // Instruction contains branch to addend.
-    displacement = getDisplacementFromArmBranch(instruction);
-    *addend = fixupAddress + 8 + displacement;
-    return std::error_code();
-  case ARM_RELOC_BR24 | rPcRel           | rLength4:
-    // ex: bl _foo (and _foo is defined)
-    *kind = arm_b24;
-    displacement = getDisplacementFromArmBranch(instruction);
-    targetAddress = fixupAddress + 8 + displacement;
-    return atomFromAddress(reloc.symbol, targetAddress, target, addend);
-  case ARM_RELOC_BR24 | rScattered | rPcRel | rLength4:
-    // ex: bl _foo+4 (and _foo is defined)
-    *kind = arm_b24;
-    displacement = getDisplacementFromArmBranch(instruction);
-    targetAddress = fixupAddress + 8 + displacement;
-    if (E ec = atomFromAddress(0, reloc.value, target, addend))
-      return ec;
-    // reloc.value is target atom's address.  Instruction contains branch
-    // to atom+addend.
-    *addend += (targetAddress - reloc.value);
-    return std::error_code();
-  case ARM_RELOC_VANILLA | rExtern   | rLength4:
-    // ex: .long _foo (and _foo is undefined)
-    *kind = pointer32;
-    if (E ec = atomFromSymbolIndex(reloc.symbol, target))
-      return ec;
-    *addend = instruction;
-    return std::error_code();
-  case ARM_RELOC_VANILLA             | rLength4:
-    // ex: .long _foo (and _foo is defined)
-    *kind = pointer32;
-    if (E ec = atomFromAddress(reloc.symbol, instruction, target, addend))
-      return ec;
-    *addend = clearThumbBit((uint32_t)*addend, *target);
-    return std::error_code();
-  case ARM_RELOC_VANILLA | rScattered | rLength4:
-    // ex: .long _foo+a (and _foo is defined)
-    *kind = pointer32;
-    if (E ec = atomFromAddress(0, reloc.value, target, addend))
-      return ec;
-   *addend += (clearThumbBit(instruction, *target) - reloc.value);
-    return std::error_code();
-  default:
-    return make_dynamic_error_code(Twine("unsupported arm relocation type"));
-  }
-  return std::error_code();
-}
-
-
-std::error_code
-KindHandler_arm::getPairReferenceInfo(const normalized::Relocation &reloc1,
-                                     const normalized::Relocation &reloc2,
-                                     const DefinedAtom *inAtom,
-                                     uint32_t offsetInAtom,
-                                     uint64_t fixupAddress, bool swap,
-                                     FindAtomBySectionAndAddress atomFromAddr,
-                                     FindAtomBySymbolIndex atomFromSymbolIndex,
-                                     Reference::KindValue *kind,
-                                     const lld::Atom **target,
-                                     Reference::Addend *addend) {
-  bool pointerDiff = false;
-  bool funcRel;
-  bool top;
-  bool thumbReloc;
-  switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
-  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLength4) << 16 |
-         ARM_RELOC_PAIR           | rScattered | rLength4):
-    // ex: movw        r1, :lower16:(_x-L1) [thumb mode]
-    *kind = thumb_movw_funcRel;
-    funcRel = true;
-    top = false;
-    thumbReloc = true;
-    break;
-  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLength8) << 16 |
-         ARM_RELOC_PAIR           | rScattered | rLength8):
-    // ex: movt        r1, :upper16:(_x-L1) [thumb mode]
-    *kind = thumb_movt_funcRel;
-    funcRel = true;
-    top = true;
-    thumbReloc = true;
-    break;
-  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLength1) << 16 |
-         ARM_RELOC_PAIR           | rScattered | rLength1):
-    // ex: movw        r1, :lower16:(_x-L1) [arm mode]
-    *kind = arm_movw_funcRel;
-    funcRel = true;
-    top = false;
-    thumbReloc = false;
-    break;
-  case ((ARM_RELOC_HALF_SECTDIFF  | rScattered | rLength2) << 16 |
-         ARM_RELOC_PAIR           | rScattered | rLength2):
-    // ex: movt        r1, :upper16:(_x-L1) [arm mode]
-    *kind = arm_movt_funcRel;
-    funcRel = true;
-    top = true;
-    thumbReloc = false;
-    break;
-  case ((ARM_RELOC_HALF     | rLength4) << 16 |
-         ARM_RELOC_PAIR     | rLength4):
-    // ex: movw        r1, :lower16:_x [thumb mode]
-    *kind = thumb_movw;
-    funcRel = false;
-    top = false;
-    thumbReloc = true;
-    break;
-  case ((ARM_RELOC_HALF     | rLength8) << 16 |
-         ARM_RELOC_PAIR     | rLength8):
-    // ex: movt        r1, :upper16:_x [thumb mode]
-    *kind = thumb_movt;
-    funcRel = false;
-    top = true;
-    thumbReloc = true;
-    break;
-  case ((ARM_RELOC_HALF     | rLength1) << 16 |
-         ARM_RELOC_PAIR     | rLength1):
-    // ex: movw        r1, :lower16:_x [arm mode]
-    *kind = arm_movw;
-    funcRel = false;
-    top = false;
-    thumbReloc = false;
-    break;
-  case ((ARM_RELOC_HALF     | rLength2) << 16 |
-         ARM_RELOC_PAIR     | rLength2):
-    // ex: movt        r1, :upper16:_x [arm mode]
-    *kind = arm_movt;
-    funcRel = false;
-    top = true;
-    thumbReloc = false;
-    break;
-  case ((ARM_RELOC_HALF | rScattered  | rLength4) << 16 |
-         ARM_RELOC_PAIR               | rLength4):
-    // ex: movw        r1, :lower16:_x+a [thumb mode]
-    *kind = thumb_movw;
-    funcRel = false;
-    top = false;
-    thumbReloc = true;
-    break;
-  case ((ARM_RELOC_HALF | rScattered  | rLength8) << 16 |
-         ARM_RELOC_PAIR               | rLength8):
-    // ex: movt        r1, :upper16:_x+a [thumb mode]
-    *kind = thumb_movt;
-    funcRel = false;
-    top = true;
-    thumbReloc = true;
-    break;
-  case ((ARM_RELOC_HALF | rScattered  | rLength1) << 16 |
-         ARM_RELOC_PAIR               | rLength1):
-    // ex: movw        r1, :lower16:_x+a [arm mode]
-    *kind = arm_movw;
-    funcRel = false;
-    top = false;
-    thumbReloc = false;
-    break;
-  case ((ARM_RELOC_HALF | rScattered  | rLength2) << 16 |
-         ARM_RELOC_PAIR               | rLength2):
-    // ex: movt        r1, :upper16:_x+a [arm mode]
-    *kind = arm_movt;
-    funcRel = false;
-    top = true;
-    thumbReloc = false;
-    break;
-  case ((ARM_RELOC_HALF | rExtern   | rLength4) << 16 |
-         ARM_RELOC_PAIR             | rLength4):
-    // ex: movw        r1, :lower16:_undef [thumb mode]
-    *kind = thumb_movw;
-    funcRel = false;
-    top = false;
-    thumbReloc = true;
-    break;
-  case ((ARM_RELOC_HALF | rExtern   | rLength8) << 16 |
-         ARM_RELOC_PAIR             | rLength8):
-    // ex: movt        r1, :upper16:_undef [thumb mode]
-    *kind = thumb_movt;
-    funcRel = false;
-    top = true;
-    thumbReloc = true;
-    break;
-  case ((ARM_RELOC_HALF | rExtern   | rLength1) << 16 |
-         ARM_RELOC_PAIR             | rLength1):
-    // ex: movw        r1, :lower16:_undef [arm mode]
-    *kind = arm_movw;
-    funcRel = false;
-    top = false;
-    thumbReloc = false;
-    break;
-  case ((ARM_RELOC_HALF | rExtern   | rLength2) << 16 |
-         ARM_RELOC_PAIR             | rLength2):
-    // ex: movt        r1, :upper16:_undef [arm mode]
-    *kind = arm_movt;
-    funcRel = false;
-    top = true;
-    thumbReloc = false;
-    break;
-  case ((ARM_RELOC_SECTDIFF       | rScattered | rLength4) << 16 |
-         ARM_RELOC_PAIR           | rScattered | rLength4):
-  case ((ARM_RELOC_LOCAL_SECTDIFF | rScattered | rLength4) << 16 |
-         ARM_RELOC_PAIR           | rScattered | rLength4):
-    // ex: .long _foo - .
-    pointerDiff = true;
-    break;
-  default:
-    return make_dynamic_error_code(Twine("unsupported arm relocation pair"));
-  }
-  const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
-  std::error_code ec;
-  uint32_t instruction = readU32(swap, fixupContent);
-  uint32_t value;
-  uint32_t fromAddress;
-  uint32_t toAddress;
-  uint16_t instruction16;
-  uint16_t other16;
-  const lld::Atom *fromTarget;
-  Reference::Addend offsetInTo;
-  Reference::Addend offsetInFrom;
-  if (pointerDiff) {
-    toAddress = reloc1.value;
-    fromAddress = reloc2.value;
-    ec = atomFromAddr(0, toAddress, target, &offsetInTo);
-    if (ec)
-      return ec;
-    ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
-    if (ec)
-      return ec;
-    if (fromTarget != inAtom)
-      return make_dynamic_error_code(Twine("SECTDIFF relocation where "
-                                     "subtrahend label is not in atom"));
-    *kind = delta32;
-    value = clearThumbBit(instruction, *target);
-    *addend = value - (toAddress - fromAddress);
-  } else if (funcRel) {
-    toAddress = reloc1.value;
-    fromAddress = reloc2.value;
-    ec = atomFromAddr(0, toAddress, target, &offsetInTo);
-    if (ec)
-      return ec;
-    ec = atomFromAddr(0, fromAddress, &fromTarget, &offsetInFrom);
-    if (ec)
-      return ec;
-    if (fromTarget != inAtom)
-      return make_dynamic_error_code(Twine("ARM_RELOC_HALF_SECTDIFF relocation "
-                                     "where subtrahend label is not in atom"));
-    other16 = (reloc2.offset & 0xFFFF);
-    if (thumbReloc)
-      instruction16 = getWordFromThumbMov(instruction);
-    else
-      instruction16 = getWordFromArmMov(instruction);
-    if (top)
-      value = (instruction16 << 16) | other16;
-    else
-      value = (other16 << 16) | instruction16;
-    value = clearThumbBit(value, *target);
-    int64_t ta = (int64_t)value - (toAddress - fromAddress);
-    *addend = ta - offsetInFrom;
-    return std::error_code();
-  } else {
-    uint32_t sectIndex;
-    if (thumbReloc)
-      instruction16 = getWordFromThumbMov(instruction);
-    else
-      instruction16 = getWordFromArmMov(instruction);
-    other16 = (reloc2.offset & 0xFFFF);
-    if (top)
-      value = (instruction16 << 16) | other16;
-    else
-      value = (other16 << 16) | instruction16;
-    if (reloc1.isExtern) {
-      ec = atomFromSymbolIndex(reloc1.symbol, target);
-      if (ec)
-        return ec;
-      *addend = value;
-    } else {
-      if (reloc1.scattered) {
-        toAddress = reloc1.value;
-        sectIndex = 0;
-      } else {
-        toAddress = value;
-        sectIndex = reloc1.symbol;
-      }
-      ec = atomFromAddr(sectIndex, toAddress, target, &offsetInTo);
-      if (ec)
-        return ec;
-      *addend = value - toAddress;
-    }
-  }
-  
-  return std::error_code();
-}
-
-
-
-void KindHandler_arm::applyFixup(Reference::KindNamespace ns,
-                                 Reference::KindArch arch,
-                                 Reference::KindValue kindValue,
-                                 uint64_t addend, uint8_t *location,
-                                 uint64_t fixupAddress,
-                                 uint64_t targetAddress,
-                                 uint64_t inAtomAddress) {
-  if (ns != Reference::KindNamespace::mach_o)
-    return;
-  assert(arch == Reference::KindArch::ARM);
-  //int32_t *loc32 = reinterpret_cast<int32_t*>(location);
-  // FIXME: these writes may need a swap.
-  switch (kindValue) {
-  case thumb_b22:
-      // FIXME
-    break;
-  case thumb_movw:
-      // FIXME
-      break;
-  case thumb_movt:
-      // FIXME
-      break;
-  case thumb_movw_funcRel:
-      // FIXME
-      break;
-  case thumb_movt_funcRel:
-      // FIXME
-      break;
-  case arm_b24:
-      // FIXME
-      break;
-  case arm_movw:
-      // FIXME
-      break;
-  case arm_movt:
-      // FIXME
-      break;
-  case arm_movw_funcRel:
-      // FIXME
-      break;
-  case arm_movt_funcRel:
-      // FIXME
-      break;
-  case pointer32:
-      // FIXME
-      break;
-  case delta32:
-      // FIXME
-      break;
-  case lazyPointer:
-  case lazyImmediateLocation:
-      // do nothing
-      break;
-  case invalid:
-    llvm_unreachable("invalid ARM Reference Kind");
-      break;
-  }
-}
-
-
-} // namespace mach_o
-} // namespace lld
-
-
-
diff --git a/lld/lib/ReaderWriter/MachO/ReferenceKinds.h b/lld/lib/ReaderWriter/MachO/ReferenceKinds.h
deleted file mode 100644 (file)
index f8a48b2..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-//===- lib/FileFormat/MachO/ReferenceKinds.h ------------------------------===//
-//
-//                             The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-
-#include "MachONormalizedFile.h"
-
-#include "lld/Core/LLVM.h"
-#include "lld/Core/Reference.h"
-#include "lld/ReaderWriter/MachOLinkingContext.h"
-
-#include "llvm/ADT/Triple.h"
-
-#ifndef LLD_READER_WRITER_MACHO_REFERENCE_KINDS_H
-#define LLD_READER_WRITER_MACHO_REFERENCE_KINDS_H
-
-namespace lld {
-namespace mach_o {
-
-
-///
-/// The KindHandler class is the abstract interface to Reference::Kind
-/// values for mach-o files.  Particular Kind values (e.g. 3) has a different
-/// meaning for each architecture.
-///
-class KindHandler {
-public:
-
-  static std::unique_ptr<mach_o::KindHandler> create(MachOLinkingContext::Arch);
-  virtual ~KindHandler();
-
-  virtual bool isCallSite(const Reference &) = 0;
-  virtual bool isPointer(const Reference &) = 0;
-  virtual bool isLazyImmediate(const Reference &) = 0;
-  virtual bool isLazyTarget(const Reference &) = 0;
-  
-  /// Returns true if the specified relocation is paired to the next relocation. 
-  virtual bool isPairedReloc(const normalized::Relocation &) = 0;
-  
-  /// Prototype for a helper function.  Given a sectionIndex and address, 
-  /// finds the atom and offset with that atom of that address. 
-  typedef std::function<std::error_code (uint32_t sectionIndex, uint64_t addr, 
-                        const lld::Atom **, Reference::Addend *)> 
-                        FindAtomBySectionAndAddress;
-  
-  /// Prototype for a helper function.  Given a symbolIndex, finds the atom
-  /// representing that symbol.
-  typedef std::function<std::error_code (uint32_t symbolIndex, 
-                        const lld::Atom **)> FindAtomBySymbolIndex;
-  
-  /// Analyzes a relocation from a .o file and returns the info
-  /// (kind, target, addend) needed to instantiate a Reference.
-  /// Two helper functions are passed as parameters to find the target atom
-  /// given a symbol index or address.
-  virtual std::error_code 
-          getReferenceInfo(const normalized::Relocation &reloc,
-                           const DefinedAtom *inAtom,
-                           uint32_t offsetInAtom,
-                           uint64_t fixupAddress, bool swap,
-                           FindAtomBySectionAndAddress atomFromAddress,
-                           FindAtomBySymbolIndex atomFromSymbolIndex,
-                           Reference::KindValue *kind, 
-                           const lld::Atom **target, 
-                           Reference::Addend *addend) = 0;
-
-  /// Analyzes a pair of relocations from a .o file and returns the info
-  /// (kind, target, addend) needed to instantiate a Reference.
-  /// Two helper functions are passed as parameters to find the target atom
-  /// given a symbol index or address.
-  virtual std::error_code 
-      getPairReferenceInfo(const normalized::Relocation &reloc1,
-                           const normalized::Relocation &reloc2,
-                           const DefinedAtom *inAtom,
-                           uint32_t offsetInAtom,
-                           uint64_t fixupAddress, bool swap,
-                           FindAtomBySectionAndAddress atomFromAddress,
-                           FindAtomBySymbolIndex atomFromSymbolIndex,
-                           Reference::KindValue *kind, 
-                           const lld::Atom **target, 
-                           Reference::Addend *addend) = 0;
-                           
-  /// Fixup an atom when generating a final linked binary.
-  virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
-                          Reference::KindValue kindValue, uint64_t addend,
-                          uint8_t *location, uint64_t fixupAddress,
-                          uint64_t targetAddress, uint64_t inAtomAddress) = 0;
-
-protected:
-  KindHandler();
-  
-  // Handy way to pack mach-o r_type and other bit fields into one 16-bit value.
-  typedef uint16_t RelocPattern;
-  enum {
-    rScattered = 0x8000,
-    rPcRel     = 0x4000,
-    rExtern    = 0x2000,
-    rLength1   = 0x0000,
-    rLength2   = 0x0100,
-    rLength4   = 0x0200,
-    rLength8   = 0x0300
-  };
-  static RelocPattern relocPattern(const normalized::Relocation &reloc);
-
-  static int16_t  readS16(bool swap, const uint8_t *addr);
-  static int32_t  readS32(bool swap, const uint8_t *addr);
-  static uint32_t readU32(bool swap, const uint8_t *addr);
-  static int64_t  readS64(bool swap, const uint8_t *addr);  
-};
-
-
-
-class KindHandler_x86_64 : public KindHandler {
-public:
-  static const Registry::KindStrings kindStrings[];
-
-  virtual ~KindHandler_x86_64();
-  bool isCallSite(const Reference &) override;
-  bool isPointer(const Reference &) override;
-  bool isLazyImmediate(const Reference &) override;
-  bool isLazyTarget(const Reference &) override;
-  bool isPairedReloc(const normalized::Relocation &) override;
-  std::error_code getReferenceInfo(const normalized::Relocation &reloc,
-                                   const DefinedAtom *inAtom,
-                                   uint32_t offsetInAtom,
-                                   uint64_t fixupAddress, bool swap,
-                                   FindAtomBySectionAndAddress atomFromAddress,
-                                   FindAtomBySymbolIndex atomFromSymbolIndex,
-                                   Reference::KindValue *kind, 
-                                   const lld::Atom **target, 
-                                   Reference::Addend *addend) override;
-  std::error_code 
-      getPairReferenceInfo(const normalized::Relocation &reloc1,
-                           const normalized::Relocation &reloc2,
-                           const DefinedAtom *inAtom,
-                           uint32_t offsetInAtom,
-                           uint64_t fixupAddress, bool swap,
-                           FindAtomBySectionAndAddress atomFromAddress,
-                           FindAtomBySymbolIndex atomFromSymbolIndex,
-                           Reference::KindValue *kind, 
-                           const lld::Atom **target, 
-                           Reference::Addend *addend) override;
-                           
-  virtual void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
-                          Reference::KindValue kindValue, uint64_t addend,
-                          uint8_t *location, uint64_t fixupAddress,
-                          uint64_t targetAddress, uint64_t inAtomAddress) 
-                          override;
-
-private:
-  friend class X86_64LazyPointerAtom;
-  friend class X86_64StubHelperAtom;
-  friend class X86_64StubAtom;
-  friend class X86_64StubHelperCommonAtom;
-  friend class X86_64NonLazyPointerAtom;
-  enum : Reference::KindValue {
-    invalid,               /// for error condition
-    
-    // Kinds found in mach-o .o files:
-    branch32,              /// ex: call _foo
-    ripRel32,              /// ex: movq _foo(%rip), %rax
-    ripRel32Minus1,        /// ex: movb $0x12, _foo(%rip)
-    ripRel32Minus2,        /// ex: movw $0x1234, _foo(%rip)
-    ripRel32Minus4,        /// ex: movl $0x12345678, _foo(%rip)
-    ripRel32Anon,          /// ex: movq L1(%rip), %rax
-    ripRel32GotLoad,       /// ex: movq  _foo@GOTPCREL(%rip), %rax
-    ripRel32Got,           /// ex: pushq _foo@GOTPCREL(%rip)
-    pointer64,             /// ex: .quad _foo
-    pointer64Anon,         /// ex: .quad L1
-    delta64,               /// ex: .quad _foo - .
-    delta32,               /// ex: .long _foo - .
-    delta64Anon,           /// ex: .quad L1 - .
-    delta32Anon,           /// ex: .long L1 - .
-    
-    // Kinds introduced by Passes:
-    ripRel32GotLoadNowLea, /// Target of GOT load is in linkage unit so 
-                           ///  "movq  _foo@GOTPCREL(%rip), %rax" can be changed
-                           /// to "leaq _foo(%rip), %rax
-    lazyPointer,           /// Location contains a lazy pointer.
-    lazyImmediateLocation, /// Location contains immediate value used in stub.
-  };
-  
-  Reference::KindValue kindFromReloc(const normalized::Relocation &reloc);
-  Reference::KindValue kindFromRelocPair(const normalized::Relocation &reloc1,
-                                         const normalized::Relocation &reloc2);
-
-
-};
-
-class KindHandler_x86 : public KindHandler {
-public:
-  static const Registry::KindStrings kindStrings[];
-
-  virtual ~KindHandler_x86();
-  bool isCallSite(const Reference &) override;
-  bool isPointer(const Reference &) override;
-  bool isLazyImmediate(const Reference &) override;
-  bool isLazyTarget(const Reference &) override;
-  bool isPairedReloc(const normalized::Relocation &) override;
-  std::error_code getReferenceInfo(const normalized::Relocation &reloc,
-                                   const DefinedAtom *inAtom,
-                                   uint32_t offsetInAtom,
-                                   uint64_t fixupAddress, bool swap,
-                                   FindAtomBySectionAndAddress atomFromAddress,
-                                   FindAtomBySymbolIndex atomFromSymbolIndex,
-                                   Reference::KindValue *kind,
-                                   const lld::Atom **target,
-                                   Reference::Addend *addend) override;
-  std::error_code
-      getPairReferenceInfo(const normalized::Relocation &reloc1,
-                           const normalized::Relocation &reloc2,
-                           const DefinedAtom *inAtom,
-                           uint32_t offsetInAtom,
-                           uint64_t fixupAddress, bool swap,
-                           FindAtomBySectionAndAddress atomFromAddress,
-                           FindAtomBySymbolIndex atomFromSymbolIndex,
-                           Reference::KindValue *kind,
-                           const lld::Atom **target,
-                           Reference::Addend *addend) override;
-
-  void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
-                          Reference::KindValue kindValue, uint64_t addend,
-                          uint8_t *location, uint64_t fixupAddress,
-                          uint64_t targetAddress, uint64_t inAtomAddress) 
-                          override;
-
-private:
-  friend class X86LazyPointerAtom;
-  friend class X86StubHelperAtom;
-  friend class X86StubAtom;
-  friend class X86StubHelperCommonAtom;
-  friend class X86NonLazyPointerAtom;
-
-  enum : Reference::KindValue {
-    invalid,               /// for error condition
-
-    // Kinds found in mach-o .o files:
-    branch32,              /// ex: call _foo
-    branch16,              /// ex: callw _foo
-    abs32,                 /// ex: movl _foo, %eax
-    funcRel32,             /// ex: movl _foo-L1(%eax), %eax
-    pointer32,             /// ex: .long _foo
-    delta32,               /// ex: .long _foo - .
-
-    // Kinds introduced by Passes:
-    lazyPointer,           /// Location contains a lazy pointer.
-    lazyImmediateLocation, /// Location contains immediate value used in stub.
-  };
-
-
-};
-
-
-
-class KindHandler_arm : public KindHandler {
-public:
-  static const Registry::KindStrings kindStrings[];
-
-  virtual ~KindHandler_arm();
-  bool isCallSite(const Reference &) override;
-  bool isPointer(const Reference &) override;
-  bool isLazyImmediate(const Reference &) override;
-  bool isLazyTarget(const Reference &) override;
-  bool isPairedReloc(const normalized::Relocation &) override;
-  std::error_code getReferenceInfo(const normalized::Relocation &reloc,
-                                   const DefinedAtom *inAtom,
-                                   uint32_t offsetInAtom,
-                                   uint64_t fixupAddress, bool swap,
-                                   FindAtomBySectionAndAddress atomFromAddress,
-                                   FindAtomBySymbolIndex atomFromSymbolIndex,
-                                   Reference::KindValue *kind,
-                                   const lld::Atom **target,
-                                   Reference::Addend *addend) override;
-  std::error_code
-      getPairReferenceInfo(const normalized::Relocation &reloc1,
-                           const normalized::Relocation &reloc2,
-                           const DefinedAtom *inAtom,
-                           uint32_t offsetInAtom,
-                           uint64_t fixupAddress, bool swap,
-                           FindAtomBySectionAndAddress atomFromAddress,
-                           FindAtomBySymbolIndex atomFromSymbolIndex,
-                           Reference::KindValue *kind,
-                           const lld::Atom **target,
-                           Reference::Addend *addend) override;
-
-  void applyFixup(Reference::KindNamespace ns, Reference::KindArch arch,
-                  Reference::KindValue kindValue, uint64_t addend,
-                  uint8_t *location, uint64_t fixupAddress,
-                  uint64_t targetAddress, uint64_t inAtomAddress) 
-                  override;
-
-private:
-  enum : Reference::KindValue {
-    invalid,               /// for error condition
-
-    // Kinds found in mach-o .o files:
-    thumb_b22,             /// ex: bl _foo
-    thumb_movw,            /// ex: movw        r1, :lower16:_foo
-    thumb_movt,            /// ex: movt        r1, :lower16:_foo
-    thumb_movw_funcRel,    /// ex: movw        r1, :lower16:(_foo-(L1+4))
-    thumb_movt_funcRel,    /// ex: movt r1, :upper16:(_foo-(L1+4))
-    arm_b24,               /// ex: bl _foo
-    arm_movw,              /// ex: movw        r1, :lower16:_foo
-    arm_movt,              /// ex: movt        r1, :lower16:_foo
-    arm_movw_funcRel,      /// ex: movw        r1, :lower16:(_foo-(L1+4))
-    arm_movt_funcRel,      /// ex: movt r1, :upper16:(_foo-(L1+4))
-    pointer32,             /// ex: .long _foo
-    delta32,               /// ex: .long _foo - .
-
-    // Kinds introduced by Passes:
-    lazyPointer,           /// Location contains a lazy pointer.
-    lazyImmediateLocation, /// Location contains immediate value used in stub.
-  };
-
-  int32_t getDisplacementFromThumbBranch(uint32_t instruction);
-  int32_t getDisplacementFromArmBranch(uint32_t instruction);
-  uint16_t getWordFromThumbMov(uint32_t instruction);
-  uint16_t getWordFromArmMov(uint32_t instruction);
-  uint32_t clearThumbBit(uint32_t value, const Atom* target);
-
-};
-
-} // namespace mach_o
-} // namespace lld
-
-
-
-#endif // LLD_READER_WRITER_MACHO_REFERENCE_KINDS_H
-
diff --git a/lld/lib/ReaderWriter/MachO/StubAtoms.hpp b/lld/lib/ReaderWriter/MachO/StubAtoms.hpp
deleted file mode 100644 (file)
index 64afd1a..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-//===- lib/ReaderWriter/MachO/StubAtoms.hpp -------------------------------===//
-//
-//                             The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_MACHO_STUB_ATOMS_H
-#define LLD_READER_WRITER_MACHO_STUB_ATOMS_H
-
-#include "llvm/ADT/ArrayRef.h"
-
-#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Reference.h"
-#include "lld/Core/SharedLibraryAtom.h"
-#include "lld/Core/Simple.h"
-
-#include "ReferenceKinds.h"
-#include "StubAtoms_x86_64.hpp"
-#include "StubAtoms_x86.hpp"
-
-namespace lld {
-namespace mach_o {
-
-
-//
-// StubBinderAtom created by the stubs pass.
-//
-class StubBinderAtom : public SharedLibraryAtom {
-public:
-  StubBinderAtom(const File &f) : _file(f) {
-  }
-
-  const File& file() const override {
-    return _file;
-  }
-
-  StringRef name() const override {
-    return StringRef("dyld_stub_binder");
-  }
-
-  StringRef loadName() const override {
-    return StringRef("/usr/lib/libSystem.B.dylib");
-  }
-
-  bool canBeNullAtRuntime() const override {
-    return false;
-  }
-
-  Type type() const override {
-    return Type::Unknown;
-  }
-
-  uint64_t size() const override {
-    return 0;
-  }
-
-private:
-  const File  &_file;
-};
-
-
-
-} // namespace mach_o
-} // namespace lld
-
-
-#endif // LLD_READER_WRITER_MACHO_STUB_ATOMS_H
diff --git a/lld/lib/ReaderWriter/MachO/StubAtoms_x86.hpp b/lld/lib/ReaderWriter/MachO/StubAtoms_x86.hpp
deleted file mode 100644 (file)
index 0d49454..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-//===- lib/ReaderWriter/MachO/StubAtoms_x86.hpp ---------------------------===//
-//
-//                             The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_H
-#define LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_H
-
-#include "llvm/ADT/ArrayRef.h"
-
-#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/SharedLibraryAtom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Reference.h"
-
-#include "ReferenceKinds.h"
-
-using llvm::makeArrayRef;
-
-namespace lld {
-namespace mach_o {
-
-//
-// X86 Stub Atom created by the stubs pass.
-//
-class X86StubAtom : public SimpleDefinedAtom {
-public:
-  X86StubAtom(const File &file, const Atom &lazyPointer)
-      : SimpleDefinedAtom(file) {
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86, KindHandler_x86::abs32, 2,
-                       &lazyPointer, 0);
-  }
-
-  ContentType contentType() const override {
-    return DefinedAtom::typeStub;
-  }
-
-  uint64_t size() const override {
-    return 6;
-  }
-
-  ContentPermissions permissions() const override {
-    return DefinedAtom::permR_X;
-  }
-
-  ArrayRef<uint8_t> rawContent() const override {
-    static const uint8_t instructions[] =
-        { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp *lazyPointer
-    assert(sizeof(instructions) == this->size());
-    return makeArrayRef(instructions);
-  }
-};
-
-
-//
-// X86 Stub Helper Common Atom created by the stubs pass.
-//
-class X86StubHelperCommonAtom : public SimpleDefinedAtom {
-public:
-  X86StubHelperCommonAtom(const File &file, const Atom &cache,
-                          const Atom &binder)
-      : SimpleDefinedAtom(file) {
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86, KindHandler_x86::abs32, 1, 
-                       &cache, 0);
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86, KindHandler_x86::abs32, 7,
-                       &binder, 0);
-  }
-
-  ContentType contentType() const override {
-    return DefinedAtom::typeStubHelper;
-  }
-
-  uint64_t size() const override {
-    return 12;
-  }
-
-  ContentPermissions permissions() const override {
-    return DefinedAtom::permR_X;
-  }
-
-  ArrayRef<uint8_t> rawContent() const override {
-    static const uint8_t instructions[] =
-        { 0x68, 0x00, 0x00, 0x00, 0x00,         // pushl $dyld_ImageLoaderCache
-          0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,   // jmp *_fast_lazy_bind
-          0x90 };                               // nop
-    assert(sizeof(instructions) == this->size());
-    return makeArrayRef(instructions);
-  }
-};
-
-
-//
-// X86 Stub Helper Atom created by the stubs pass.
-//
-class X86StubHelperAtom : public SimpleDefinedAtom {
-public:
-  X86StubHelperAtom(const File &file, const Atom &helperCommon)
-      : SimpleDefinedAtom(file) {
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86, 
-                       KindHandler_x86::lazyImmediateLocation, 1, this, 0);
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86, KindHandler_x86::branch32, 6,
-                       &helperCommon, 0);
-  }
-
-  ContentType contentType() const override {
-    return DefinedAtom::typeStubHelper;
-  }
-
-  uint64_t size() const override {
-    return 10;
-  }
-
-  ContentPermissions permissions() const override {
-    return DefinedAtom::permR_X;
-  }
-
-  ArrayRef<uint8_t> rawContent() const override {
-    static const uint8_t instructions[] =
-        { 0x68, 0x00, 0x00, 0x00, 0x00,   // pushq $lazy-info-offset
-          0xE9, 0x00, 0x00, 0x00, 0x00 }; // jmp helperhelper
-    assert(sizeof(instructions) == this->size());
-    return makeArrayRef(instructions);
-  }
-};
-
-
-//
-// X86 Lazy Pointer Atom created by the stubs pass.
-//
-class X86LazyPointerAtom : public SimpleDefinedAtom {
-public:
-  X86LazyPointerAtom(const File &file, const Atom &helper, const Atom &shlib)
-      : SimpleDefinedAtom(file) {
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86, KindHandler_x86::pointer32, 0,
-                       &helper, 0);
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86, KindHandler_x86::lazyPointer,
-                       0, &shlib, 0);
-  }
-
-  ContentType contentType() const override {
-    return DefinedAtom::typeLazyPointer;
-  }
-
-  Alignment alignment() const override {
-    return Alignment(2);
-  }
-
-  uint64_t size() const override {
-    return 4;
-  }
-
-  ContentPermissions permissions() const override {
-    return DefinedAtom::permRW_;
-  }
-
-  ArrayRef<uint8_t> rawContent() const override {
-    static const uint8_t bytes[] = { 0x00, 0x00, 0x00, 0x00 };
-    return makeArrayRef(bytes);
-  }
-};
-
-
-//
-// X86 NonLazy (GOT) Pointer Atom created by the stubs pass.
-//
-class X86NonLazyPointerAtom : public SimpleDefinedAtom {
-public:
-  X86NonLazyPointerAtom(const File &file)
-      : SimpleDefinedAtom(file) {}
-
-  X86NonLazyPointerAtom(const File &file, const Atom &shlib)
-      : SimpleDefinedAtom(file) {
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86, KindHandler_x86::pointer32, 0,
-                       &shlib, 0);
-  }
-
-  ContentType contentType() const override {
-    return DefinedAtom::typeGOT;
-  }
-
-  Alignment alignment() const override {
-    return Alignment(2);
-  }
-
-  uint64_t size() const override {
-    return 4;
-  }
-
-  ContentPermissions permissions() const override {
-    return DefinedAtom::permRW_;
-  }
-
-  ArrayRef<uint8_t> rawContent() const override {
-    static const uint8_t bytes[] = { 0x00, 0x00, 0x00, 0x0 };
-    return makeArrayRef(bytes);
-  }
-};
-
-} // namespace mach_o
-} // namespace lld
-
-
-#endif // LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_H
diff --git a/lld/lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp b/lld/lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp
deleted file mode 100644 (file)
index 6608732..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-//===- lib/ReaderWriter/MachO/StubAtoms_x86_64.hpp ------------------------===//
-//
-//                             The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_64_H
-#define LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_64_H
-
-#include "llvm/ADT/ArrayRef.h"
-
-#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/SharedLibraryAtom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Reference.h"
-
-#include "ReferenceKinds.h"
-
-using llvm::makeArrayRef;
-using namespace llvm::MachO;
-
-namespace lld {
-namespace mach_o {
-
-//
-// X86_64 Stub Atom created by the stubs pass.
-//
-class X86_64StubAtom : public SimpleDefinedAtom {
-public:
-  X86_64StubAtom(const File &file, const Atom &lazyPointer)
-      : SimpleDefinedAtom(file) {
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86_64, 
-                       KindHandler_x86_64::ripRel32, 2,
-                       &lazyPointer, 0);
-  }
-
-  ContentType contentType() const override {
-    return DefinedAtom::typeStub;
-  }
-
-  uint64_t size() const override {
-    return 6;
-  }
-
-  ContentPermissions permissions() const override {
-    return DefinedAtom::permR_X;
-  }
-
-  ArrayRef<uint8_t> rawContent() const override {
-    static const uint8_t instructions[] =
-        { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00 }; // jmp *lazyPointer
-    assert(sizeof(instructions) == this->size());
-    return makeArrayRef(instructions);
-  }
-};
-
-//
-// X86_64 Stub Helper Common Atom created by the stubs pass.
-//
-class X86_64StubHelperCommonAtom : public SimpleDefinedAtom {
-public:
-  X86_64StubHelperCommonAtom(const File &file, const Atom &cache,
-                             const Atom &binder)
-      : SimpleDefinedAtom(file) {
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86_64, 
-                       KindHandler_x86_64::ripRel32, 3, &cache, 0);
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86_64, 
-                       KindHandler_x86_64::ripRel32, 11, &binder, 0);
-  }
-
-  ContentType contentType() const override {
-    return DefinedAtom::typeStubHelper;
-  }
-
-  uint64_t size() const override {
-    return 16;
-  }
-
-  ContentPermissions permissions() const override {
-    return DefinedAtom::permR_X;
-  }
-
-  ArrayRef<uint8_t> rawContent() const override {
-    static const uint8_t instructions[] =
-        { 0x4C, 0x8D, 0x1D, 0x00, 0x00, 0x00, 0x00,   // leaq cache(%rip),%r11
-          0x41, 0x53,                                 // push %r11
-          0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,         // jmp *binder(%rip)
-          0x90 };                                     // nop
-    assert(sizeof(instructions) == this->size());
-    return makeArrayRef(instructions);
-  }
-};
-
-//
-// X86_64 Stub Helper Atom created by the stubs pass.
-//
-class X86_64StubHelperAtom : public SimpleDefinedAtom {
-public:
-  X86_64StubHelperAtom(const File &file, const Atom &helperCommon)
-      : SimpleDefinedAtom(file) {
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86_64,
-                       KindHandler_x86_64::lazyImmediateLocation, 1, this, 0);
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86_64, 
-                       KindHandler_x86_64::ripRel32, 6,
-                       &helperCommon, 0);
-  }
-
-  ContentType contentType() const override {
-    return DefinedAtom::typeStubHelper;
-  }
-
-  uint64_t size() const override {
-    return 10;
-  }
-
-  ContentPermissions permissions() const override {
-    return DefinedAtom::permR_X;
-  }
-
-  ArrayRef<uint8_t> rawContent() const override {
-    static const uint8_t instructions[] =
-        { 0x68, 0x00, 0x00, 0x00, 0x00,   // pushq $lazy-info-offset
-          0xE9, 0x00, 0x00, 0x00, 0x00 }; // jmp helperhelper
-    assert(sizeof(instructions) == this->size());
-    return makeArrayRef(instructions);
-  }
-};
-
-//
-// X86_64 Lazy Pointer Atom created by the stubs pass.
-//
-class X86_64LazyPointerAtom : public SimpleDefinedAtom {
-public:
-  X86_64LazyPointerAtom(const File &file, const Atom &helper,
-                        const Atom &shlib)
-      : SimpleDefinedAtom(file) {
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86_64, 
-                       KindHandler_x86_64::pointer64, 0, &helper, 0);
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86_64,
-                       KindHandler_x86_64::lazyPointer, 0, &shlib, 0);
-  }
-
-  ContentType contentType() const override {
-    return DefinedAtom::typeLazyPointer;
-  }
-
-  Alignment alignment() const override {
-    return Alignment(3);
-  }
-
-  uint64_t size() const override {
-    return 8;
-  }
-
-  ContentPermissions permissions() const override {
-    return DefinedAtom::permRW_;
-  }
-
-  ArrayRef<uint8_t> rawContent() const override {
-    static const uint8_t bytes[] =
-        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-    return makeArrayRef(bytes);
-  }
-};
-
-//
-// X86_64 NonLazy (GOT) Pointer Atom created by the stubs pass.
-//
-class X86_64NonLazyPointerAtom : public SimpleDefinedAtom {
-public:
-  X86_64NonLazyPointerAtom(const File &file)
-      : SimpleDefinedAtom(file) {}
-
-  X86_64NonLazyPointerAtom(const File &file, const Atom &shlib)
-      : SimpleDefinedAtom(file) {
-    this->addReference(Reference::KindNamespace::mach_o,
-                       Reference::KindArch::x86_64, 
-                       KindHandler_x86_64::pointer64, 0, &shlib, 0);
-  }
-
-  ContentType contentType() const override {
-    return DefinedAtom::typeGOT;
-  }
-
-  Alignment alignment() const override {
-    return Alignment(3);
-  }
-
-  uint64_t size() const override {
-    return 8;
-  }
-
-  ContentPermissions permissions() const override {
-    return DefinedAtom::permRW_;
-  }
-
-  ArrayRef<uint8_t> rawContent() const override {
-    static const uint8_t bytes[] =
-        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-    return makeArrayRef(bytes);
-  }
-};
-
-} // namespace mach_o
-} // namespace lld
-
-
-#endif // LLD_READER_WRITER_MACHO_STUB_ATOMS_X86_64_H
index 630e00b..4956102 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
+#include "ArchHandler.h"
+#include "File.h"
+#include "MachOPasses.h"
+
 #include "lld/Core/DefinedAtom.h"
 #include "lld/Core/File.h"
 #include "lld/Core/LLVM.h"
 #include "lld/Core/Reference.h"
+#include "lld/Core/Simple.h"
+#include "lld/ReaderWriter/MachOLinkingContext.h"
+
 #include "llvm/ADT/DenseMap.h"
 
-#include "MachOPasses.h"
 
 namespace lld {
+namespace mach_o {
+
+
+//
+//  Lazy Pointer Atom created by the stubs pass.
+//
+class LazyPointerAtom : public SimpleDefinedAtom {
+public:
+  LazyPointerAtom(const File &file, bool is64) 
+    : SimpleDefinedAtom(file), _is64(is64) { }
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeLazyPointer;
+  }
+
+  Alignment alignment() const override {
+    return Alignment(_is64 ? 3 : 2);
+  }
+
+  uint64_t size() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permRW_;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t zeros[] =
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return llvm::makeArrayRef(zeros, size());
+  }
+
+private:
+  const bool _is64;
+};
+
+
+//
+//  NonLazyPointer (GOT) Atom created by the stubs pass.
+//
+class NonLazyPointerAtom : public SimpleDefinedAtom {
+public:
+  NonLazyPointerAtom(const File &file, bool is64) 
+    : SimpleDefinedAtom(file), _is64(is64) { }
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeGOT;
+  }
+
+  Alignment alignment() const override {
+    return Alignment(_is64 ? 3 : 2);
+  }
+
+  uint64_t size() const override {
+    return _is64 ? 8 : 4;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permRW_;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    static const uint8_t zeros[] =
+        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    return llvm::makeArrayRef(zeros, size());
+  }
+
+private:
+  const bool _is64;
+};
+
+
+
+//
+// Stub Atom created by the stubs pass.
+//
+class StubAtom : public SimpleDefinedAtom {
+public:
+  StubAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+      : SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeStub;
+  }
+
+  Alignment alignment() const override {
+    return Alignment(_stubInfo.codeAlignment);
+  }
+
+  uint64_t size() const override {
+    return _stubInfo.stubSize;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(_stubInfo.stubBytes, _stubInfo.stubSize);
+  }
+
+private:
+  const ArchHandler::StubInfo   &_stubInfo;
+};
+
+
+//
+// Stub Helper Atom created by the stubs pass.
+//
+class StubHelperAtom : public SimpleDefinedAtom {
+public:
+  StubHelperAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+      : SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeStubHelper;
+  }
+
+  Alignment alignment() const override {
+    return Alignment(_stubInfo.codeAlignment);
+  }
+
+  uint64_t size() const override {
+    return _stubInfo.stubHelperSize;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(_stubInfo.stubHelperBytes, 
+                              _stubInfo.stubHelperSize);
+  }
+
+private:
+  const ArchHandler::StubInfo   &_stubInfo;
+};
+
+
+//
+// Stub Helper Common Atom created by the stubs pass.
+//
+class StubHelperCommonAtom : public SimpleDefinedAtom {
+public:
+  StubHelperCommonAtom(const File &file, const ArchHandler::StubInfo &stubInfo)
+      : SimpleDefinedAtom(file), _stubInfo(stubInfo) { }
+
+  ContentType contentType() const override {
+    return DefinedAtom::typeStubHelper;
+  }
+
+  Alignment alignment() const override {
+    return Alignment(_stubInfo.codeAlignment);
+  }
+
+  uint64_t size() const override {
+    return _stubInfo.stubHelperCommonSize;
+  }
+
+  ContentPermissions permissions() const override {
+    return DefinedAtom::permR_X;
+  }
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(_stubInfo.stubHelperCommonBytes, 
+                        _stubInfo.stubHelperCommonSize);
+  }
+
+private:
+  const ArchHandler::StubInfo   &_stubInfo;
+};
+
+
+class StubsPass : public Pass {
+public:
+  StubsPass(const MachOLinkingContext &context)
+    : _context(context)
+    , _archHandler(_context.archHandler())
+    , _stubInfo(_archHandler.stubInfo())
+    , _file("<mach-o Stubs pass>")
+    , _helperCommonAtom(nullptr)
+    , _helperCacheNLPAtom(nullptr)
+    , _helperBinderNLPAtom(nullptr) {
+  }
 
-void StubsPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
-  // Skip this pass if output format uses text relocations instead of stubs.
-  if (!this->noTextRelocs())
-    return;
-
-  // Scan all references in all atoms.
-  for (const DefinedAtom *atom : mergedFile->defined()) {
-    for (const Reference *ref : *atom) {
-      // Look at call-sites.
-      if (!this->isCallSite(*ref))
-        continue;
-      const Atom *target = ref->target();
-      assert(target != nullptr);
-      if (target->definition() == Atom::definitionSharedLibrary) {
-        // Calls to shared libraries go through stubs.
-        replaceCalleeWithStub(target, ref);
-        continue;
+
+  void perform(std::unique_ptr<MutableFile> &mergedFile) override {
+    // Skip this pass if output format uses text relocations instead of stubs.
+    if (!this->noTextRelocs())
+      return;
+    
+    // Scan all references in all atoms.
+    for (const DefinedAtom *atom : mergedFile->defined()) {
+      for (const Reference *ref : *atom) {
+        // Look at call-sites.
+        if (!this->isCallSite(*ref))
+          continue;
+        const Atom *target = ref->target();
+        assert(target != nullptr);
+        if (target->definition() == Atom::definitionSharedLibrary) {
+          // Calls to shared libraries go through stubs.
+          replaceCalleeWithStub(target, ref);
+          continue;
+        }
+        const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
+        if (defTarget && defTarget->interposable() != DefinedAtom::interposeNo){
+          // Calls to interposable functions in same linkage unit must also go
+          // through a stub.
+          assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
+          replaceCalleeWithStub(target, ref);
+        }
       }
-      const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
-      if (defTarget && defTarget->interposable() != DefinedAtom::interposeNo) {
-        // Calls to interposable functions in same linkage unit must also go
-        // through a stub.
-        assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
-        replaceCalleeWithStub(target, ref);
+    }
+    // Exit early if no stubs needed.
+    if (_targetToStub.empty())
+      return;
+    
+    // Add reference to dyld_stub_binder in libSystem.dylib
+    if (_helperBinderNLPAtom) {
+      bool found = false;
+      for (const SharedLibraryAtom *atom : mergedFile->sharedLibrary()) {
+        if (atom->name().equals(_stubInfo.binderSymbolName)) {
+          addReference(_helperBinderNLPAtom,  
+                       _stubInfo.nonLazyPointerReferenceToBinder, atom);
+          found = true;
+          break;
+        }
       }
+      assert(found && "dyld_stub_binder not found");
+    }
+    
+    // Add all stubs to master file.
+    for (auto it : _targetToStub) {
+      mergedFile->addAtom(*it.second);
+    }
+    // Add helper code atoms.
+    mergedFile->addAtom(*_helperCommonAtom);
+    for (const DefinedAtom *lp : _stubHelperAtoms) {
+      mergedFile->addAtom(*lp);
+    }
+    // Add GOT slots used for lazy binding.
+    mergedFile->addAtom(*_helperBinderNLPAtom);
+    mergedFile->addAtom(*_helperCacheNLPAtom);
+    // Add all lazy pointers to master file.
+    for (const DefinedAtom *lp : _lazyPointers) {
+      mergedFile->addAtom(*lp);
     }
   }
-  // Add all created stubs and support Atoms.
-  this->addStubAtoms(*mergedFile);
-}
 
-void StubsPass::replaceCalleeWithStub(const Atom *target,
-                                      const Reference *ref) {
-  // Make file-format specific stub and other support atoms.
-  const DefinedAtom *stub = this->getStub(*target);
-  assert(stub != nullptr);
-  // Switch call site to reference stub atom instead.
-  const_cast<Reference *>(ref)->setTarget(stub);
+
+private:
+
+  bool noTextRelocs() {
+    return true;
+  }
+
+  bool isCallSite(const Reference &ref) {
+    return _archHandler.isCallSite(ref);
+  }
+
+  void replaceCalleeWithStub(const Atom *target, const Reference *ref) {
+    // Make file-format specific stub and other support atoms.
+    const DefinedAtom *stub = this->getStub(*target);
+    assert(stub != nullptr);
+    // Switch call site to reference stub atom instead.
+    const_cast<Reference *>(ref)->setTarget(stub);
+  }
+
+  const DefinedAtom* getStub(const Atom& target) {
+    auto pos = _targetToStub.find(&target);
+    if ( pos != _targetToStub.end() ) {
+      // Reuse an existing stub.
+      assert(pos->second != nullptr);
+      return pos->second;
+    }
+    else {
+      // There is no existing stub, so create a new one.
+      return this->makeStub(target);
+    }
+  }
+
+  const DefinedAtom* makeStub(const Atom &target) {
+    SimpleDefinedAtom* stub   = new (_file.allocator()) 
+                                                    StubAtom(_file, _stubInfo);
+    SimpleDefinedAtom* lp     = new (_file.allocator()) 
+                                    LazyPointerAtom(_file, _context.is64Bit());
+    SimpleDefinedAtom* helper = new (_file.allocator()) 
+                                              StubHelperAtom(_file, _stubInfo);
+   
+    addReference(stub, _stubInfo.stubReferenceToLP, lp);
+    addReference(lp, _stubInfo.lazyPointerReferenceToHelper, helper);
+    addReference(lp, _stubInfo.lazyPointerReferenceToFinal, &target);
+    addReference(helper, _stubInfo.stubHelperReferenceToImm, helper);
+    addReference(helper, _stubInfo.stubHelperReferenceToHelperCommon, 
+                 helperCommon());
+    
+    _stubHelperAtoms.push_back(helper);
+    _targetToStub[&target] = stub;
+    _lazyPointers.push_back(lp);
+    
+    return stub;
+  }
+  void addReference(SimpleDefinedAtom* atom, 
+                    const ArchHandler::ReferenceInfo &refInfo,
+                    const lld::Atom* target) {
+    atom->addReference(Reference::KindNamespace::mach_o,
+                      refInfo.arch, refInfo.kind, refInfo.offset,
+                      target, refInfo.addend);
+  }
+  
+  const DefinedAtom* helperCommon() {
+    if ( !_helperCommonAtom ) {
+      // Lazily create common helper code and data.
+      _helperCommonAtom    = new (_file.allocator()) 
+                                         StubHelperCommonAtom(_file, _stubInfo);
+      _helperCacheNLPAtom  = new (_file.allocator()) 
+                                  NonLazyPointerAtom(_file, _context.is64Bit());
+      _helperBinderNLPAtom = new (_file.allocator()) 
+                                  NonLazyPointerAtom(_file, _context.is64Bit());
+      addReference(_helperCommonAtom, 
+                   _stubInfo.stubHelperCommonReferenceToCache, 
+                   _helperCacheNLPAtom);
+      addReference(_helperCommonAtom, 
+                   _stubInfo.stubHelperCommonReferenceToBinder, 
+                   _helperBinderNLPAtom);
+    }
+    return _helperCommonAtom;
+  }
+
+
+  const MachOLinkingContext                      &_context;
+  mach_o::ArchHandler                            &_archHandler;
+  const ArchHandler::StubInfo                    &_stubInfo;
+  MachOFile                                       _file;
+  llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToStub;
+  std::vector<const DefinedAtom*>                 _lazyPointers;
+  std::vector<const DefinedAtom*>                 _stubHelperAtoms;
+  SimpleDefinedAtom                              *_helperCommonAtom;
+  SimpleDefinedAtom                              *_helperCacheNLPAtom;
+  SimpleDefinedAtom                              *_helperBinderNLPAtom;
+};
+
+
+
+void addStubsPass(PassManager &pm, const MachOLinkingContext &ctx) {
+  pm.add(std::unique_ptr<Pass>(new StubsPass(ctx)));
 }
 
+} // end namespace mach_o
 } // end namespace lld
diff --git a/lld/lib/ReaderWriter/MachO/StubsPass.hpp b/lld/lib/ReaderWriter/MachO/StubsPass.hpp
deleted file mode 100644 (file)
index 0e70589..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-//===- lib/ReaderWriter/MachO/StubsPass.hpp -------------------------------===//
-//
-//                             The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLD_READER_WRITER_MACHO_STUBS_PASS_H
-#define LLD_READER_WRITER_MACHO_STUBS_PASS_H
-
-#include "llvm/ADT/DenseMap.h"
-
-#include "lld/Core/DefinedAtom.h"
-#include "lld/Core/File.h"
-#include "lld/Core/Pass.h"
-#include "lld/Core/Reference.h"
-#include "lld/Core/SharedLibraryAtom.h"
-#include "lld/Core/Simple.h"
-
-#include "MachOPasses.h"
-#include "ReferenceKinds.h"
-#include "StubAtoms.hpp"
-
-namespace lld {
-namespace mach_o {
-
-
-class StubsPass : public lld::StubsPass {
-public:
-  StubsPass(const MachOLinkingContext &context)
-    : _context(context)
-    , _kindHandler(_context.kindHandler())
-    , _file(context)
-    , _helperCommonAtom(nullptr)
-    , _helperCacheAtom(nullptr)
-    , _helperBinderAtom(nullptr) {
-  }
-
-  bool noTextRelocs() override {
-    return true;
-  }
-
-  bool isCallSite(const Reference &ref) override {
-    return _kindHandler.isCallSite(ref);
-  }
-
-  const DefinedAtom* getStub(const Atom& target) override {
-    auto pos = _targetToStub.find(&target);
-    if ( pos != _targetToStub.end() ) {
-      // Reuse an existing stub.
-      assert(pos->second != nullptr);
-      return pos->second;
-    }
-    else {
-      // There is no existing stub, so create a new one.
-      return this->makeStub(target);
-    }
-  }
-
-  const DefinedAtom* makeStub(const Atom& target) {
-    switch (_context.arch()) {
-      case MachOLinkingContext::arch_x86_64:
-        return makeStub_x86_64(target);
-      case MachOLinkingContext::arch_x86:
-        return makeStub_x86(target);
-      case MachOLinkingContext::arch_armv6:
-      case MachOLinkingContext::arch_armv7:
-      case MachOLinkingContext::arch_armv7s:
-        return makeStub_arm(target);
-      default:
-        llvm_unreachable("Unknown mach-o arch");
-    }
-  }
-
-  const DefinedAtom* makeStub_x86_64(const Atom& target) {
-    if ( _helperCommonAtom == nullptr ) {
-      // Lazily create common helper code and data.
-      _helperCacheAtom = new X86_64NonLazyPointerAtom(_file);
-      _binderAtom = new StubBinderAtom(_file);
-      _helperBinderAtom = new X86_64NonLazyPointerAtom(_file, *_binderAtom);
-      _helperCommonAtom = new X86_64StubHelperCommonAtom(_file,
-                                       *_helperCacheAtom, *_helperBinderAtom);
-    }
-    const DefinedAtom* helper = new X86_64StubHelperAtom(_file,
-                                                          *_helperCommonAtom);
-    _stubHelperAtoms.push_back(helper);
-    const DefinedAtom* lp = new X86_64LazyPointerAtom(_file, *helper, target);
-    assert(lp->contentType() == DefinedAtom::typeLazyPointer);
-    _lazyPointers.push_back(lp);
-    const DefinedAtom* stub = new X86_64StubAtom(_file, *lp);
-     assert(stub->contentType() == DefinedAtom::typeStub);
-    _targetToStub[&target] = stub;
-    return stub;
-  }
-
-  const DefinedAtom* makeStub_x86(const Atom& target) {
-    if ( _helperCommonAtom == nullptr ) {
-      // Lazily create common helper code and data.
-      _helperCacheAtom = new X86NonLazyPointerAtom(_file);
-      _binderAtom = new StubBinderAtom(_file);
-      _helperBinderAtom = new X86NonLazyPointerAtom(_file, *_binderAtom);
-      _helperCommonAtom = new X86StubHelperCommonAtom(_file,
-                                       *_helperCacheAtom, *_helperBinderAtom);
-    }
-    const DefinedAtom* helper = new X86StubHelperAtom(_file,
-                                                          *_helperCommonAtom);
-    _stubHelperAtoms.push_back(helper);
-    const DefinedAtom* lp = new X86LazyPointerAtom(_file, *helper, target);
-    assert(lp->contentType() == DefinedAtom::typeLazyPointer);
-    _lazyPointers.push_back(lp);
-    const DefinedAtom* stub = new X86StubAtom(_file, *lp);
-     assert(stub->contentType() == DefinedAtom::typeStub);
-    _targetToStub[&target] = stub;
-    return stub;
-  }
-
-  const DefinedAtom* makeStub_arm(const Atom& target) {
-    assert(0 && "stubs not yet implemented for arm");
-    return nullptr;
-  }
-
-
-  void addStubAtoms(MutableFile &mergedFile) override {
-    // Exit early if no stubs needed.
-    if (_targetToStub.empty())
-      return;
-    // Add all stubs to master file.
-    for (auto it : _targetToStub) {
-      mergedFile.addAtom(*it.second);
-    }
-    // Add helper code atoms.
-    mergedFile.addAtom(*_helperCommonAtom);
-    for (const DefinedAtom *lp : _stubHelperAtoms) {
-      mergedFile.addAtom(*lp);
-    }
-    // Add GOT slots used for lazy binding.
-    mergedFile.addAtom(*_helperBinderAtom);
-    mergedFile.addAtom(*_helperCacheAtom);
-    // Add all lazy pointers to master file.
-    for (const DefinedAtom *lp : _lazyPointers) {
-      mergedFile.addAtom(*lp);
-    }
-    // Add sharedlibrary atom
-    mergedFile.addAtom(*_binderAtom);
-  }
-
-private:
-
-  class File : public SimpleFile {
-  public:
-    File(const MachOLinkingContext &context) : SimpleFile("MachO Stubs pass") {}
-  };
-
-  const MachOLinkingContext &_context;
-  mach_o::KindHandler                            &_kindHandler;
-  File                                            _file;
-  llvm::DenseMap<const Atom*, const DefinedAtom*> _targetToStub;
-  std::vector<const DefinedAtom*>                 _lazyPointers;
-  std::vector<const DefinedAtom*>                 _stubHelperAtoms;
-  const SharedLibraryAtom                        *_binderAtom;
-  const DefinedAtom*                              _helperCommonAtom;
-  const DefinedAtom*                              _helperCacheAtom;
-  const DefinedAtom*                              _helperBinderAtom;
-};
-
-
-} // namespace mach_o
-} // namespace lld
-
-
-#endif // LLD_READER_WRITER_MACHO_STUBS_PASS_H
diff --git a/lld/test/darwin/hello-world.objtxt b/lld/test/darwin/hello-world.objtxt
deleted file mode 100644 (file)
index 7d13b4b..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t  && \
-# RUN: llvm-nm %t | FileCheck %s
-#
-# Test that hello-world can be linked into a mach-o executable
-#
-
---- !native
-defined-atoms:
-    - name:              _main
-      type:              code
-      scope:             global
-      content:           [ 55, 48, 89, E5, 48, 8D, 3D, 00,
-                           00, 00, 00, E8, 00, 00, 00, 00,
-                           31, C0, 5D, C3 ]
-      references:
-      - offset:          7
-        kind:            ripRel32
-        target:          LC1
-      - offset:          12
-        kind:            branch32
-        target:          _printf
-
-    - ref-name:          LC1
-      type:              c-string
-      merge:             by-content
-      content:           [ 68, 65, 6C, 6C, 6F, 0A, 00 ]
-
-shared-library-atoms:
-    - name:              _printf
-      load-name:         /usr/lib/libSystem.B.dylib
-
-...
-
-# CHECK:       {{[0-9a-f]+}} T _main
-# CHECK:       U _printf
-# CHECK:       U dyld_stub_binder
index f8e118d..20f2d0b 100644 (file)
@@ -38,6 +38,27 @@ global-symbols:
    desc:        [ ]
    value:       0
 
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ ]
+install-name:    /usr/lib/libSystem.B.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55 ]
+
+global-symbols:
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+
 ...
 
 # CHECK:       {{[0-9a-f]+}} T _foo
index 12f0815..f06ec7a 100644 (file)
@@ -25,6 +25,28 @@ defined-atoms:
      type:            data
      content:         [ 01 ]
 
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ ]
+install-name:    /usr/lib/libSystem.B.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55 ]
+
+global-symbols:
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+
+
 # CHECK-LABEL: Section {
 # CHECK:     Name: __text
 # CHECK:     Segment: __TEXT
index b0ed762..4d70b00 100644 (file)
@@ -19,6 +19,26 @@ defined-atoms:
      section-name:    __CUST/__custom
 
 
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ ]
+install-name:    /usr/lib/libSystem.B.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55 ]
+
+global-symbols:
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
 # CHECK-LABEL: Section {
 # CHECK:     Name: __text
 # CHECK:     Segment: __TEXT
index 8bb3909..f19e3ea 100644 (file)
@@ -75,6 +75,11 @@ global-symbols:
     scope:           [ N_EXT ]
     sect:            1
     value:           0x0000000000000001
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000001
 
 ...
 
diff --git a/lld/test/mach-o/hello-world-x86_64.yaml b/lld/test/mach-o/hello-world-x86_64.yaml
new file mode 100644 (file)
index 0000000..4ab4be9
--- /dev/null
@@ -0,0 +1,144 @@
+# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t  && \
+# RUN: llvm-nm %t | FileCheck %s
+#
+# Test that x86_64 hello-world can be linked into a mach-o executable
+#
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_OBJECT
+flags:           [ MH_SUBSECTIONS_VIA_SYMBOLS ]
+has-UUID:        false
+OS:              unknown
+sections:        
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55, 0x48, 0x89, 0xE5, 0x48, 0x8B, 0x05, 0x00, 
+                       0x00, 0x00, 0x00, 0x48, 0x8B, 0x38, 0x48, 0x8D, 
+                       0x35, 0x00, 0x00, 0x00, 0x00, 0x31, 0xC0, 0xE8, 
+                       0x00, 0x00, 0x00, 0x00, 0x31, 0xC0, 0x5D, 0xC3 ]
+    relocations:     
+      - offset:          0x00000018
+        type:            X86_64_RELOC_BRANCH
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          5
+      - offset:          0x00000011
+        type:            X86_64_RELOC_SIGNED
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          0
+      - offset:          0x00000007
+        type:            X86_64_RELOC_GOT_LOAD
+        length:          2
+        pc-rel:          true
+        extern:          true
+        symbol:          4
+  - segment:         __TEXT
+    section:         __cstring
+    type:            S_CSTRING_LITERALS
+    attributes:      [  ]
+    address:         0x0000000000000020
+    content:         [ 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x00 ]
+  - segment:         __LD
+    section:         __compact_unwind
+    type:            S_REGULAR
+    attributes:      [  ]
+    alignment:       3
+    address:         0x0000000000000028
+    content:         [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+    relocations:     
+      - offset:          0x00000000
+        type:            X86_64_RELOC_UNSIGNED
+        length:          3
+        pc-rel:          false
+        extern:          false
+        symbol:          1
+  - segment:         __TEXT
+    section:         __eh_frame
+    type:            S_COALESCED
+    attributes:      [  ]
+    alignment:       3
+    address:         0x0000000000000048
+    content:         [ 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x01, 0x7A, 0x52, 0x00, 0x01, 0x78, 0x10, 0x01, 
+                       0x10, 0x0C, 0x07, 0x08, 0x90, 0x01, 0x00, 0x00, 
+                       0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 
+                       0x98, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+                       0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+                       0x00, 0x41, 0x0E, 0x10, 0x86, 0x02, 0x43, 0x0D, 
+                       0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+local-symbols:   
+  - name:            L1
+    type:            N_SECT
+    sect:            2
+    value:           0x0000000000000020
+  - name:            EH_frame0
+    type:            N_SECT
+    sect:            4
+    value:           0x0000000000000048
+global-symbols:  
+  - name:            _main
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            _main.eh
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            4
+    value:           0x0000000000000060
+undefined-symbols: 
+  - name:            ___stdoutp
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+  - name:            _fprintf
+    type:            N_UNDF
+    scope:           [ N_EXT ]
+    value:           0x0000000000000000
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ ]
+install-name:    /usr/lib/libSystem.B.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55 ]
+
+global-symbols:
+  - name:            _fprintf
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+  - name:            ___stdoutp
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+
+...
+
+# CHECK:       U ___stdoutp
+# CHECK:       U _fprintf
+# CHECK:       {{[0-9a-f]+}} T _main
+# CHECK:       U dyld_stub_binder
index 2f8ddca..8701f40 100644 (file)
@@ -151,3 +151,25 @@ defined-atoms:
 # CHECK: SectionData (
 # CHECK-NEXT: 0000: 0E000000 00000000
 # CHECK-NEXT: )
+
+
+--- !mach-o
+arch:            x86_64
+file-type:       MH_DYLIB
+flags:           [ ]
+install-name:    /usr/lib/libSystem.B.dylib
+sections:
+  - segment:         __TEXT
+    section:         __text
+    type:            S_REGULAR
+    attributes:      [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
+    address:         0x0000000000000000
+    content:         [ 0x55 ]
+
+global-symbols:
+  - name:            dyld_stub_binder
+    type:            N_SECT
+    scope:           [ N_EXT ]
+    sect:            1
+    value:           0x0000000000000000
+