Index: include/llvm/MC/MCAsmBackend.h
===================================================================
--- include/llvm/MC/MCAsmBackend.h
+++ include/llvm/MC/MCAsmBackend.h
@@ -96,6 +96,10 @@
   /// getNumFixupKinds - Get the number of target specific fixup kinds.
   virtual unsigned getNumFixupKinds() const = 0;
 
+  virtual unsigned getFixupKind(StringRef Reloc) const {
+    llvm_unreachable("not implemented");
+  }
+
   /// getFixupKindInfo - Get information on a fixup kind.
   virtual const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const;
 
Index: include/llvm/MC/MCAssembler.h
===================================================================
--- include/llvm/MC/MCAssembler.h
+++ include/llvm/MC/MCAssembler.h
@@ -804,6 +804,27 @@
   MCSymbol *End;
 };
 
+// Information about relocations generated by directive .reloc.
+struct RelocInfo {
+  RelocInfo(const MCExpr *Offset_, unsigned Kind_, const MCExpr *Value_,
+            MCSectionData *SectionData_, SMLoc Loc_)
+      : Offset(Offset_), Kind(Kind_), Value(Value_),
+        SectionData(SectionData_), Loc(Loc_) {}
+  // Offset expression.
+  const MCExpr *Offset;
+
+  // Relocation kind.
+  unsigned Kind;
+
+  // Value expression.
+  const MCExpr *Value;
+
+  // Section in which this .reloc appeared.
+  MCSectionData *SectionData;
+
+  SMLoc Loc;
+};
+
 class MCAssembler {
   friend class MCAsmLayout;
 
@@ -846,6 +867,9 @@
 
   iplist<MCSymbolData> Symbols;
 
+  /// List of .reloc directives.
+  SmallVector<RelocInfo, 4> Relocs;
+
   /// The map of sections to their associated assembler backend data.
   //
   // FIXME: Avoid this indirection?
@@ -939,6 +963,11 @@
   uint64_t handleFixup(const MCAsmLayout &Layout,
                        MCFragment &F, const MCFixup &Fixup);
 
+  /// Return the fragment to which RI's relocation is applied and the offset
+  /// relative to the beginning of the fragment.
+  std::pair<MCEncodedFragmentWithFixups *, uint32_t>
+  getFragmentAndOffset(const RelocInfo &RI);
+
 public:
   /// Compute the effective fragment size assuming it is laid out at the given
   /// \p SectionAddress and \p FragmentOffset.
@@ -1030,6 +1059,8 @@
     BundleAlignSize = Size;
   }
 
+  SmallVectorImpl<RelocInfo> &getRelocList() { return Relocs; }
+
   /// @name Section List Access
   /// @{
 
Index: include/llvm/MC/MCObjectStreamer.h
===================================================================
--- include/llvm/MC/MCObjectStreamer.h
+++ include/llvm/MC/MCObjectStreamer.h
@@ -87,6 +87,9 @@
                              const MCExpr *Subsection);
   virtual void EmitInstruction(const MCInst &Inst);
 
+  virtual void EmitReloc(const MCExpr *Offset, StringRef Reloc,
+                         const MCExpr *Expression, SMLoc Loc);
+
   /// \brief Emit an instruction to a special fragment, because this instruction
   /// can change its size during relaxation.
   virtual void EmitInstToFragment(const MCInst &Inst);
Index: include/llvm/MC/MCStreamer.h
===================================================================
--- include/llvm/MC/MCStreamer.h
+++ include/llvm/MC/MCStreamer.h
@@ -356,6 +356,12 @@
   /// a Thumb mode function (ARM target only).
   virtual void EmitThumbFunc(MCSymbol *Func) = 0;
 
+  // Emit .reloc directive.
+  virtual void EmitReloc(const MCExpr *Offset, StringRef Reloc,
+                         const MCExpr *Expression, SMLoc Loc) {
+    llvm_unreachable("not implemented");
+  }
+
   /// getOrCreateSymbolData - Get symbol data for given symbol.
   virtual MCSymbolData &getOrCreateSymbolData(MCSymbol *Symbol);
 
Index: include/llvm/Object/ELFObjectFile.h
===================================================================
--- include/llvm/Object/ELFObjectFile.h
+++ include/llvm/Object/ELFObjectFile.h
@@ -783,6 +783,7 @@
   }
   case ELF::EM_ARM:
   case ELF::EM_HEXAGON:
+  case ELF::EM_MIPS:
     res = *SymName;
     break;
   default:
Index: lib/MC/MCAsmStreamer.cpp
===================================================================
--- lib/MC/MCAsmStreamer.cpp
+++ lib/MC/MCAsmStreamer.cpp
@@ -143,6 +143,8 @@
   virtual void EmitLinkerOptions(ArrayRef<std::string> Options);
   virtual void EmitDataRegion(MCDataRegionType Kind);
   virtual void EmitThumbFunc(MCSymbol *Func);
+  virtual void EmitReloc(const MCExpr *Offset, StringRef Reloc,
+                         const MCExpr *Expression, SMLoc Loc);
 
   virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value);
   virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol);
@@ -391,6 +393,11 @@
   EmitEOL();
 }
 
+void MCAsmStreamer::EmitReloc(const MCExpr *Offset, StringRef Reloc,
+                              const MCExpr *Expression, SMLoc Loc) {
+  OS << "\t.reloc\t" << *Offset << ", " << Reloc << ", " << *Expression << "\n";
+}
+
 void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
   OS << *Symbol << " = " << *Value;
   EmitEOL();
Index: lib/MC/MCAssembler.cpp
===================================================================
--- lib/MC/MCAssembler.cpp
+++ lib/MC/MCAssembler.cpp
@@ -801,6 +801,15 @@
   // example, to set the index fields in the symbol data).
   getWriter().ExecutePostLayoutBinding(*this, Layout);
 
+  // Add fixups generated by directive ".reloc".
+  for (SmallVectorImpl<RelocInfo>::const_iterator I = Relocs.begin(),
+       E = Relocs.end(); I != E; ++I) {
+    std::pair<MCEncodedFragmentWithFixups *, uint32_t> P =
+        getFragmentAndOffset(*I);
+    MCFixup Fixup = MCFixup::Create(P.second, I->Value, (MCFixupKind)I->Kind);
+    P.first->getFixups().push_back(Fixup);
+  }
+
   // Evaluate and apply the fixups, generating relocation entries as necessary.
   for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) {
     for (MCSectionData::iterator it2 = it->begin(),
@@ -825,6 +834,54 @@
   stats::ObjectBytes += OS.tell() - StartOffset;
 }
 
+std::pair<MCEncodedFragmentWithFixups *, uint32_t>
+MCAssembler::getFragmentAndOffset(const RelocInfo &RI) {
+  MCValue OffsetVal;
+  MCAsmLayout Layout(*this);
+
+  if (!RI.Offset->EvaluateAsRelocatable(OffsetVal, Layout))
+    getContext().FatalError(RI.Loc, "unable to evaluate offset");
+
+  MCSectionData *SD;
+  int64_t Offset = OffsetVal.getConstant();
+
+  if (OffsetVal.isAbsolute()) {
+    // If offset evaluates to an absolute, relocation is generated in the
+    // section in which the .reloc directive appeared.
+    assert(RI.SectionData);
+    SD = RI.SectionData;
+  } else {
+    // If offset evaluates to symbol+offset, relocation is generated in the
+    // given symbol's section.
+    MCSymbolData *SymData = &getSymbolData(OffsetVal.getSymA()->getSymbol());
+    Offset += Layout.getSymbolOffset(SymData);
+    SD = SymData->getFragment()->getParent();
+  }
+
+  if (Offset < 0)
+    getContext().FatalError(RI.Loc, "offset of .reloc cannot be negative");
+
+  MCEncodedFragmentWithFixups *F = 0;
+  uint64_t FragOffset;
+
+  // Find the fragment to which the relocation is applied.
+  for (MCSectionData::iterator I = SD->begin(), E = SD->end(); I != E; ++I) {
+    FragOffset = Layout.getFragmentOffset(&*I);
+
+    if (FragOffset <= (uint64_t)Offset &&
+        FragOffset + computeFragmentSize(Layout, *I) > (uint64_t)Offset) {
+      F = dyn_cast<MCEncodedFragmentWithFixups>(&*I);
+      break;
+    }
+  }
+
+  if (!F)
+    getContext().FatalError(RI.Loc, "cannot find a fragment to which this "
+                                    "relocation can be applied");
+
+  return std::make_pair(F, Offset - FragOffset);
+}
+
 bool MCAssembler::fixupNeedsRelaxation(const MCFixup &Fixup,
                                        const MCRelaxableFragment *DF,
                                        const MCAsmLayout &Layout) const {
Index: lib/MC/MCObjectStreamer.cpp
===================================================================
--- lib/MC/MCObjectStreamer.cpp
+++ lib/MC/MCObjectStreamer.cpp
@@ -231,6 +231,13 @@
   EmitInstToFragment(Inst);
 }
 
+void MCObjectStreamer::EmitReloc(const MCExpr *Offset, StringRef Reloc,
+                                 const MCExpr *Expression, SMLoc Loc) {
+  unsigned Kind = getAssembler().getBackend().getFixupKind(Reloc);
+  RelocInfo R(Offset, Kind, Expression, getCurrentSectionData(), Loc);
+  getAssembler().getRelocList().push_back(R);
+}
+
 void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) {
   // Always create a new, separate fragment here, because its size can change
   // during relaxation.
Index: lib/MC/MCParser/AsmParser.cpp
===================================================================
--- lib/MC/MCParser/AsmParser.cpp
+++ lib/MC/MCParser/AsmParser.cpp
@@ -350,7 +350,7 @@
     DK_INCLUDE, DK_INCBIN, DK_CODE16, DK_CODE16GCC, DK_REPT, DK_IRP, DK_IRPC,
     DK_IF, DK_IFB, DK_IFNB, DK_IFC, DK_IFNC, DK_IFDEF, DK_IFNDEF, DK_IFNOTDEF,
     DK_ELSEIF, DK_ELSE, DK_ENDIF,
-    DK_SPACE, DK_SKIP, DK_FILE, DK_LINE, DK_LOC, DK_STABS,
+    DK_SPACE, DK_SKIP, DK_FILE, DK_LINE, DK_LOC, DK_STABS, DK_RELOC,
     DK_CFI_SECTIONS, DK_CFI_STARTPROC, DK_CFI_ENDPROC, DK_CFI_DEF_CFA,
     DK_CFI_DEF_CFA_OFFSET, DK_CFI_ADJUST_CFA_OFFSET, DK_CFI_DEF_CFA_REGISTER,
     DK_CFI_OFFSET, DK_CFI_REL_OFFSET, DK_CFI_PERSONALITY, DK_CFI_LSDA,
@@ -383,6 +383,9 @@
   bool parseDirectiveLoc();
   bool parseDirectiveStabs();
 
+  // ".reloc"
+  bool parseDirectiveReloc();
+
   // .cfi directives
   bool parseDirectiveCFIRegister(SMLoc DirectiveLoc);
   bool parseDirectiveCFIWindowSave();
@@ -1458,6 +1461,8 @@
       return parseDirectiveLoc();
     case DK_STABS:
       return parseDirectiveStabs();
+    case DK_RELOC:
+      return parseDirectiveReloc();
     case DK_CFI_SECTIONS:
       return parseDirectiveCFISections();
     case DK_CFI_STARTPROC:
@@ -2747,6 +2752,35 @@
   return TokError("unsupported directive '.stabs'");
 }
 
+/// parseDirectiveReloc
+/// ::= .reloc expression, string, expression
+bool AsmParser::parseDirectiveReloc() {
+  const MCExpr *Offset, *Value;
+  StringRef RelocStr;
+
+  if (parseExpression(Offset))
+    return true;
+
+  if (getLexer().isNot(AsmToken::Comma))
+    return TokError("unexpected token in reloc directive");
+
+  Lex();
+
+  if (parseIdentifier(RelocStr))
+    return true;
+
+  if (getLexer().isNot(AsmToken::Comma))
+    return TokError("unexpected token in reloc directive");
+
+  Lex();
+
+  if (parseExpression(Value))
+    return true;
+
+  getStreamer().EmitReloc(Offset, RelocStr, Value, getLexer().getLoc());
+  return false;
+}
+
 /// parseDirectiveCFISections
 /// ::= .cfi_sections section [, section]
 bool AsmParser::parseDirectiveCFISections() {
@@ -3835,6 +3869,7 @@
   DirectiveKindMap[".line"] = DK_LINE;
   DirectiveKindMap[".loc"] = DK_LOC;
   DirectiveKindMap[".stabs"] = DK_STABS;
+  DirectiveKindMap[".reloc"] = DK_RELOC;
   DirectiveKindMap[".sleb128"] = DK_SLEB128;
   DirectiveKindMap[".uleb128"] = DK_ULEB128;
   DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;
Index: lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
===================================================================
--- lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
+++ lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp
@@ -14,6 +14,7 @@
 
 #include "MipsFixupKinds.h"
 #include "MCTargetDesc/MipsMCTargetDesc.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/MC/MCAsmBackend.h"
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCDirectives.h"
@@ -201,6 +202,7 @@
       { "fixup_Mips_GOT_LO16",     0,     16,   0 },
       { "fixup_Mips_CALL_HI16",    0,     16,   0 },
       { "fixup_Mips_CALL_LO16",    0,     16,   0 },
+      { "fixup_Mips_JALR",         0,     16,   0 },
       { "fixup_MICROMIPS_26_S1",   0,     26,   0 },
       { "fixup_MICROMIPS_HI16",    0,     16,   0 },
       { "fixup_MICROMIPS_LO16",    0,     16,   0 },
@@ -224,6 +226,16 @@
     return Infos[Kind - FirstTargetFixupKind];
   }
 
+  unsigned getFixupKind(StringRef Reloc) const {
+    Mips::Fixups Kind = StringSwitch<Mips::Fixups>(Reloc)
+      .Case("R_MIPS_JALR", Mips::fixup_Mips_JALR)
+      .Default(Mips::LastTargetFixupKind);
+
+    assert(Kind != Mips::LastTargetFixupKind && "Unknown relocation.");
+
+    return Kind;
+  }
+
   /// @name Target Relaxation Interfaces
   /// @{
 
Index: lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
===================================================================
--- lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
+++ lib/Target/Mips/MCTargetDesc/MipsELFObjectWriter.cpp
@@ -68,6 +68,9 @@
   assert(Target.getSymA() && "SymA cannot be 0.");
   const MCSymbol &Sym = Target.getSymA()->getSymbol().AliasedSymbol();
 
+  if ((llvm::Mips::Fixups)Fixup.getKind() == Mips::fixup_Mips_JALR)
+    return &Sym;
+
   if (Sym.getSection().getKind().isMergeableCString() ||
       Sym.getSection().getKind().isMergeableConst())
     return &Sym;
@@ -183,6 +186,9 @@
   case Mips::fixup_Mips_CALL_LO16:
     Type = ELF::R_MIPS_CALL_LO16;
     break;
+  case Mips::fixup_Mips_JALR:
+    Type = ELF::R_MIPS_JALR;
+    break;
   case Mips::fixup_MICROMIPS_26_S1:
     Type = ELF::R_MICROMIPS_26_S1;
     break;
Index: lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
===================================================================
--- lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
+++ lib/Target/Mips/MCTargetDesc/MipsFixupKinds.h
@@ -128,6 +128,9 @@
     // resulting in - R_MIPS_CALL_LO16
     fixup_Mips_CALL_LO16,
 
+    // resulting in - R_MIPS_JALR
+    fixup_Mips_JALR,
+
     // resulting in - R_MICROMIPS_26_S1
     fixup_MICROMIPS_26_S1,
 
Index: test/MC/Mips/reloc.s
===================================================================
--- /dev/null
+++ test/MC/Mips/reloc.s
@@ -0,0 +1,46 @@
+// RUN: llvm-mc -filetype=obj %s -o %t.o -arch=mips
+// RUN: llvm-objdump -r %t.o | FileCheck %s
+
+// CHECK:  RELOCATION RECORDS FOR [.rel.text]:
+// CHECK: 0  R_MIPS_JALR s2
+// CHECK: 4  R_MIPS_JALR s0
+// CHECK: 8  R_MIPS_JALR s5
+// CHECK: 12 R_MIPS_JALR s1
+
+// CHECK: RELOCATION RECORDS FOR [.rel.data]:
+// CHECK: 4  R_MIPS_JALR s8
+// CHECK: 12 R_MIPS_JALR s3
+// CHECK: 18 R_MIPS_JALR s4
+// CHECK: 20 R_MIPS_JALR s7
+
+.text
+.reloc 4, R_MIPS_JALR, s0
+.reloc s1+4, R_MIPS_JALR, s7
+.reloc 0, R_MIPS_JALR, s2
+.reloc s5-4, R_MIPS_JALR, s1
+s4:
+ .long 0,0,0,0
+s5:
+ .long 0,0,0,0
+s6:
+ .long 0,0,0,0
+s7:
+ .long 0,0,0,0
+s8:
+ .long 0,0,0,0
+
+.data
+.reloc 4, R_MIPS_JALR, s8
+.reloc s0+18, R_MIPS_JALR, s4
+.reloc s1-4, R_MIPS_JALR, s3
+.reloc s4+8, R_MIPS_JALR, s5
+s0:
+ .long 0,0,0,0
+s1:
+ .long 0,0,0,0
+s2:
+ .long 0,0,0,0
+ .long 0,0,0,0
+s3:
+ .long 0,0,0,0
+