[LLVMdev] arm64 / iOS support

Carlo Kok ck at remobjects.com
Wed Sep 25 11:32:38 PDT 2013


Attached is a working patch set for llvm to be able to emit arm64 
(currently as triple aarch64-apple-ios) mach-o object files, in case 
someone is interested. I'm not sure if the llvm maintainers want the 
patch given the previous message that there's going to be an official 
patch set from apple to support this, but here is mine.

What works (tested on an iPhone 5S):
* objc strings, selectors, class refs
* defining classes
* regular strings, int64 constants
* exception handling
* emitting debug info: I couldn't test this yet due to no support for it 
in lldb.

What doesn't work yet:
* varargs, need to figure out how to do that

Some things that work but aren't right yet:
* The decision on if to emit a symbol for a label or not are currently 
done by section type, there has to be a way to tell llvm to always 
generate a symbol when it uses a label between a section, but I haven't 
found it yet.


If this is of interest suggestions on improvements are welcome.


made with a lot of help from Tim Northover and others in the irc channel.

-- 
Carlo Kok
RemObjects Software
-------------- next part --------------
diff --git a/include/llvm/Support/MachO.h b/include/llvm/Support/MachO.h
index b2ac6b3..cb12902 100644
--- a/include/llvm/Support/MachO.h
+++ b/include/llvm/Support/MachO.h
@@ -402,6 +402,21 @@ namespace llvm {
       ARM_THUMB_32BIT_BRANCH       = 7, // obsolete
       ARM_RELOC_HALF               = 8,
       ARM_RELOC_HALF_SECTDIFF      = 9,
+	  
+	  // Constant values for r_type field in an arm64 architecture
+      ARM64_RELOC_UNSIGNED = GENERIC_RELOC_VANILLA,   // for pointers
+      ARM64_RELOC_SUBTRACTOR = 1,       // must be followed by a ARM64_RELOC_UNSIGNED
+      ARM64_RELOC_BRANCH26 =2,         // a B/BL instruction with 26-bit displacement
+      ARM64_RELOC_PAGE21 = 3,           // pc-rel distance to page of target
+      ARM64_RELOC_PAGEOFF12 = 4,        // offset within page, scaled by r_length
+      ARM64_RELOC_GOT_LOAD_PAGE21 = 5,  // pc-rel distance to page of GOT slot
+      ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6, // offset within page of GOT slot,
+                                    //  scaled by r_length
+      ARM64_RELOC_POINTER_TO_GOT = 7,   // for pointers to GOT slots
+      ARM64_RELOC_TLVP_LOAD_PAGE21 = 7, // pc-rel distance to page of TLVP slot
+      ARM64_RELOC_TLVP_LOAD_PAGEOFF12 = 8, // offset within page of TLVP slot,
+                                     //  scaled by r_length
+      ARM64_RELOC_ADDEND = 9,   // must be followed by PAGE21 or PAGEOFF12	  
 
       // Constant values for the r_type field in an x86_64 architecture
       // llvm::MachO::relocation_info or llvm::MachO::scattered_relocation_info
@@ -908,6 +923,7 @@ namespace llvm {
    /* CPU_TYPE_MIPS      = 8, */
       CPU_TYPE_MC98000   = 10, // Old Motorola PowerPC
       CPU_TYPE_ARM       = 12,
+      CPU_TYPE_ARM64     = CPU_TYPE_ARM | CPU_ARCH_ABI64,
       CPU_TYPE_SPARC     = 14,
       CPU_TYPE_POWERPC   = 18,
       CPU_TYPE_POWERPC64 = CPU_TYPE_POWERPC | CPU_ARCH_ABI64
@@ -980,6 +996,12 @@ namespace llvm {
       CPU_SUBTYPE_ARM_V7EM    = 16
     };
 
+    enum CPUSubTypeARM64 {
+      CPU_SUBTYPE_ARM64_ALL  = 0,
+      CPU_SUBTYPE_ARM64_V8 = 1
+    };
+
+
     enum CPUSubTypeSPARC {
       CPU_SUBTYPE_SPARC_ALL   = 0
     };
diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp
index 958648c..b5269b6 100644
--- a/lib/MC/MCObjectFileInfo.cpp
+++ b/lib/MC/MCObjectFileInfo.cpp
@@ -18,14 +18,25 @@ using namespace llvm;
 
 void MCObjectFileInfo::InitMachOMCObjectFileInfo(Triple T) {
   // MachO
-  IsFunctionEHFrameSymbolPrivate = false;
-  SupportsWeakOmittedEHFrame = false;
 
-  PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel
-    | dwarf::DW_EH_PE_sdata4;
-  LSDAEncoding = FDEEncoding = FDECFIEncoding = dwarf::DW_EH_PE_pcrel;
-  TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
-    dwarf::DW_EH_PE_sdata4;
+  if (T.getArch() ==  Triple::aarch64) {
+      PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; // good
+      LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
+      FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
+      FDECFIEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
+      TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; // good
+      IsFunctionEHFrameSymbolPrivate = false;
+      SupportsWeakOmittedEHFrame = false;
+  } else {
+    IsFunctionEHFrameSymbolPrivate = false;
+    SupportsWeakOmittedEHFrame = false;
+
+    PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel
+      | dwarf::DW_EH_PE_sdata4;
+    LSDAEncoding = FDEEncoding = FDECFIEncoding = dwarf::DW_EH_PE_pcrel;
+    TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
+      dwarf::DW_EH_PE_sdata4;
+  }
 
   // .comm doesn't support alignment before Leopard.
   if (T.isMacOSX() && T.isMacOSXVersionLT(10, 5))
@@ -699,7 +710,7 @@ void MCObjectFileInfo::InitMCObjectFileInfo(StringRef TT, Reloc::Model relocm,
   if ((Arch == Triple::x86 || Arch == Triple::x86_64 ||
        Arch == Triple::arm || Arch == Triple::thumb ||
        Arch == Triple::ppc || Arch == Triple::ppc64 ||
-       Arch == Triple::UnknownArch) &&
+       Arch == Triple::UnknownArch || Arch == Triple::aarch64) &&
       (T.isOSDarwin() || T.getEnvironment() == Triple::MachO)) {
     Env = IsMachO;
     InitMachOMCObjectFileInfo(T);
diff --git a/lib/Target/AArch64/AArch64AsmPrinter.cpp b/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 759809f..2a38247 100644
--- a/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -281,6 +281,8 @@ void AArch64AsmPrinter::EmitEndOfAsmFile(Module &M) {
       }
       Stubs.clear();
     }
+  } else if (Subtarget->isTargetDarwin()) {
+    OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols);
   }
 }
 
diff --git a/lib/Target/AArch64/AArch64ISelLowering.cpp b/lib/Target/AArch64/AArch64ISelLowering.cpp
index 48f34c0..0feaa0d 100644
--- a/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -32,6 +32,8 @@ using namespace llvm;
 static TargetLoweringObjectFile *createTLOF(AArch64TargetMachine &TM) {
   const AArch64Subtarget *Subtarget = &TM.getSubtarget<AArch64Subtarget>();
 
+  if (Subtarget->isTargetDarwin())
+    return new AArch64MachOTargetObjectFile();
   if (Subtarget->isTargetLinux())
     return new AArch64LinuxTargetObjectFile();
   if (Subtarget->isTargetELF())
@@ -41,9 +43,7 @@ static TargetLoweringObjectFile *createTLOF(AArch64TargetMachine &TM) {
 
 AArch64TargetLowering::AArch64TargetLowering(AArch64TargetMachine &TM)
   : TargetLowering(TM, createTLOF(TM)), Itins(TM.getInstrItineraryData()) {
-
-  const AArch64Subtarget *Subtarget = &TM.getSubtarget<AArch64Subtarget>();
-
+  Subtarget = &TM.getSubtarget<AArch64Subtarget>();
   // SIMD compares set the entire lane's bits to 1
   setBooleanVectorContents(ZeroOrNegativeOneBooleanContent);
 
@@ -2050,6 +2050,90 @@ AArch64TargetLowering::LowerGlobalAddressELF(SDValue Op,
   }
 }
 
+SDValue
+AArch64TargetLowering::LowerGlobalAddressDarwin(SDValue Op,
+                                                  SelectionDAG &DAG) const {
+  
+  EVT PtrVT = getPointerTy();
+  SDLoc dl(Op);
+  const GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Op);
+  const GlobalValue *GV = GN->getGlobal();
+  unsigned Alignment = GV->getAlignment();
+  Reloc::Model RelocM = getTargetMachine().getRelocationModel();
+  if (GV->isWeakForLinker() && GV->isDeclaration() && RelocM == Reloc::Static) {
+    // Weak undefined symbols can't use ADRP/ADD pair since they should evaluate
+    // to zero when they remain undefined. In PIC mode the GOT can take care of
+    // this, but in absolute mode we use a constant pool load.
+    SDValue PoolAddr;
+    PoolAddr = DAG.getNode(AArch64ISD::WrapperSmall, dl, PtrVT,
+                           DAG.getTargetConstantPool(GV, PtrVT, 0, 0,
+                                                     AArch64II::MO_NO_FLAG),
+                           DAG.getTargetConstantPool(GV, PtrVT, 0, 0,
+                                                     AArch64II::MO_LO12),
+                           DAG.getConstant(8, MVT::i32));
+    SDValue GlobalAddr = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), PoolAddr,
+                                     MachinePointerInfo::getConstantPool(),
+                                     /*isVolatile=*/ false,
+                                     /*isNonTemporal=*/ true,
+                                     /*isInvariant=*/ true, 8);
+    if (GN->getOffset() != 0)
+      return DAG.getNode(ISD::ADD, dl, PtrVT, GlobalAddr,
+                         DAG.getConstant(GN->getOffset(), PtrVT));
+
+    return GlobalAddr;
+  }
+
+  if (Alignment == 0) {
+    const PointerType *GVPtrTy = cast<PointerType>(GV->getType());
+    if (GVPtrTy->getElementType()->isSized()) {
+      Alignment
+        = getDataLayout()->getABITypeAlignment(GVPtrTy->getElementType());
+    } else {
+      // Be conservative if we can't guess, not that it really matters:
+      // functions and labels aren't valid for loads, and the methods used to
+      // actually calculate an address work with any alignment.
+      Alignment = 1;
+    }
+  }
+
+  unsigned char HiFixup, LoFixup;
+  bool UseGOT = getSubtarget()->GVIsIndirectSymbol(GV, RelocM);
+
+  if (UseGOT) {
+    HiFixup = AArch64II::MO_GOT;
+    LoFixup = AArch64II::MO_GOT_LO12;
+    Alignment = 8;
+  } else {
+    HiFixup = AArch64II::MO_NO_FLAG;
+    LoFixup = AArch64II::MO_LO12;
+  }
+
+  // AArch64's small model demands the following sequence:
+  // ADRP x0, somewhere
+  // ADD x0, x0, #:lo12:somewhere ; (or LDR directly).
+  SDValue GlobalRef = DAG.getNode(AArch64ISD::WrapperSmall, dl, PtrVT,
+                                  DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0,
+                                                             HiFixup),
+                                  DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0,
+                                                             LoFixup),
+                                  DAG.getConstant(Alignment, MVT::i32));
+
+  if (UseGOT) {
+    if (GN->getOffset() != 0)
+      GlobalRef = DAG.getNode(ISD::ADD, dl, PtrVT, GlobalRef,
+                       DAG.getConstant(GN->getOffset(), PtrVT));
+    GlobalRef = DAG.getNode(AArch64ISD::GOTLoad, dl, PtrVT, DAG.getEntryNode(),
+                            GlobalRef);
+  } else
+
+  if (GN->getOffset() != 0)
+    return DAG.getNode(ISD::ADD, dl, PtrVT, GlobalRef,
+                       DAG.getConstant(GN->getOffset(), PtrVT));
+
+  return GlobalRef;
+}
+
+
 SDValue AArch64TargetLowering::LowerTLSDescCall(SDValue SymAddr,
                                                 SDValue DescAddr,
                                                 SDLoc DL,
@@ -2677,7 +2761,8 @@ AArch64TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
   case ISD::BlockAddress: return LowerBlockAddress(Op, DAG);
   case ISD::BRCOND: return LowerBRCOND(Op, DAG);
   case ISD::BR_CC: return LowerBR_CC(Op, DAG);
-  case ISD::GlobalAddress: return LowerGlobalAddressELF(Op, DAG);
+  case ISD::GlobalAddress: return Subtarget->isTargetDarwin() ? LowerGlobalAddressDarwin(Op, DAG) : 
+                             LowerGlobalAddressELF(Op, DAG);
   case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG);
   case ISD::JumpTable: return LowerJumpTable(Op, DAG);
   case ISD::SELECT: return LowerSELECT(Op, DAG);
diff --git a/lib/Target/AArch64/AArch64ISelLowering.h b/lib/Target/AArch64/AArch64ISelLowering.h
index 7c7d038..ee31a10 100644
--- a/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/lib/Target/AArch64/AArch64ISelLowering.h
@@ -148,6 +148,8 @@ class AArch64Subtarget;
 class AArch64TargetMachine;
 
 class AArch64TargetLowering : public TargetLowering {
+private:
+  const AArch64Subtarget *Subtarget;
 public:
   explicit AArch64TargetLowering(AArch64TargetMachine &TM);
 
@@ -245,6 +247,7 @@ public:
   SDValue LowerGlobalAddressELFSmall(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerGlobalAddressELFLarge(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerGlobalAddressELF(SDValue Op, SelectionDAG &DAG) const;
+  SDValue LowerGlobalAddressDarwin(SDValue Op, SelectionDAG &DAG) const;
 
   SDValue LowerTLSDescCall(SDValue SymAddr, SDValue DescAddr, SDLoc DL,
                            SelectionDAG &DAG) const;
diff --git a/lib/Target/AArch64/AArch64MCInstLower.cpp b/lib/Target/AArch64/AArch64MCInstLower.cpp
index 7ce5ce3..e7c7f97 100644
--- a/lib/Target/AArch64/AArch64MCInstLower.cpp
+++ b/lib/Target/AArch64/AArch64MCInstLower.cpp
@@ -36,10 +36,16 @@ AArch64AsmPrinter::lowerSymbolOperand(const MachineOperand &MO,
 
   switch (MO.getTargetFlags()) {
   case AArch64II::MO_GOT:
-    Expr = AArch64MCExpr::CreateGOT(Expr, OutContext);
+    if (this->Subtarget->isTargetDarwin())
+      Expr = AArch64MCExpr::CreateGOTDarwin(Expr, OutContext);
+    else
+      Expr = AArch64MCExpr::CreateGOT(Expr, OutContext);
     break;
   case AArch64II::MO_GOT_LO12:
-    Expr = AArch64MCExpr::CreateGOTLo12(Expr, OutContext);
+    if (this->Subtarget->isTargetDarwin())
+      Expr = AArch64MCExpr::CreateGOTLo12Darwin(Expr, OutContext);
+    else
+      Expr = AArch64MCExpr::CreateGOTLo12(Expr, OutContext);
     break;
   case AArch64II::MO_LO12:
     Expr = AArch64MCExpr::CreateLo12(Expr, OutContext);
diff --git a/lib/Target/AArch64/AArch64Subtarget.h b/lib/Target/AArch64/AArch64Subtarget.h
index 4ffb605..b5e43d7 100644
--- a/lib/Target/AArch64/AArch64Subtarget.h
+++ b/lib/Target/AArch64/AArch64Subtarget.h
@@ -47,6 +47,7 @@ public:
 
   bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }
   bool isTargetLinux() const { return TargetTriple.isOSLinux(); }
+  bool isTargetDarwin() const { return TargetTriple.isOSDarwin(); }
 
   bool hasNEON() const { return HasNEON; }
 
diff --git a/lib/Target/AArch64/AArch64TargetObjectFile.cpp b/lib/Target/AArch64/AArch64TargetObjectFile.cpp
index b4452f5..954cad6 100644
--- a/lib/Target/AArch64/AArch64TargetObjectFile.cpp
+++ b/lib/Target/AArch64/AArch64TargetObjectFile.cpp
@@ -13,6 +13,14 @@
 
 
 #include "AArch64TargetObjectFile.h"
+#include "llvm/Target/Mangler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCExpr.h"
+#include "MCTargetDesc/AArch64MCExpr.h"
+#include "llvm/CodeGen/MachineModuleInfoImpls.h"
+
 
 using namespace llvm;
 
@@ -22,3 +30,24 @@ AArch64LinuxTargetObjectFile::Initialize(MCContext &Ctx,
   TargetLoweringObjectFileELF::Initialize(Ctx, TM);
   InitializeELF(TM.Options.UseInitArray);
 }
+
+MCSymbol *AArch64MachOTargetObjectFile::getCFIPersonalitySymbol(
+    const GlobalValue *GV, Mangler *Mang, MachineModuleInfo *MMI) const {
+  MCSymbol *SSym = Mang->getSymbol(GV);
+
+  return SSym;
+}
+
+const MCExpr *AArch64MachOTargetObjectFile::getTTypeGlobalReference(
+    const GlobalValue *GV, Mangler *Mang, MachineModuleInfo *MMI,
+    unsigned Encoding, MCStreamer &Streamer) const {
+  MCSymbol *sym = getContext().CreateTempSymbol();
+  Streamer.EmitLabel(sym);
+  const MCExpr *expr = MCSymbolRefExpr::Create(
+      Mang->getSymbol(GV), MCSymbolRefExpr::VK_GOT, getContext());
+  expr = MCBinaryExpr::CreateSub(
+      expr,
+      MCSymbolRefExpr::Create(sym, MCSymbolRefExpr::VK_None, getContext()),
+      getContext());
+  return expr;
+}
diff --git a/lib/Target/AArch64/AArch64TargetObjectFile.h b/lib/Target/AArch64/AArch64TargetObjectFile.h
index bf0565a..91e9d5e 100644
--- a/lib/Target/AArch64/AArch64TargetObjectFile.h
+++ b/lib/Target/AArch64/AArch64TargetObjectFile.h
@@ -26,6 +26,17 @@ namespace llvm {
     virtual void Initialize(MCContext &Ctx, const TargetMachine &TM);
   };
 
+class AArch64MachOTargetObjectFile : public TargetLoweringObjectFileMachO {
+  virtual MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV,
+                                            Mangler *Mang,
+                                            MachineModuleInfo *MMI) const;
+  virtual const MCExpr *getTTypeGlobalReference(const GlobalValue *GV,
+                                                Mangler *Mang,
+                                                MachineModuleInfo *MMI,
+                                                unsigned Encoding,
+                                                MCStreamer &Streamer) const;
+};
+
 } // end namespace llvm
 
 #endif
diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
index 8a9077c..e3cceca 100644
--- a/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
+++ b/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp
@@ -19,7 +19,11 @@
 #include "llvm/MC/MCELFObjectWriter.h"
 #include "llvm/MC/MCFixupKindInfo.h"
 #include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/SectionKind.h"
 #include "llvm/Support/ELF.h"
+#include "llvm/Support/MachO.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace llvm;
@@ -73,11 +77,147 @@ void AArch64AsmBackend::processFixupValue(const MCAssembler &Asm,
     IsResolved = false;
 }
 
-
 static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value);
 
 namespace {
 
+class DarwinAArch64AsmBackend : public AArch64AsmBackend {
+public:
+  DarwinAArch64AsmBackend(const Target &T, const StringRef TT, uint8_t _OSABI)
+      : AArch64AsmBackend(T, TT) {}
+  bool mayNeedRelaxation(const MCInst &) const { return false; }
+
+  virtual bool doesSectionRequireSymbols(const MCSection &Section) const {
+    SectionKind kind = Section.getKind();
+    return kind.isDataRel() || kind.isReadOnlyWithRel() || kind.isMetadata() ||
+           kind.isMergeableConst();
+  }
+
+  unsigned int getNumFixupKinds() const { return AArch64::NumTargetFixupKinds; }
+
+  bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
+                            const MCRelaxableFragment *DF,
+                            const MCAsmLayout &Layout) const {
+    return false;
+  }
+
+  virtual void processFixupValue(const MCAssembler &Asm,
+                                 const MCAsmLayout &Layout,
+                                 const MCFixup &Fixup, const MCFragment *DF,
+                                 MCValue &Target, uint64_t &Value,
+                                 bool &IsResolved) {
+    AArch64AsmBackend::processFixupValue(Asm, Layout, Fixup, DF, Target, Value,
+                                         IsResolved);
+    if ((uint32_t)Fixup.getKind() == AArch64::fixup_a64_call)
+      IsResolved = false;
+  }
+  void relaxInstruction(const MCInst &, llvm::MCInst &) const {
+    llvm_unreachable("Cannot relax instructions");
+  }
+  const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
+    const static MCFixupKindInfo Infos[AArch64::NumTargetFixupKinds] = {
+      // This table *must* be in the order that the fixup_* kinds are defined in
+      // AArch64FixupKinds.h.
+      //
+      // Name                   Offset (bits)    Size (bits)    Flags
+      { "fixup_a64_ld_prel", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+      { "fixup_a64_adr_prel", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+      { "fixup_a64_adr_prel_page", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+      { "fixup_a64_add_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst8_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst16_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst32_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst64_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst128_lo12", 0, 32, 0 },
+      { "fixup_a64_tstbr", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+      { "fixup_a64_condbr", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+      { "fixup_a64_uncondbr", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+      { "fixup_a64_call", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+      { "fixup_a64_movw_uabs_g0", 0, 32, 0 },
+      { "fixup_a64_movw_uabs_g0_nc", 0, 32, 0 },
+      { "fixup_a64_movw_uabs_g1", 0, 32, 0 },
+      { "fixup_a64_movw_uabs_g1_nc", 0, 32, 0 },
+      { "fixup_a64_movw_uabs_g2", 0, 32, 0 },
+      { "fixup_a64_movw_uabs_g2_nc", 0, 32, 0 },
+      { "fixup_a64_movw_uabs_g3", 0, 32, 0 },
+      { "fixup_a64_movw_sabs_g0", 0, 32, 0 },
+      { "fixup_a64_movw_sabs_g1", 0, 32, 0 },
+      { "fixup_a64_movw_sabs_g2", 0, 32, 0 },
+      { "fixup_a64_adr_prel_got_page", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+      { "fixup_a64_ld64_got_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_movw_dtprel_g2", 0, 32, 0 },
+      { "fixup_a64_movw_dtprel_g1", 0, 32, 0 },
+      { "fixup_a64_movw_dtprel_g1_nc", 0, 32, 0 },
+      { "fixup_a64_movw_dtprel_g0", 0, 32, 0 },
+      { "fixup_a64_movw_dtprel_g0_nc", 0, 32, 0 },
+      { "fixup_a64_add_dtprel_hi12", 0, 32, 0 },
+      { "fixup_a64_add_dtprel_lo12", 0, 32, 0 },
+      { "fixup_a64_add_dtprel_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_ldst8_dtprel_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst8_dtprel_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_ldst16_dtprel_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst16_dtprel_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_ldst32_dtprel_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst32_dtprel_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_ldst64_dtprel_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst64_dtprel_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_movw_gottprel_g1", 0, 32, 0 },
+      { "fixup_a64_movw_gottprel_g0_nc", 0, 32, 0 },
+      { "fixup_a64_adr_gottprel_page", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+      { "fixup_a64_ld64_gottprel_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_ld_gottprel_prel19", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+      { "fixup_a64_movw_tprel_g2", 0, 32, 0 },
+      { "fixup_a64_movw_tprel_g1", 0, 32, 0 },
+      { "fixup_a64_movw_tprel_g1_nc", 0, 32, 0 },
+      { "fixup_a64_movw_tprel_g0", 0, 32, 0 },
+      { "fixup_a64_movw_tprel_g0_nc", 0, 32, 0 },
+      { "fixup_a64_add_tprel_hi12", 0, 32, 0 },
+      { "fixup_a64_add_tprel_lo12", 0, 32, 0 },
+      { "fixup_a64_add_tprel_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_ldst8_tprel_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst8_tprel_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_ldst16_tprel_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst16_tprel_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_ldst32_tprel_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst32_tprel_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_ldst64_tprel_lo12", 0, 32, 0 },
+      { "fixup_a64_ldst64_tprel_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_tlsdesc_adr_page", 0, 32, MCFixupKindInfo::FKF_IsPCRel },
+      { "fixup_a64_tlsdesc_ld64_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_tlsdesc_add_lo12_nc", 0, 32, 0 },
+      { "fixup_a64_tlsdesc_call", 0, 0, 0 }
+    };
+    if (Kind < FirstTargetFixupKind)
+      return MCAsmBackend::getFixupKindInfo(Kind);
+
+    assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
+           "Invalid kind!");
+    return Infos[Kind - FirstTargetFixupKind];
+  }
+
+  void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
+                  uint64_t Value) const {
+    unsigned NumBytes = getFixupKindInfo(Fixup.getKind()).TargetSize / 8;
+    Value = adjustFixupValue(Fixup.getKind(), Value);
+    if (!Value)
+      return; // Doesn't change encoding.
+
+    unsigned Offset = Fixup.getOffset();
+    assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!");
+
+    // For each byte of the fragment that the fixup touches, mask in the bits
+    // from the fixup value.
+    for (unsigned i = 0; i != NumBytes; ++i) {
+      Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff);
+    }
+  }
+
+  MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
+    return createAArch64MachOObjectWriter(OS, MachO::CPU_TYPE_ARM64,
+                                          MachO::CPU_SUBTYPE_ARM64_ALL);
+  }
+};
+
 class ELFAArch64AsmBackend : public AArch64AsmBackend {
 public:
   uint8_t OSABI;
@@ -581,5 +721,7 @@ MCAsmBackend *
 llvm::createAArch64AsmBackend(const Target &T, const MCRegisterInfo &MRI,
                               StringRef TT, StringRef CPU) {
   Triple TheTriple(TT);
+  if (TheTriple.isOSDarwin())
+    return new DarwinAArch64AsmBackend(T, TT, TheTriple.getOS());
   return new ELFAArch64AsmBackend(T, TT, TheTriple.getOS());
 }
diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
index 8ec8cbf..9200742 100644
--- a/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
+++ b/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.cpp
@@ -12,6 +12,9 @@
 //===----------------------------------------------------------------------===//
 
 #include "AArch64MCAsmInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCExpr.h"
 
 using namespace llvm;
 
@@ -39,3 +42,34 @@ AArch64ELFMCAsmInfo::AArch64ELFMCAsmInfo() {
   // Exceptions handling
   ExceptionsType = ExceptionHandling::DwarfCFI;
 }
+
+AArch64MachOMCAsmInfo::AArch64MachOMCAsmInfo() {
+  PointerSize = 8;
+
+  Code32Directive = ".code\t32";
+  SupportsDebugInformation = true;
+  ExceptionsType = ExceptionHandling::DwarfCFI;
+
+  /*Data16bitsDirective = "\t.hword\t";
+  Data32bitsDirective = "\t.word\t";
+  Data64bitsDirective = "\t.xword\t";
+
+  UseDataRegionDirectives = true;
+
+  WeakRefDirective = "\t.weak\t";
+
+  HasLEB128 = true;
+  SupportsDebugInformation = true;
+
+  // Exceptions handling
+  ExceptionsType = ExceptionHandling::DwarfCFI;*/
+}
+
+const MCExpr *AArch64MachOMCAsmInfo::getExprForPersonalitySymbol(
+    const MCSymbol *Sym, unsigned Encoding, MCStreamer &Streamer) const {
+  MCContext &Context = Streamer.getContext();
+  const MCExpr *Res =
+      MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_GOT, Context);
+  const MCExpr *Four = MCConstantExpr::Create(4, Context);
+  return MCBinaryExpr::CreateAdd(Res, Four, Context);
+}
diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h b/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h
index a20bc47..61ad0cc 100644
--- a/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h
+++ b/lib/Target/AArch64/MCTargetDesc/AArch64MCAsmInfo.h
@@ -15,6 +15,7 @@
 #define LLVM_AARCH64TARGETASMINFO_H
 
 #include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCAsmInfoDarwin.h"
 
 namespace llvm {
 
@@ -22,6 +23,13 @@ namespace llvm {
     explicit AArch64ELFMCAsmInfo();
   };
 
+struct AArch64MachOMCAsmInfo : public MCAsmInfoDarwin {
+  explicit AArch64MachOMCAsmInfo();
+  virtual const MCExpr *getExprForPersonalitySymbol(const MCSymbol *Sym,
+                                                    unsigned Encoding,
+                                                    MCStreamer &Streamer) const;
+};
+
 } // namespace llvm
 
 #endif
diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
index 7bfaecc..36d6c5f 100644
--- a/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
+++ b/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
@@ -170,6 +170,7 @@ getOffsetUImm12OpValue(const MCInst &MI, unsigned OpIdx,
     break;
   }
   case AArch64MCExpr::VK_AARCH64_GOT_LO12:
+  case AArch64MCExpr::VK_AARCH64_GOT_LO12_DARWIN:
     assert(MemSize == 8 && "Invalid fixup for operation");
     FixupKind = AArch64::fixup_a64_ld64_got_lo12_nc;
     break;
@@ -283,6 +284,7 @@ AArch64MCCodeEmitter::getAdrpLabelOpValue(const MCInst &MI, unsigned OpIdx,
     FixupKind = AArch64::fixup_a64_adr_prel_page;
     break;
   case AArch64MCExpr::VK_AARCH64_GOT:
+  case AArch64MCExpr::VK_AARCH64_GOT_DARWIN:
     FixupKind = AArch64::fixup_a64_adr_prel_got_page;
     break;
   case AArch64MCExpr::VK_AARCH64_GOTTPREL:
diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp
index c1abfe7..4344efc 100644
--- a/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp
+++ b/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp
@@ -32,6 +32,8 @@ void AArch64MCExpr::PrintImpl(raw_ostream &OS) const {
   default: llvm_unreachable("Invalid kind!");
   case VK_AARCH64_GOT:              OS << ":got:"; break;
   case VK_AARCH64_GOT_LO12:         OS << ":got_lo12:"; break;
+  case VK_AARCH64_GOT_DARWIN:       
+  case VK_AARCH64_GOT_LO12_DARWIN:  break;
   case VK_AARCH64_LO12:             OS << ":lo12:"; break;
   case VK_AARCH64_ABS_G0:           OS << ":abs_g0:"; break;
   case VK_AARCH64_ABS_G0_NC:        OS << ":abs_g0_nc:"; break;
@@ -74,6 +76,12 @@ void AArch64MCExpr::PrintImpl(raw_ostream &OS) const {
   Expr->print(OS);
   if (Expr->getKind() != MCExpr::SymbolRef)
     OS << ')';
+  switch (Kind) {
+    case VK_AARCH64_GOT_DARWIN:       OS << "@GOTPAGE"; break;
+    case VK_AARCH64_GOT_LO12_DARWIN:  OS << "@GOTPAGEOFF"; break;
+    default:
+      break;
+  }
 }
 
 bool
diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.h b/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.h
index d9798ae..8cefa99 100644
--- a/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.h
+++ b/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.h
@@ -25,6 +25,8 @@ public:
     VK_AARCH64_None,
     VK_AARCH64_GOT,      // :got: modifier in assembly
     VK_AARCH64_GOT_LO12, // :got_lo12:
+    VK_AARCH64_GOT_DARWIN,      // :got: modifier in assembly
+    VK_AARCH64_GOT_LO12_DARWIN, // :got_lo12:
     VK_AARCH64_LO12,     // :lo12:
 
     VK_AARCH64_ABS_G0, // :abs_g0:
@@ -93,6 +95,15 @@ public:
     return Create(VK_AARCH64_GOT_LO12, Expr, Ctx);
   }
 
+  static const AArch64MCExpr *CreateGOTDarwin(const MCExpr *Expr, MCContext &Ctx) {
+    return Create(VK_AARCH64_GOT_DARWIN, Expr, Ctx);
+  }
+
+  static const AArch64MCExpr *CreateGOTLo12Darwin(const MCExpr *Expr,
+                                            MCContext &Ctx) {
+    return Create(VK_AARCH64_GOT_LO12_DARWIN, Expr, Ctx);
+  }
+
   static const AArch64MCExpr *CreateDTPREL_G1(const MCExpr *Expr,
                                              MCContext &Ctx) {
     return Create(VK_AARCH64_DTPREL_G1, Expr, Ctx);
diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp
index 58fc95c..32899b9 100644
--- a/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp
+++ b/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp
@@ -61,7 +61,11 @@ static MCAsmInfo *createAArch64MCAsmInfo(const MCRegisterInfo &MRI,
                                          StringRef TT) {
   Triple TheTriple(TT);
 
-  MCAsmInfo *MAI = new AArch64ELFMCAsmInfo();
+  MCAsmInfo *MAI;
+  if (TheTriple.isOSDarwin())
+    MAI = new AArch64MachOMCAsmInfo();
+  else
+    MAI = new AArch64ELFMCAsmInfo();
   unsigned Reg = MRI.getDwarfRegNum(AArch64::XSP, true);
   MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(0, Reg, 0);
   MAI->addInitialFrameState(Inst);
@@ -77,7 +81,9 @@ static MCCodeGenInfo *createAArch64MCCodeGenInfo(StringRef TT, Reloc::Model RM,
     // On ELF platforms the default static relocation model has a smart enough
     // linker to cope with referencing external symbols defined in a shared
     // library. Hence DynamicNoPIC doesn't need to be promoted to PIC.
-    RM = Reloc::Static;
+    Triple TheTriple(TT);
+
+    RM = TheTriple.isOSDarwin() ? Reloc::PIC_ : Reloc::Static;
   }
 
   if (CM == CodeModel::Default)
@@ -101,6 +107,8 @@ static MCStreamer *createMCStreamer(const Target &T, StringRef TT,
                                     bool NoExecStack) {
   Triple TheTriple(TT);
 
+  if (TheTriple.isOSDarwin())
+    return createMachOStreamer(Ctx, MAB, OS, Emitter, RelaxAll);
   return createAArch64ELFStreamer(Ctx, MAB, OS, Emitter, RelaxAll, NoExecStack);
 }
 
diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h b/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h
index 670e657..c40b3e6 100644
--- a/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h
+++ b/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.h
@@ -43,6 +43,10 @@ MCCodeEmitter *createAArch64MCCodeEmitter(const MCInstrInfo &MCII,
 MCObjectWriter *createAArch64ELFObjectWriter(raw_ostream &OS,
                                              uint8_t OSABI);
 
+MCObjectWriter *createAArch64MachOObjectWriter(raw_ostream &OS,
+                                               uint32_t CPUType,
+                                               uint32_t CPUSubtype);
+
 MCAsmBackend *createAArch64AsmBackend(const Target &T,
                                       const MCRegisterInfo &MRI,
                                       StringRef TT, StringRef CPU);
diff --git a/lib/Target/AArch64/MCTargetDesc/AArch64MachOObjectWriter.cpp b/lib/Target/AArch64/MCTargetDesc/AArch64MachOObjectWriter.cpp
new file mode 100644
index 0000000..0531a01
--- /dev/null
+++ b/lib/Target/AArch64/MCTargetDesc/AArch64MachOObjectWriter.cpp
@@ -0,0 +1,266 @@
+//===-- AArch64MachOObjectWriter.cpp - AArch64 ELF Writer
+//-------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file handles ELF-specific object emission, converting LLVM's internal
+// fixups into the appropriate relocations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/AArch64FixupKinds.h"
+#include "MCTargetDesc/AArch64MCTargetDesc.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCMachObjectWriter.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+namespace {
+class AArch64MachOObjectWriter : public MCMachObjectTargetWriter {
+
+  bool requiresExternRelocation(MachObjectWriter *Writer,
+                                const MCAssembler &Asm,
+                                const MCFragment &Fragment, unsigned RelocType,
+                                const MCSymbolData *SD, uint64_t FixedValue);
+
+public:
+  AArch64MachOObjectWriter(uint32_t CPUType, uint32_t CPUSubtype);
+
+  virtual ~AArch64MachOObjectWriter();
+
+protected:
+  virtual void
+  RecordRelocation(MachObjectWriter *Writer, const MCAssembler &Asm,
+                   const MCAsmLayout &Layout, const MCFragment *Fragment,
+                   const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue);
+
+private:
+};
+}
+
+AArch64MachOObjectWriter::AArch64MachOObjectWriter(uint32_t CPUType,
+                                                   uint32_t CPUSubtype)
+    : MCMachObjectTargetWriter(/*Is64Bit*/ true, CPUType, CPUSubtype,
+                               /* aggressive symbol folding */ true) {}
+
+AArch64MachOObjectWriter::~AArch64MachOObjectWriter() {}
+
+static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType,
+                                     unsigned &Log2Size) {
+  RelocType = unsigned(MachO::ARM64_RELOC_UNSIGNED);
+  Log2Size = ~0U;
+
+  AArch64::Fixups realKind = (AArch64::Fixups)Kind;
+  switch (Kind) {
+  default:
+    return false;
+
+  case FK_Data_1:
+    Log2Size = llvm::Log2_32(1);
+    return true;
+  case FK_Data_2:
+    Log2Size = llvm::Log2_32(2);
+    return true;
+  case FK_Data_4:
+    Log2Size = llvm::Log2_32(4);
+    return true;
+  case FK_Data_8:
+    Log2Size = llvm::Log2_32(8);
+    return true;
+  case AArch64::fixup_a64_adr_prel_page:
+    RelocType = unsigned(MachO::ARM64_RELOC_PAGE21);
+    Log2Size = llvm::Log2_32(4);
+    return true;
+  case AArch64::fixup_a64_ldst64_lo12:
+    RelocType = unsigned(MachO::ARM64_RELOC_PAGEOFF12);
+    Log2Size = llvm::Log2_32(4);
+    return true;
+  case AArch64::fixup_a64_ldst32_lo12:
+    RelocType = unsigned(MachO::ARM64_RELOC_PAGEOFF12);
+    Log2Size = llvm::Log2_32(4);
+    return true;
+  case AArch64::fixup_a64_add_lo12:
+    RelocType = unsigned(MachO::ARM64_RELOC_PAGEOFF12);
+    Log2Size = llvm::Log2_32(4);
+    return true;
+  case AArch64::fixup_a64_adr_prel_got_page:
+    RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGE21);
+    Log2Size = llvm::Log2_32(4);
+    return true;
+  case AArch64::fixup_a64_ld64_got_lo12_nc:
+    RelocType = unsigned(MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12);
+    Log2Size = llvm::Log2_32(4);
+    return true;
+  case AArch64::fixup_a64_uncondbr:
+  case AArch64::fixup_a64_call:
+    RelocType = unsigned(MachO::ARM64_RELOC_BRANCH26);
+    Log2Size = llvm::Log2_32(4);
+    return true;
+  case AArch64::fixup_a64_adr_gottprel_page:
+    RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGE21);
+    Log2Size = llvm::Log2_32(4);
+    return true;
+  case AArch64::fixup_a64_ld64_gottprel_lo12_nc:
+    RelocType = unsigned(MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
+    Log2Size = llvm::Log2_32(4);
+    return true;
+  }
+}
+
+bool AArch64MachOObjectWriter::requiresExternRelocation(
+    MachObjectWriter *Writer, const MCAssembler &Asm,
+    const MCFragment &Fragment, unsigned RelocType, const MCSymbolData *SD,
+    uint64_t FixedValue) {
+  // Most cases can be identified purely from the symbol.
+  if (Writer->doesSymbolRequireExternRelocation(SD)) {
+    return true;
+  }
+  switch (RelocType) {
+  default:
+    return false;
+  case MachO::ARM64_RELOC_UNSIGNED:
+  case MachO::ARM64_RELOC_PAGEOFF12:
+  case MachO::ARM64_RELOC_PAGE21:
+  case MachO::ARM64_RELOC_BRANCH26:
+  case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
+  case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
+    if (!SD->getSymbol().isTemporary()) {
+      return true;
+    }
+    {
+      SectionKind kind = SD->getSymbol().getSection().getKind();
+      if (kind.isDataRel() || kind.isReadOnlyWithRel() || kind.isMetadata() ||
+          kind.isMergeableConst())
+        return true;
+    }
+    return false;
+  }
+}
+
+void AArch64MachOObjectWriter::RecordRelocation(
+    MachObjectWriter *Writer, const MCAssembler &Asm, const MCAsmLayout &Layout,
+    const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target,
+    uint64_t &FixedValue) {
+  unsigned IsPCRel = Writer->isFixupKindPCRel(Asm, Fixup.getKind());
+  unsigned Log2Size;
+  unsigned RelocType = MachO::ARM_RELOC_VANILLA;
+
+  MCSymbolRefExpr::VariantKind Modifier = MCSymbolRefExpr::VK_None;
+  if (Target.getSymA())
+    Modifier = Target.getSymA()->getKind();
+  if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size))
+    // If we failed to get fixup kind info, it's because there's no legal
+    // relocation type for the fixup kind. This happens when it's a fixup that's
+    // expected to always be resolvable at assembly time and not have any
+    // relocations needed.
+    Asm.getContext().FatalError(Fixup.getLoc(),
+                                "unsupported relocation on symbol");
+
+  if (Modifier == MCSymbolRefExpr::VK_GOT) {
+    RelocType = MachO::ARM64_RELOC_POINTER_TO_GOT;
+  }
+
+  // Get the symbol data, if any.
+  MCSymbolData *SD = 0;
+  if (Target.getSymA())
+    SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
+
+  // FIXME: For other platforms, we need to use scattered relocations for
+  // internal relocations with offsets.  If this is an internal relocation with
+  // an offset, it also needs a scattered relocation entry.
+  //
+  // Is this right for ARM?
+  uint32_t Offset = Target.getConstant();
+
+  if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
+    const MCSymbol &SymbolB = RefB->getSymbol();
+    MCSymbolData &SDB = Asm.getSymbolData(SymbolB);
+    IsPCRel = true;
+
+    // Offset of the symbol in the section
+    int64_t a = Layout.getSymbolOffset(&SDB);
+
+    // Offset of the relocation in the section
+    int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
+    Offset += b - a;
+  }
+
+  if (IsPCRel && RelocType == MachO::ARM_RELOC_VANILLA)
+    Offset += 1 << Log2Size;
+
+  // See <reloc.h>.
+  uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
+  unsigned Index = 0;
+  unsigned IsExtern = 0;
+  unsigned Type = 0;
+
+  if (Target.isAbsolute()) { // constant
+    // FIXME!
+    report_fatal_error("FIXME: relocations to absolute targets "
+                       "not yet implemented");
+  } else {
+    // Resolve constant variables.
+    if (SD->getSymbol().isVariable()) {
+      int64_t Res;
+      if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute(
+              Res, Layout, Writer->getSectionAddressMap())) {
+        FixedValue = Res;
+        return;
+      }
+    }
+
+    // Check whether we need an external or internal relocation.
+    if (requiresExternRelocation(Writer, Asm, *Fragment, RelocType, SD,
+                                 FixedValue)) {
+      IsExtern = 1;
+      Index = SD->getIndex();
+
+      // For external relocations, make sure to offset the fixup value to
+      // compensate for the addend of the symbol address, if it was
+      // undefined. This occurs with weak definitions, for example.
+      if (!SD->Symbol->isUndefined())
+        FixedValue -= Layout.getSymbolOffset(SD);
+    } else {
+      // The index is the section ordinal (1-based).
+      const MCSectionData &SymSD =
+          Asm.getSectionData(SD->getSymbol().getSection());
+      Index = SymSD.getOrdinal() + 1;
+      FixedValue += Writer->getSectionAddress(&SymSD);
+    }
+    if (IsPCRel)
+      FixedValue -= Writer->getSectionAddress(Fragment->getParent());
+
+    // The type is determined by the fixup kind.
+    Type = RelocType;
+  }
+
+  // struct relocation_info (8 bytes)
+  MachO::any_relocation_info MRE;
+  MRE.r_word0 = FixupOffset;
+  MRE.r_word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) |
+                 (IsExtern << 27) | (Type << 28));
+
+  Writer->addRelocation(Fragment->getParent(), MRE);
+
+  if (IsExtern)
+    FixedValue = 0;
+}
+
+MCObjectWriter *llvm::createAArch64MachOObjectWriter(raw_ostream &OS,
+                                                     uint32_t CPUType,
+                                                     uint32_t CPUSubtype) {
+  MCMachObjectTargetWriter *MOTW =
+      new AArch64MachOObjectWriter(CPUType, CPUSubtype);
+  return createMachObjectWriter(MOTW, OS, /*IsLittleEndian=*/true);
+}
diff --git a/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt b/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt
index 44c66a2..cf045a0 100644
--- a/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt
+++ b/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt
@@ -6,6 +6,7 @@ add_llvm_library(LLVMAArch64Desc
   AArch64MCCodeEmitter.cpp
   AArch64MCExpr.cpp
   AArch64MCTargetDesc.cpp
+  AArch64MachOObjectWriter.cpp
   )
 add_dependencies(LLVMAArch64Desc AArch64CommonTableGen)
 


More information about the llvm-dev mailing list