MC/Mach-O: Split out RecordARMRelocation for now, it is weird enough it isn't
[oota-llvm.git] / lib / MC / MachObjectWriter.cpp
index d31ecef27a8411e7a78bf12962f45ae6b25d8e19..a4c612d0d696c02f9fb6b14c2b3bbec97e8b2ddc 100644 (file)
@@ -7,6 +7,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/MC/MCMachObjectWriter.h"
+#include "llvm/ADT/OwningPtr.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/MC/MCAssembler.h"
@@ -50,24 +52,6 @@ static unsigned getFixupKindLog2Size(unsigned Kind) {
   }
 }
 
-static bool isFixupKindPCRel(unsigned Kind) {
-  switch (Kind) {
-  default:
-    return false;
-  case FK_PCRel_1:
-  case FK_PCRel_2:
-  case FK_PCRel_4:
-  case X86::reloc_riprel_4byte:
-  case X86::reloc_riprel_4byte_movq_load:
-    return true;
-  }
-}
-
-static bool isFixupKindRIPRel(unsigned Kind) {
-  return Kind == X86::reloc_riprel_4byte ||
-    Kind == X86::reloc_riprel_4byte_movq_load;
-}
-
 static bool doesSymbolRequireExternRelocation(MCSymbolData *SD) {
   // Undefined symbols are always extern.
   if (SD->Symbol->isUndefined())
@@ -179,6 +163,9 @@ class MachObjectWriter : public MCObjectWriter {
     }
   };
 
+  /// The target specific Mach-O writer instance.
+  llvm::OwningPtr<MCMachObjectTargetWriter> TargetObjectWriter;
+
   /// @name Relocation Data
   /// @{
 
@@ -197,6 +184,19 @@ class MachObjectWriter : public MCObjectWriter {
 
   /// @}
 
+private:
+  /// @name Utility Methods
+  /// @{
+
+  bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) {
+    const MCFixupKindInfo &FKI = Asm.getBackend().getFixupKindInfo(
+      (MCFixupKind) Kind);
+
+    return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel;
+  }
+
+  /// @}
+
   SectionAddrMap SectionAddress;
   uint64_t getSectionAddress(const MCSectionData* SD) const {
     return SectionAddress.lookup(SD);
@@ -225,19 +225,23 @@ class MachObjectWriter : public MCObjectWriter {
     return OffsetToAlignment(EndAddr, NextSD.getAlignment());
   }
 
-  unsigned Is64Bit : 1;
-
-  uint32_t CPUType;
-  uint32_t CPUSubtype;
-
 public:
-  MachObjectWriter(raw_ostream &_OS,
-                   bool _Is64Bit, uint32_t _CPUType, uint32_t _CPUSubtype,
+  MachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_ostream &_OS,
                    bool _IsLittleEndian)
-    : MCObjectWriter(_OS, _IsLittleEndian),
-      Is64Bit(_Is64Bit), CPUType(_CPUType), CPUSubtype(_CPUSubtype) {
+    : MCObjectWriter(_OS, _IsLittleEndian), TargetObjectWriter(MOTW) {
   }
 
+  /// @name Target Writer Proxy Accessors
+  /// @{
+
+  bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
+  bool isARM() const {
+    uint32_t CPUType = TargetObjectWriter->getCPUType() & mach::CTFM_ArchMask;
+    return CPUType == mach::CTM_ARM;
+  }
+
+  /// @}
+
   void WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize,
                    bool SubsectionsViaSymbols) {
     uint32_t Flags = 0;
@@ -251,19 +255,19 @@ public:
     uint64_t Start = OS.tell();
     (void) Start;
 
-    Write32(Is64Bit ? macho::HM_Object64 : macho::HM_Object32);
+    Write32(is64Bit() ? macho::HM_Object64 : macho::HM_Object32);
 
-    Write32(CPUType);
-    Write32(CPUSubtype);
+    Write32(TargetObjectWriter->getCPUType());
+    Write32(TargetObjectWriter->getCPUSubtype());
 
     Write32(macho::HFT_Object);
     Write32(NumLoadCommands);
     Write32(LoadCommandsSize);
     Write32(Flags);
-    if (Is64Bit)
+    if (is64Bit())
       Write32(0); // reserved
 
-    assert(OS.tell() - Start == Is64Bit ? 
+    assert(OS.tell() - Start == is64Bit() ? 
            macho::Header64Size : macho::Header32Size);
   }
 
@@ -281,15 +285,16 @@ public:
     uint64_t Start = OS.tell();
     (void) Start;
 
-    unsigned SegmentLoadCommandSize = Is64Bit ? macho::SegmentLoadCommand64Size:
+    unsigned SegmentLoadCommandSize =
+      is64Bit() ? macho::SegmentLoadCommand64Size:
       macho::SegmentLoadCommand32Size;
-    Write32(Is64Bit ? macho::LCT_Segment64 : macho::LCT_Segment);
+    Write32(is64Bit() ? macho::LCT_Segment64 : macho::LCT_Segment);
     Write32(SegmentLoadCommandSize +
-            NumSections * (Is64Bit ? macho::Section64Size :
+            NumSections * (is64Bit() ? macho::Section64Size :
                            macho::Section32Size));
 
     WriteBytes("", 16);
-    if (Is64Bit) {
+    if (is64Bit()) {
       Write64(0); // vmaddr
       Write64(VMSize); // vmsize
       Write64(SectionDataStartOffset); // file offset
@@ -328,7 +333,7 @@ public:
     const MCSectionMachO &Section = cast<MCSectionMachO>(SD.getSection());
     WriteBytes(Section.getSectionName(), 16);
     WriteBytes(Section.getSegmentName(), 16);
-    if (Is64Bit) {
+    if (is64Bit()) {
       Write64(getSectionAddress(&SD)); // address
       Write64(SectionSize); // size
     } else {
@@ -348,10 +353,10 @@ public:
     Write32(Flags);
     Write32(IndirectSymBase.lookup(&SD)); // reserved1
     Write32(Section.getStubSize()); // reserved2
-    if (Is64Bit)
+    if (is64Bit())
       Write32(0); // reserved3
 
-    assert(OS.tell() - Start == Is64Bit ? macho::Section64Size :
+    assert(OS.tell() - Start == is64Bit() ? macho::Section64Size :
            macho::Section32Size);
   }
 
@@ -469,7 +474,7 @@ public:
     // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc'
     // value.
     Write16(Flags);
-    if (Is64Bit)
+    if (is64Bit())
       Write64(Address);
     else
       Write32(Address);
@@ -489,11 +494,15 @@ public:
   //  - Input errors, where something cannot be correctly encoded. 'as' allows
   //    these through in many cases.
 
+  static bool isFixupKindRIPRel(unsigned Kind) {
+    return Kind == X86::reloc_riprel_4byte ||
+      Kind == X86::reloc_riprel_4byte_movq_load;
+  }
   void RecordX86_64Relocation(const MCAssembler &Asm, const MCAsmLayout &Layout,
                               const MCFragment *Fragment,
                               const MCFixup &Fixup, MCValue Target,
                               uint64_t &FixedValue) {
-    unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind());
+    unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind());
     unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind());
     unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
 
@@ -731,7 +740,7 @@ public:
                                  const MCFixup &Fixup, MCValue Target,
                                  uint64_t &FixedValue) {
     uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
-    unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind());
+    unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind());
     unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
     unsigned Type = macho::RIT_Vanilla;
 
@@ -760,14 +769,15 @@ public:
       // Note that there is no longer any semantic difference between these two
       // relocation types from the linkers point of view, this is done solely
       // for pedantic compatibility with 'as'.
-      Type = A_SD->isExternal() ? macho::RIT_Difference :
-        macho::RIT_LocalDifference;
+      Type = A_SD->isExternal() ? (unsigned)macho::RIT_Difference :
+        (unsigned)macho::RIT_Generic_LocalDifference;
       Value2 = getSymbolAddress(B_SD, Layout);
       FixedValue -= getSectionAddress(B_SD->getFragment()->getParent());
     }
 
     // Relocations are written out in reverse order, so the PAIR comes first.
-    if (Type == macho::RIT_Difference || Type == macho::RIT_LocalDifference) {
+    if (Type == macho::RIT_Difference ||
+        Type == macho::RIT_Generic_LocalDifference) {
       macho::RelocationEntry MRE;
       MRE.Word0 = ((0         <<  0) |
                    (macho::RIT_Pair  << 24) |
@@ -794,7 +804,7 @@ public:
                             const MCFixup &Fixup, MCValue Target,
                             uint64_t &FixedValue) {
     assert(Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP &&
-           !Is64Bit &&
+           !is64Bit() &&
            "Should only be called with a 32-bit TLVP relocation!");
 
     unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
@@ -825,23 +835,34 @@ public:
     // struct relocation_info (8 bytes)
     macho::RelocationEntry MRE;
     MRE.Word0 = Value;
-    MRE.Word1 = ((Index     <<  0) |
-                 (IsPCRel   << 24) |
-                 (Log2Size  << 25) |
-                 (1         << 27) | // Extern
-                 (macho::RIT_TLV   << 28)); // Type
+    MRE.Word1 = ((Index                  <<  0) |
+                 (IsPCRel                << 24) |
+                 (Log2Size               << 25) |
+                 (1                      << 27) | // Extern
+                 (macho::RIT_Generic_TLV << 28)); // Type
     Relocations[Fragment->getParent()].push_back(MRE);
   }
 
+  void RecordARMRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout,
+                           const MCFragment *Fragment, const MCFixup &Fixup,
+                           MCValue Target, uint64_t &FixedValue) {
+    // FIXME!
+  }
+
   void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout,
                         const MCFragment *Fragment, const MCFixup &Fixup,
                         MCValue Target, uint64_t &FixedValue) {
-    if (Is64Bit) {
+    // FIXME: These needs to be factored into the target Mach-O writer.
+    if (isARM()) {
+      RecordARMRelocation(Asm, Layout, Fragment, Fixup, Target, FixedValue);
+      return;
+    }
+    if (is64Bit()) {
       RecordX86_64Relocation(Asm, Layout, Fragment, Fixup, Target, FixedValue);
       return;
     }
 
-    unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind());
+    unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind());
     unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
 
     // If this is a 32-bit TLVP reloc it's handled a bit differently.
@@ -884,6 +905,17 @@ public:
       // FIXME: Currently, these are never generated (see code below). I cannot
       // find a case where they are actually emitted.
       Type = macho::RIT_Vanilla;
+    } else if (SD->getSymbol().isVariable()) {
+      const MCExpr *Value = SD->getSymbol().getVariableValue();
+      int64_t Res;
+      bool isAbs = Value->EvaluateAsAbsolute(Res, Layout, SectionAddress);
+      if (isAbs) {
+        FixedValue = Res;
+        return;
+      } else {
+        report_fatal_error("unsupported relocation of variable '" +
+                           SD->getSymbol().getName() + "'");
+      }
     } else {
       // Check whether we need an external or internal relocation.
       if (doesSymbolRequireExternRelocation(SD)) {
@@ -1107,15 +1139,48 @@ public:
                        UndefinedSymbolData);
   }
 
+  bool IsSymbolRefDifferenceFullyResolved(const MCAssembler &Asm,
+                                          const MCSymbolRefExpr *A,
+                                          const MCSymbolRefExpr *B,
+                                          bool InSet) const {
+    if (InSet)
+      return true;
+
+    if (!TargetObjectWriter->useAggressiveSymbolFolding())
+      return false;
+
+    // The effective address is
+    //     addr(atom(A)) + offset(A)
+    //   - addr(atom(B)) - offset(B)
+    // and the offsets are not relocatable, so the fixup is fully resolved when
+    //  addr(atom(A)) - addr(atom(B)) == 0.
+    const MCSymbolData *A_Base = 0, *B_Base = 0;
+
+    // Modified symbol references cannot be resolved.
+    if (A->getKind() != MCSymbolRefExpr::VK_None ||
+        B->getKind() != MCSymbolRefExpr::VK_None)
+      return false;
+
+    A_Base = Asm.getAtom(&Asm.getSymbolData(A->getSymbol()));
+    if (!A_Base)
+      return false;
+
+    B_Base = Asm.getAtom(&Asm.getSymbolData(B->getSymbol()));
+    if (!B_Base)
+      return false;
+
+    // If the atoms are the same, they are guaranteed to have the same address.
+    if (A_Base == B_Base)
+      return true;
+
+    // Otherwise, we can't prove this is fully resolved.
+    return false;
+  }
 
   bool IsFixupFullyResolved(const MCAssembler &Asm,
                             const MCValue Target,
                             bool IsPCRel,
                             const MCFragment *DF) const {
-    // If we aren't using scattered symbols, the fixup is fully resolved.
-    if (!Asm.getBackend().hasScatteredSymbols())
-      return true;
-
     // Otherwise, determine whether this value is actually resolved; scattering
     // may cause atoms to move.
 
@@ -1149,7 +1214,7 @@ public:
     // The section data starts after the header, the segment load command (and
     // section headers) and the symbol table.
     unsigned NumLoadCommands = 1;
-    uint64_t LoadCommandsSize = Is64Bit ?
+    uint64_t LoadCommandsSize = is64Bit() ?
       macho::SegmentLoadCommand64Size + NumSections * macho::Section64Size :
       macho::SegmentLoadCommand32Size + NumSections * macho::Section32Size;
 
@@ -1164,7 +1229,7 @@ public:
 
     // Compute the total size of the section data, as well as its file size and
     // vm size.
-    uint64_t SectionDataStart = (Is64Bit ? macho::Header64Size :
+    uint64_t SectionDataStart = (is64Bit() ? macho::Header64Size :
                                  macho::Header32Size) + LoadCommandsSize;
     uint64_t SectionDataSize = 0;
     uint64_t SectionDataFileSize = 0;
@@ -1232,7 +1297,7 @@ public:
 
       // The string table is written after symbol table.
       uint64_t StringTableOffset =
-        SymbolTableOffset + NumSymTabSymbols * (Is64Bit ? macho::Nlist64Size :
+        SymbolTableOffset + NumSymTabSymbols * (is64Bit() ? macho::Nlist64Size :
                                                 macho::Nlist32Size);
       WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols,
                              StringTableOffset, StringTable.size());
@@ -1246,7 +1311,7 @@ public:
     // Write the actual section data.
     for (MCAssembler::const_iterator it = Asm.begin(),
            ie = Asm.end(); it != ie; ++it) {
-      Asm.WriteSectionData(it, Layout, this);
+      Asm.WriteSectionData(it, Layout);
 
       uint64_t Pad = getPaddingSize(it, Layout);
       for (unsigned int i = 0; i < Pad; ++i)
@@ -1311,9 +1376,8 @@ public:
 
 }
 
-MCObjectWriter *llvm::createMachObjectWriter(raw_ostream &OS, bool is64Bit,
-                                             uint32_t CPUType,
-                                             uint32_t CPUSubtype,
+MCObjectWriter *llvm::createMachObjectWriter(MCMachObjectTargetWriter *MOTW,
+                                             raw_ostream &OS,
                                              bool IsLittleEndian) {
-  return new MachObjectWriter(OS, is64Bit, CPUType, CPUSubtype, IsLittleEndian);
+  return new MachObjectWriter(MOTW, OS, IsLittleEndian);
 }