Implement ELF object file writing support for the MBlaze backend. Its not perfect yet, but it works for many tests.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@119952 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp
index 4ea6308..b9a0b02 100644
--- a/lib/MC/ELFObjectWriter.cpp
+++ b/lib/MC/ELFObjectWriter.cpp
@@ -30,6 +30,7 @@
 #include "llvm/Target/TargetAsmBackend.h"
 
 #include "../Target/X86/X86FixupKinds.h"
+#include "../Target/MBlaze/MBlazeFixupKinds.h"
 
 #include <vector>
 using namespace llvm;
@@ -77,6 +78,16 @@
   }
 }
 
+static bool isFixupKindMBlazePCRel(unsigned Kind) {
+  switch (Kind) {
+  default:
+    return false;
+  case MBlaze::reloc_pcrel_2byte:
+  case MBlaze::reloc_pcrel_4byte:
+    return true;
+  }
+}
+
 static bool RelocNeedsGOT(MCSymbolRefExpr::VariantKind Variant) {
   switch (Variant) {
   default:
@@ -358,7 +369,7 @@
     X86ELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool IsLittleEndian,
                        uint16_t _EMachine, bool _HasRelAddend,
                        Triple::OSType _OSType);
-    
+
     virtual ~X86ELFObjectWriter();
     virtual void RecordRelocation(const MCAssembler &Asm,
                                   const MCAsmLayout &Layout,
@@ -375,7 +386,7 @@
     ARMELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool IsLittleEndian,
                        uint16_t _EMachine, bool _HasRelAddend,
                        Triple::OSType _OSType);
-    
+
     virtual ~ARMELFObjectWriter();
     virtual void RecordRelocation(const MCAssembler &Asm,
                                   const MCAsmLayout &Layout,
@@ -383,6 +394,22 @@
                                   const MCFixup &Fixup, MCValue Target,
                                   uint64_t &FixedValue);
   };
+
+  //===- MBlazeELFObjectWriter -------------------------------------------===//
+
+  class MBlazeELFObjectWriter : public ELFObjectWriter {
+  public:
+    MBlazeELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool IsLittleEndian,
+                          uint16_t _EMachine, bool _HasRelAddend,
+                          Triple::OSType _OSType);
+
+    virtual ~MBlazeELFObjectWriter();
+    virtual void RecordRelocation(const MCAssembler &Asm,
+                                  const MCAsmLayout &Layout,
+                                  const MCFragment *Fragment,
+                                  const MCFixup &Fixup, MCValue Target,
+                                  uint64_t &FixedValue);
+  };
 }
 
 ELFObjectWriter::~ELFObjectWriter()
@@ -1349,6 +1376,9 @@
     case ELF::EM_ARM:
       return new ARMELFObjectWriter(OS, Is64Bit, IsLittleEndian, EMachine,
                                     HasRelocationAddend, OSType); break;
+    case ELF::EM_MBLAZE:
+      return new MBlazeELFObjectWriter(OS, Is64Bit, IsLittleEndian, EMachine,
+                                       HasRelocationAddend, OSType); break;
     default: llvm_unreachable("Unsupported architecture"); break;
   }
 }
@@ -1377,7 +1407,115 @@
   assert(0 && "ARMELFObjectWriter::RecordRelocation() unimplemented");
 }
 
+//===- MBlazeELFObjectWriter -------------------------------------------===//
 
+MBlazeELFObjectWriter::MBlazeELFObjectWriter(raw_ostream &_OS, bool _Is64Bit,
+                                             bool _IsLittleEndian,
+                                             uint16_t _EMachine,
+                                             bool _HasRelocationAddend,
+                                             Triple::OSType _OSType)
+  : ELFObjectWriter(_OS, _Is64Bit, _IsLittleEndian, _EMachine,
+                    _HasRelocationAddend, _OSType) {
+}
+
+MBlazeELFObjectWriter::~MBlazeELFObjectWriter() {
+}
+
+void MBlazeELFObjectWriter::RecordRelocation(const MCAssembler &Asm,
+                                             const MCAsmLayout &Layout,
+                                             const MCFragment *Fragment,
+                                             const MCFixup &Fixup,
+                                             MCValue Target,
+                                             uint64_t &FixedValue) {
+  int64_t Addend = 0;
+  int Index = 0;
+  int64_t Value = Target.getConstant();
+  const MCSymbol &Symbol = Target.getSymA()->getSymbol();
+  const MCSymbol &ASymbol = Symbol.AliasedSymbol();
+  const MCSymbol *RelocSymbol = SymbolToReloc(Asm, Target, *Fragment);
+
+  bool IsPCRel = isFixupKindMBlazePCRel(Fixup.getKind());
+  if (!Target.isAbsolute()) {
+    if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
+      const MCSymbol &SymbolB = RefB->getSymbol();
+      MCSymbolData &SDB = Asm.getSymbolData(SymbolB);
+      IsPCRel = true;
+      MCSectionData *Sec = Fragment->getParent();
+
+      // Offset of the symbol in the section
+      int64_t a = Layout.getSymbolAddress(&SDB) - Layout.getSectionAddress(Sec);
+
+      // Ofeset of the relocation in the section
+      int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
+      Value += b - a;
+    }
+
+    if (!RelocSymbol) {
+      MCSymbolData &SD = Asm.getSymbolData(ASymbol);
+      MCFragment *F = SD.getFragment();
+
+      Index = F->getParent()->getOrdinal();
+
+      MCSectionData *FSD = F->getParent();
+      // Offset of the symbol in the section
+      Value += Layout.getSymbolAddress(&SD) - Layout.getSectionAddress(FSD);
+    } else {
+      if (Asm.getSymbolData(Symbol).getFlags() & ELF_Other_Weakref)
+        WeakrefUsedInReloc.insert(RelocSymbol);
+      else
+        UsedInReloc.insert(RelocSymbol);
+      Index = -1;
+    }
+    Addend = Value;
+  }
+
+  FixedValue = Value;
+
+  // determine the type of the relocation
+  unsigned Type;
+  if (IsPCRel) {
+    switch ((unsigned)Fixup.getKind()) {
+    default:
+      llvm_unreachable("Unimplemented");
+    case MBlaze::reloc_pcrel_4byte:
+      Type = ELF::R_MICROBLAZE_64_PCREL;
+      break;
+    case MBlaze::reloc_pcrel_2byte:
+      Type = ELF::R_MICROBLAZE_32_PCREL;
+      break;
+    }
+  } else {
+    switch ((unsigned)Fixup.getKind()) {
+    default: llvm_unreachable("invalid fixup kind!");
+    case FK_Data_4:
+      Type = (RelocSymbol || Addend !=0) ? ELF::R_MICROBLAZE_32
+                                         : ELF::R_MICROBLAZE_64;
+      break;
+    case FK_Data_2:
+      Type = ELF::R_MICROBLAZE_32;
+      break;
+    }
+  }
+
+  MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind();
+  if (RelocNeedsGOT(Modifier))
+    NeedsGOT = true;
+
+  ELFRelocationEntry ERE;
+
+  ERE.Index = Index;
+  ERE.Type = Type;
+  ERE.Symbol = RelocSymbol;
+
+  ERE.r_offset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
+
+  if (HasRelocationAddend)
+    ERE.r_addend = Addend;
+  else
+    ERE.r_addend = 0; // Silence compiler warning.
+
+  Relocations[Fragment->getParent()].push_back(ERE);
+}
 
 //===- X86ELFObjectWriter -------------------------------------------===//