diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h
--- a/llvm/include/llvm/MC/MCAsmBackend.h
+++ b/llvm/include/llvm/MC/MCAsmBackend.h
@@ -129,10 +129,6 @@
                           uint64_t Value, bool IsResolved,
                           const MCSubtargetInfo *STI) const = 0;
 
-  /// Check whether the given target requires emitting differences of two
-  /// symbols as a set of relocations.
-  virtual bool requiresDiffExpressionRelocations() const { return false; }
-
   /// @}
 
   /// \name Target Relaxation Interfaces
@@ -169,6 +165,16 @@
   virtual void relaxInstruction(MCInst &Inst,
                                 const MCSubtargetInfo &STI) const {};
 
+  virtual bool relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF,
+                                  MCAsmLayout &Layout, bool &WasRelaxed) const {
+    return false;
+  }
+
+  virtual bool relaxDwarfCFA(MCDwarfCallFrameFragment &DF, MCAsmLayout &Layout,
+                             bool &WasRelaxed) const {
+    return false;
+  }
+
   /// @}
 
   /// Returns the minimum size of a nop in bytes on this target. The assembler
diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -387,13 +387,6 @@
   static void Encode(MCContext &Context, MCDwarfLineTableParams Params,
                      int64_t LineDelta, uint64_t AddrDelta, raw_ostream &OS);
 
-  /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas using
-  /// fixed length operands. Returns (Offset, Size, SetDelta).
-  static std::tuple<uint32_t, uint32_t, bool> fixedEncode(MCContext &Context,
-                                                          int64_t LineDelta,
-                                                          uint64_t AddrDelta,
-                                                          raw_ostream &OS);
-
   /// Utility function to emit the encoding to a streamer.
   static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
                    int64_t LineDelta, uint64_t AddrDelta);
@@ -667,8 +660,7 @@
   static void Emit(MCObjectStreamer &streamer, MCAsmBackend *MAB, bool isEH);
   static void EmitAdvanceLoc(MCObjectStreamer &Streamer, uint64_t AddrDelta);
   static void EncodeAdvanceLoc(MCContext &Context, uint64_t AddrDelta,
-                               raw_ostream &OS, uint32_t *Offset = nullptr,
-                               uint32_t *Size = nullptr);
+                               raw_ostream &OS);
 };
 
 } // end namespace llvm
diff --git a/llvm/include/llvm/MC/MCFixup.h b/llvm/include/llvm/MC/MCFixup.h
--- a/llvm/include/llvm/MC/MCFixup.h
+++ b/llvm/include/llvm/MC/MCFixup.h
@@ -41,16 +41,6 @@
   FK_SecRel_2,    ///< A two-byte section relative fixup.
   FK_SecRel_4,    ///< A four-byte section relative fixup.
   FK_SecRel_8,    ///< A eight-byte section relative fixup.
-  FK_Data_Add_1,  ///< A one-byte add fixup.
-  FK_Data_Add_2,  ///< A two-byte add fixup.
-  FK_Data_Add_4,  ///< A four-byte add fixup.
-  FK_Data_Add_8,  ///< A eight-byte add fixup.
-  FK_Data_Add_6b, ///< A six-bits add fixup.
-  FK_Data_Sub_1,  ///< A one-byte sub fixup.
-  FK_Data_Sub_2,  ///< A two-byte sub fixup.
-  FK_Data_Sub_4,  ///< A four-byte sub fixup.
-  FK_Data_Sub_8,  ///< A eight-byte sub fixup.
-  FK_Data_Sub_6b, ///< A six-bits sub fixup.
 
   FirstTargetFixupKind = 128,
 
@@ -105,28 +95,6 @@
     return FI;
   }
 
-  /// Return a fixup corresponding to the add half of a add/sub fixup pair for
-  /// the given Fixup.
-  static MCFixup createAddFor(const MCFixup &Fixup) {
-    MCFixup FI;
-    FI.Value = Fixup.getValue();
-    FI.Offset = Fixup.getOffset();
-    FI.Kind = getAddKindForKind(Fixup.getKind());
-    FI.Loc = Fixup.getLoc();
-    return FI;
-  }
-
-  /// Return a fixup corresponding to the sub half of a add/sub fixup pair for
-  /// the given Fixup.
-  static MCFixup createSubFor(const MCFixup &Fixup) {
-    MCFixup FI;
-    FI.Value = Fixup.getValue();
-    FI.Offset = Fixup.getOffset();
-    FI.Kind = getSubKindForKind(Fixup.getKind());
-    FI.Loc = Fixup.getLoc();
-    return FI;
-  }
-
   MCFixupKind getKind() const { return Kind; }
 
   unsigned getTargetKind() const { return Kind; }
@@ -172,32 +140,6 @@
     }
   }
 
-  /// Return the generic fixup kind for an addition with a given size. It
-  /// is an error to pass an unsupported size.
-  static MCFixupKind getAddKindForKind(MCFixupKind Kind) {
-    switch (Kind) {
-    default: llvm_unreachable("Unknown type to convert!");
-    case FK_Data_1: return FK_Data_Add_1;
-    case FK_Data_2: return FK_Data_Add_2;
-    case FK_Data_4: return FK_Data_Add_4;
-    case FK_Data_8: return FK_Data_Add_8;
-    case FK_Data_6b: return FK_Data_Add_6b;
-    }
-  }
-
-  /// Return the generic fixup kind for an subtraction with a given size. It
-  /// is an error to pass an unsupported size.
-  static MCFixupKind getSubKindForKind(MCFixupKind Kind) {
-    switch (Kind) {
-    default: llvm_unreachable("Unknown type to convert!");
-    case FK_Data_1: return FK_Data_Sub_1;
-    case FK_Data_2: return FK_Data_Sub_2;
-    case FK_Data_4: return FK_Data_Sub_4;
-    case FK_Data_8: return FK_Data_Sub_8;
-    case FK_Data_6b: return FK_Data_Sub_6b;
-    }
-  }
-
   SMLoc getLoc() const { return Loc; }
 };
 
diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp
--- a/llvm/lib/MC/MCAsmBackend.cpp
+++ b/llvm/lib/MC/MCAsmBackend.cpp
@@ -95,16 +95,7 @@
       {"FK_SecRel_2", 0, 16, 0},
       {"FK_SecRel_4", 0, 32, 0},
       {"FK_SecRel_8", 0, 64, 0},
-      {"FK_Data_Add_1", 0, 8, 0},
-      {"FK_Data_Add_2", 0, 16, 0},
-      {"FK_Data_Add_4", 0, 32, 0},
-      {"FK_Data_Add_8", 0, 64, 0},
-      {"FK_Data_Add_6b", 0, 6, 0},
-      {"FK_Data_Sub_1", 0, 8, 0},
-      {"FK_Data_Sub_2", 0, 16, 0},
-      {"FK_Data_Sub_4", 0, 32, 0},
-      {"FK_Data_Sub_8", 0, 64, 0},
-      {"FK_Data_Sub_6b", 0, 6, 0}};
+  };
 
   assert((size_t)Kind <= array_lengthof(Builtins) && "Unknown fixup kind");
   return Builtins[Kind];
diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp
--- a/llvm/lib/MC/MCAssembler.cpp
+++ b/llvm/lib/MC/MCAssembler.cpp
@@ -792,26 +792,7 @@
     // The fixup was unresolved, we need a relocation. Inform the object
     // writer of the relocation, and give it an opportunity to adjust the
     // fixup value if need be.
-    if (Target.getSymA() && Target.getSymB() &&
-        getBackend().requiresDiffExpressionRelocations()) {
-      // The fixup represents the difference between two symbols, which the
-      // backend has indicated must be resolved at link time. Split up the fixup
-      // into two relocations, one for the add, and one for the sub, and emit
-      // both of these. The constant will be associated with the add half of the
-      // expression.
-      MCFixup FixupAdd = MCFixup::createAddFor(Fixup);
-      MCValue TargetAdd =
-          MCValue::get(Target.getSymA(), nullptr, Target.getConstant());
-      getWriter().recordRelocation(*this, Layout, &F, FixupAdd, TargetAdd,
-                                   FixedValue);
-      MCFixup FixupSub = MCFixup::createSubFor(Fixup);
-      MCValue TargetSub = MCValue::get(Target.getSymB());
-      getWriter().recordRelocation(*this, Layout, &F, FixupSub, TargetSub,
-                                   FixedValue);
-    } else {
-      getWriter().recordRelocation(*this, Layout, &F, Fixup, Target,
-                                   FixedValue);
-    }
+    getWriter().recordRelocation(*this, Layout, &F, Fixup, Target, FixedValue);
   }
   return std::make_tuple(Target, FixedValue, IsResolved);
 }
@@ -1100,6 +1081,12 @@
 
 bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout,
                                      MCDwarfLineAddrFragment &DF) {
+
+  bool WasRelaxed;
+  if (Layout.getAssembler().getBackend().relaxDwarfLineAddr(DF, Layout,
+                                                            WasRelaxed))
+    return WasRelaxed;
+
   MCContext &Context = Layout.getAssembler().getContext();
   uint64_t OldSize = DF.getContents().size();
   int64_t AddrDelta;
@@ -1113,33 +1100,17 @@
   raw_svector_ostream OSE(Data);
   DF.getFixups().clear();
 
-  if (!getBackend().requiresDiffExpressionRelocations()) {
-    MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta,
-                            AddrDelta, OSE);
-  } else {
-    uint32_t Offset;
-    uint32_t Size;
-    bool SetDelta;
-    std::tie(Offset, Size, SetDelta) =
-        MCDwarfLineAddr::fixedEncode(Context, LineDelta, AddrDelta, OSE);
-    // Add Fixups for address delta or new address.
-    const MCExpr *FixupExpr;
-    if (SetDelta) {
-      FixupExpr = &DF.getAddrDelta();
-    } else {
-      const MCBinaryExpr *ABE = cast<MCBinaryExpr>(&DF.getAddrDelta());
-      FixupExpr = ABE->getLHS();
-    }
-    DF.getFixups().push_back(
-        MCFixup::create(Offset, FixupExpr,
-                        MCFixup::getKindForSize(Size, false /*isPCRel*/)));
-  }
-
+  MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta,
+                          AddrDelta, OSE);
   return OldSize != Data.size();
 }
 
 bool MCAssembler::relaxDwarfCallFrameFragment(MCAsmLayout &Layout,
                                               MCDwarfCallFrameFragment &DF) {
+  bool WasRelaxed;
+  if (Layout.getAssembler().getBackend().relaxDwarfCFA(DF, Layout, WasRelaxed))
+    return WasRelaxed;
+
   MCContext &Context = Layout.getAssembler().getContext();
   uint64_t OldSize = DF.getContents().size();
   int64_t AddrDelta;
@@ -1151,20 +1122,7 @@
   raw_svector_ostream OSE(Data);
   DF.getFixups().clear();
 
-  if (getBackend().requiresDiffExpressionRelocations()) {
-    uint32_t Offset;
-    uint32_t Size;
-    MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE, &Offset,
-                                          &Size);
-    if (Size) {
-      DF.getFixups().push_back(MCFixup::create(
-          Offset, &DF.getAddrDelta(),
-          MCFixup::getKindForSizeInBits(Size /*In bits.*/, false /*isPCRel*/)));
-    }
-  } else {
-    MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE);
-  }
-
+  MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE);
   return OldSize != Data.size();
 }
 
@@ -1194,10 +1152,6 @@
   raw_svector_ostream OSE(Data);
   PF.getFixups().clear();
 
-  // Relocations should not be needed in general except on RISC-V which we are
-  // not targeted for now.
-  assert(!getBackend().requiresDiffExpressionRelocations() &&
-         "cannot relax relocations");
   // AddrDelta is a signed integer
   encodeSLEB128(AddrDelta, OSE, OldSize);
   return OldSize != Data.size();
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -734,54 +734,6 @@
   }
 }
 
-std::tuple<uint32_t, uint32_t, bool>
-MCDwarfLineAddr::fixedEncode(MCContext &Context, int64_t LineDelta,
-                             uint64_t AddrDelta, raw_ostream &OS) {
-  uint32_t Offset, Size;
-  if (LineDelta != INT64_MAX) {
-    OS << char(dwarf::DW_LNS_advance_line);
-    encodeSLEB128(LineDelta, OS);
-  }
-
-  // Use address delta to adjust address or use absolute address to adjust
-  // address.
-  bool SetDelta;
-  // According to DWARF spec., the DW_LNS_fixed_advance_pc opcode takes a
-  // single uhalf (unencoded) operand. So, the maximum value of AddrDelta
-  // is 65535. We set a conservative upper bound for it for relaxation.
-  if (AddrDelta > 60000) {
-    const MCAsmInfo *asmInfo = Context.getAsmInfo();
-    unsigned AddrSize = asmInfo->getCodePointerSize();
-
-    OS << char(dwarf::DW_LNS_extended_op);
-    encodeULEB128(1 + AddrSize, OS);
-    OS << char(dwarf::DW_LNE_set_address);
-    // Generate fixup for the address.
-    Offset = OS.tell();
-    Size = AddrSize;
-    SetDelta = false;
-    OS.write_zeros(AddrSize);
-  } else {
-    OS << char(dwarf::DW_LNS_fixed_advance_pc);
-    // Generate fixup for 2-bytes address delta.
-    Offset = OS.tell();
-    Size = 2;
-    SetDelta = true;
-    OS << char(0);
-    OS << char(0);
-  }
-
-  if (LineDelta == INT64_MAX) {
-    OS << char(dwarf::DW_LNS_extended_op);
-    OS << char(1);
-    OS << char(dwarf::DW_LNE_end_sequence);
-  } else {
-    OS << char(dwarf::DW_LNS_copy);
-  }
-
-  return std::make_tuple(Offset, Size, SetDelta);
-}
-
 // Utility function to write a tuple for .debug_abbrev.
 static void EmitAbbrev(MCStreamer *MCOS, uint64_t Name, uint64_t Form) {
   MCOS->emitULEB128IntValue(Name);
@@ -1940,54 +1892,28 @@
 }
 
 void MCDwarfFrameEmitter::EncodeAdvanceLoc(MCContext &Context,
-                                           uint64_t AddrDelta, raw_ostream &OS,
-                                           uint32_t *Offset, uint32_t *Size) {
+                                           uint64_t AddrDelta,
+                                           raw_ostream &OS) {
   // Scale the address delta by the minimum instruction length.
   AddrDelta = ScaleAddrDelta(Context, AddrDelta);
-
-  bool WithFixups = false;
-  if (Offset && Size)
-    WithFixups = true;
+  if (AddrDelta == 0)
+    return;
 
   support::endianness E =
       Context.getAsmInfo()->isLittleEndian() ? support::little : support::big;
-  if (AddrDelta == 0) {
-    if (WithFixups) {
-      *Offset = 0;
-      *Size = 0;
-    }
-  } else if (isUIntN(6, AddrDelta)) {
+
+  if (isUIntN(6, AddrDelta)) {
     uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta;
-    if (WithFixups) {
-      *Offset = OS.tell();
-      *Size = 6;
-      OS << uint8_t(dwarf::DW_CFA_advance_loc);
-    } else
-      OS << Opcode;
+    OS << Opcode;
   } else if (isUInt<8>(AddrDelta)) {
     OS << uint8_t(dwarf::DW_CFA_advance_loc1);
-    if (WithFixups) {
-      *Offset = OS.tell();
-      *Size = 8;
-      OS.write_zeros(1);
-    } else
-      OS << uint8_t(AddrDelta);
+    OS << uint8_t(AddrDelta);
   } else if (isUInt<16>(AddrDelta)) {
     OS << uint8_t(dwarf::DW_CFA_advance_loc2);
-    if (WithFixups) {
-      *Offset = OS.tell();
-      *Size = 16;
-      OS.write_zeros(2);
-    } else
-      support::endian::write<uint16_t>(OS, AddrDelta, E);
+    support::endian::write<uint16_t>(OS, AddrDelta, E);
   } else {
     assert(isUInt<32>(AddrDelta));
     OS << uint8_t(dwarf::DW_CFA_advance_loc4);
-    if (WithFixups) {
-      *Offset = OS.tell();
-      *Size = 32;
-      OS.write_zeros(4);
-    } else
-      support::endian::write<uint32_t>(OS, AddrDelta, E);
+    support::endian::write<uint32_t>(OS, AddrDelta, E);
   }
 }
diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp
--- a/llvm/lib/MC/MCExpr.cpp
+++ b/llvm/lib/MC/MCExpr.cpp
@@ -671,24 +671,6 @@
   }
 }
 
-static bool canFold(const MCAssembler *Asm, const MCSymbolRefExpr *A,
-                    const MCSymbolRefExpr *B, bool InSet) {
-  if (InSet)
-    return true;
-
-  if (!Asm->getBackend().requiresDiffExpressionRelocations())
-    return true;
-
-  const MCSymbol &CheckSym = A ? A->getSymbol() : B->getSymbol();
-  if (!CheckSym.isInSection())
-    return true;
-
-  if (!CheckSym.getSection().hasInstructions())
-    return true;
-
-  return false;
-}
-
 /// Evaluate the result of an add between (conceptually) two MCValues.
 ///
 /// This routine conceptually attempts to construct an MCValue:
@@ -725,11 +707,8 @@
   assert((!Layout || Asm) &&
          "Must have an assembler object if layout is given!");
 
-  // If we have a layout, we can fold resolved differences. Do not do this if
-  // the backend requires this to be emitted as individual relocations, unless
-  // the InSet flag is set to get the current difference anyway (used for
-  // example to calculate symbol sizes).
-  if (Asm && canFold(Asm, LHS_A, LHS_B, InSet)) {
+  // If we have a layout, we can fold resolved differences.
+  if (Asm) {
     // First, fold out any differences which are fully resolved. By
     // reassociating terms in
     //   Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst).
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -127,12 +127,9 @@
 
 // As a compile-time optimization, avoid allocating and evaluating an MCExpr
 // tree for (Hi - Lo) when Hi and Lo are offsets into the same fragment.
-static Optional<uint64_t>
-absoluteSymbolDiff(MCAssembler &Asm, const MCSymbol *Hi, const MCSymbol *Lo) {
+static Optional<uint64_t> absoluteSymbolDiff(const MCSymbol *Hi,
+                                             const MCSymbol *Lo) {
   assert(Hi && Lo);
-  if (Asm.getBackendPtr()->requiresDiffExpressionRelocations())
-    return None;
-
   if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() ||
       Hi->isVariable() || Lo->isVariable())
     return None;
@@ -143,19 +140,17 @@
 void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi,
                                               const MCSymbol *Lo,
                                               unsigned Size) {
-  if (Optional<uint64_t> Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) {
-    emitIntValue(*Diff, Size);
-    return;
-  }
+  if (!getAssembler().getContext().getTargetTriple().isRISCV())
+    if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo))
+      return emitIntValue(*Diff, Size);
   MCStreamer::emitAbsoluteSymbolDiff(Hi, Lo, Size);
 }
 
 void MCObjectStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi,
                                                        const MCSymbol *Lo) {
-  if (Optional<uint64_t> Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) {
-    emitULEB128IntValue(*Diff);
-    return;
-  }
+  if (!getAssembler().getContext().getTargetTriple().isRISCV())
+    if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo))
+      return emitULEB128IntValue(*Diff);
   MCStreamer::emitAbsoluteSymbolDiffAsULEB128(Hi, Lo);
 }
 
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
@@ -42,20 +42,6 @@
 
   void setForceRelocs() { ForceRelocs = true; }
 
-  // Returns true if relocations will be forced for shouldForceRelocation by
-  // default. This will be true if relaxation is enabled or had previously
-  // been enabled.
-  bool willForceRelocations() const {
-    return ForceRelocs || STI.getFeatureBits()[RISCV::FeatureRelax];
-  }
-
-  // Generate diff expression relocations if the relax feature is enabled or had
-  // previously been enabled, otherwise it is safe for the assembler to
-  // calculate these internally.
-  bool requiresDiffExpressionRelocations() const override {
-    return willForceRelocations();
-  }
-
   // Return Size with extra Nop Bytes for alignment directive in code section.
   bool shouldInsertExtraNopBytesForCodeAlign(const MCAlignFragment &AF,
                                              unsigned &Size) override;
@@ -108,6 +94,11 @@
   void relaxInstruction(MCInst &Inst,
                         const MCSubtargetInfo &STI) const override;
 
+  bool relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF, MCAsmLayout &Layout,
+                          bool &WasRelaxed) const override;
+  bool relaxDwarfCFA(MCDwarfCallFrameFragment &DF, MCAsmLayout &Layout,
+                     bool &WasRelaxed) const override;
+
   bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
 
   const MCTargetOptions &getTargetOptions() const { return TargetOptions; }
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -9,6 +9,7 @@
 #include "RISCVAsmBackend.h"
 #include "RISCVMCExpr.h"
 #include "llvm/ADT/APInt.h"
+#include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCAsmLayout.h"
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCContext.h"
@@ -18,7 +19,10 @@
 #include "llvm/MC/MCObjectWriter.h"
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/MC/MCValue.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/EndianStream.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/LEB128.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
@@ -70,7 +74,26 @@
       {"fixup_riscv_call", 0, 64, MCFixupKindInfo::FKF_IsPCRel},
       {"fixup_riscv_call_plt", 0, 64, MCFixupKindInfo::FKF_IsPCRel},
       {"fixup_riscv_relax", 0, 0, 0},
-      {"fixup_riscv_align", 0, 0, 0}};
+      {"fixup_riscv_align", 0, 0, 0},
+
+      {"fixup_riscv_set_8", 0, 8, 0},
+      {"fixup_riscv_add_8", 0, 8, 0},
+      {"fixup_riscv_sub_8", 0, 8, 0},
+
+      {"fixup_riscv_set_16", 0, 16, 0},
+      {"fixup_riscv_add_16", 0, 16, 0},
+      {"fixup_riscv_sub_16", 0, 16, 0},
+
+      {"fixup_riscv_set_32", 0, 32, 0},
+      {"fixup_riscv_add_32", 0, 32, 0},
+      {"fixup_riscv_sub_32", 0, 32, 0},
+
+      {"fixup_riscv_add_64", 0, 64, 0},
+      {"fixup_riscv_sub_64", 0, 64, 0},
+
+      {"fixup_riscv_set_6b", 2, 6, 0},
+      {"fixup_riscv_sub_6b", 2, 6, 0},
+  };
   static_assert((array_lengthof(Infos)) == RISCV::NumTargetFixupKinds,
                 "Not all fixup kinds added to Infos array");
 
@@ -179,6 +202,132 @@
   Inst = std::move(Res);
 }
 
+bool RISCVAsmBackend::relaxDwarfLineAddr(MCDwarfLineAddrFragment &DF,
+                                         MCAsmLayout &Layout,
+                                         bool &WasRelaxed) const {
+  static const constexpr int64_t kAddrDeltaLimit = 50000;
+
+  MCContext &C = Layout.getAssembler().getContext();
+
+  int64_t LineDelta = DF.getLineDelta();
+  const MCExpr &AddrDelta = DF.getAddrDelta();
+  SmallVectorImpl<char> &Data = DF.getContents();
+  SmallVectorImpl<MCFixup> &Fixups = DF.getFixups();
+  size_t OldSize = Data.size();
+
+  int64_t Value;
+  bool IsAbsolute = AddrDelta.evaluateKnownAbsolute(Value, Layout);
+  assert(IsAbsolute && "CFA with invalid expression");
+  (void)IsAbsolute;
+
+  Data.clear();
+  Fixups.clear();
+  raw_svector_ostream OS(Data);
+
+  // INT64_MAX is a signal that this is actually a DW_LNE_end_sequence.
+  if (LineDelta != INT64_MAX) {
+    OS << uint8_t(dwarf::DW_LNS_advance_line);
+    encodeSLEB128(LineDelta, OS);
+  }
+
+  unsigned Offset;
+  std::pair<unsigned, unsigned> Fixup;
+
+  if (Value > kAddrDeltaLimit) {
+    unsigned PtrSize = C.getAsmInfo()->getCodePointerSize();
+
+    OS << uint8_t(dwarf::DW_LNS_extended_op);
+    encodeULEB128(PtrSize + 1, OS);
+
+    OS << uint8_t(dwarf::DW_LNE_set_address);
+    Offset = OS.tell();
+    Fixup = PtrSize == 4 ? std::make_pair(RISCV::fixup_riscv_add_32,
+                                          RISCV::fixup_riscv_sub_32)
+                         : std::make_pair(RISCV::fixup_riscv_add_64,
+                                          RISCV::fixup_riscv_sub_64);
+    OS.write_zeros(PtrSize);
+  } else {
+    OS << uint8_t(dwarf::DW_LNS_fixed_advance_pc);
+    Offset = OS.tell();
+    Fixup = {RISCV::fixup_riscv_add_16, RISCV::fixup_riscv_sub_16};
+    support::endian::write<uint16_t>(OS, 0, support::little);
+  }
+
+  const MCBinaryExpr &MBE = cast<MCBinaryExpr>(AddrDelta);
+  Fixups.push_back(MCFixup::create(
+      Offset, MBE.getLHS(), static_cast<MCFixupKind>(std::get<0>(Fixup))));
+  Fixups.push_back(MCFixup::create(
+      Offset, MBE.getRHS(), static_cast<MCFixupKind>(std::get<1>(Fixup))));
+
+  if (LineDelta == INT64_MAX) {
+    OS << uint8_t(dwarf::DW_LNS_extended_op);
+    OS << uint8_t(1);
+    OS << uint8_t(dwarf::DW_LNE_end_sequence);
+  } else {
+    OS << uint8_t(dwarf::DW_LNS_copy);
+  }
+
+  WasRelaxed = OldSize != Data.size();
+  return true;
+}
+
+bool RISCVAsmBackend::relaxDwarfCFA(MCDwarfCallFrameFragment &DF,
+                                    MCAsmLayout &Layout, bool &Relaxed) const {
+  MCContext &C = Layout.getAssembler().getContext();
+
+  const MCExpr &AddrDelta = DF.getAddrDelta();
+  SmallVectorImpl<char> &Data = DF.getContents();
+  SmallVectorImpl<MCFixup> &Fixups = DF.getFixups();
+  size_t OldSize = Data.size();
+
+  int64_t Value;
+  bool IsAbsolute = AddrDelta.evaluateKnownAbsolute(Value, Layout);
+  assert(IsAbsolute && "CFA with invalid expression");
+  (void)IsAbsolute;
+
+  Data.clear();
+  Fixups.clear();
+  raw_svector_ostream OS(Data);
+
+  assert(C.getAsmInfo()->getMinInstAlignment() == 1 &&
+         "expected 1-byte alignment");
+  if (Value == 0) {
+    Relaxed = OldSize != Data.size();
+    return true;
+  }
+
+  auto AddFixups = [&Fixups, &AddrDelta](unsigned Offset,
+                                         std::pair<unsigned, unsigned> Fixup) {
+    const MCBinaryExpr &MBE = cast<MCBinaryExpr>(AddrDelta);
+    Fixups.push_back(MCFixup::create(
+        Offset, MBE.getLHS(), static_cast<MCFixupKind>(std::get<0>(Fixup))));
+    Fixups.push_back(MCFixup::create(
+        Offset, MBE.getRHS(), static_cast<MCFixupKind>(std::get<1>(Fixup))));
+  };
+
+  if (isUIntN(6, Value)) {
+    OS << uint8_t(dwarf::DW_CFA_advance_loc);
+    AddFixups(0, {RISCV::fixup_riscv_set_6b, RISCV::fixup_riscv_sub_6b});
+  } else if (isUInt<8>(Value)) {
+    OS << uint8_t(dwarf::DW_CFA_advance_loc1);
+    support::endian::write<uint8_t>(OS, 0, support::little);
+    AddFixups(1, {RISCV::fixup_riscv_set_8, RISCV::fixup_riscv_sub_8});
+  } else if (isUInt<16>(Value)) {
+    OS << uint8_t(dwarf::DW_CFA_advance_loc2);
+    support::endian::write<uint16_t>(OS, 0, support::little);
+    AddFixups(1, {RISCV::fixup_riscv_set_16, RISCV::fixup_riscv_sub_16});
+  } else if (isUInt<32>(Value)) {
+    OS << uint8_t(dwarf::DW_CFA_advance_loc4);
+    support::endian::write<uint32_t>(OS, 0, support::little);
+    AddFixups(1, {RISCV::fixup_riscv_set_32, RISCV::fixup_riscv_sub_32});
+  } else {
+    llvm_unreachable("unsupported CFA encoding");
+  }
+
+  Relaxed = OldSize != Data.size();
+  return true;
+}
+
 // Given a compressed control flow instruction this function returns
 // the expanded instruction.
 unsigned RISCVAsmBackend::getRelaxedOpcode(unsigned Op) const {
@@ -227,12 +376,25 @@
   case RISCV::fixup_riscv_tls_got_hi20:
   case RISCV::fixup_riscv_tls_gd_hi20:
     llvm_unreachable("Relocation should be unconditionally forced\n");
+  case RISCV::fixup_riscv_set_8:
+  case RISCV::fixup_riscv_add_8:
+  case RISCV::fixup_riscv_sub_8:
+  case RISCV::fixup_riscv_set_16:
+  case RISCV::fixup_riscv_add_16:
+  case RISCV::fixup_riscv_sub_16:
+  case RISCV::fixup_riscv_set_32:
+  case RISCV::fixup_riscv_add_32:
+  case RISCV::fixup_riscv_sub_32:
+  case RISCV::fixup_riscv_add_64:
+  case RISCV::fixup_riscv_sub_64:
   case FK_Data_1:
   case FK_Data_2:
   case FK_Data_4:
   case FK_Data_8:
   case FK_Data_6b:
     return Value;
+  case RISCV::fixup_riscv_set_6b:
+    return Value & 0x03;
   case RISCV::fixup_riscv_lo12_i:
   case RISCV::fixup_riscv_pcrel_lo12_i:
   case RISCV::fixup_riscv_tprel_lo12_i:
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
@@ -86,6 +86,22 @@
       return ELF::R_RISCV_CALL;
     case RISCV::fixup_riscv_call_plt:
       return ELF::R_RISCV_CALL_PLT;
+    case RISCV::fixup_riscv_add_8:
+      return ELF::R_RISCV_ADD8;
+    case RISCV::fixup_riscv_sub_8:
+      return ELF::R_RISCV_SUB8;
+    case RISCV::fixup_riscv_add_16:
+      return ELF::R_RISCV_ADD16;
+    case RISCV::fixup_riscv_sub_16:
+      return ELF::R_RISCV_SUB16;
+    case RISCV::fixup_riscv_add_32:
+      return ELF::R_RISCV_ADD32;
+    case RISCV::fixup_riscv_sub_32:
+      return ELF::R_RISCV_SUB32;
+    case RISCV::fixup_riscv_add_64:
+      return ELF::R_RISCV_ADD64;
+    case RISCV::fixup_riscv_sub_64:
+      return ELF::R_RISCV_SUB64;
     }
   }
 
@@ -106,26 +122,6 @@
     return ELF::R_RISCV_32;
   case FK_Data_8:
     return ELF::R_RISCV_64;
-  case FK_Data_Add_1:
-    return ELF::R_RISCV_ADD8;
-  case FK_Data_Add_2:
-    return ELF::R_RISCV_ADD16;
-  case FK_Data_Add_4:
-    return ELF::R_RISCV_ADD32;
-  case FK_Data_Add_8:
-    return ELF::R_RISCV_ADD64;
-  case FK_Data_Add_6b:
-    return ELF::R_RISCV_SET6;
-  case FK_Data_Sub_1:
-    return ELF::R_RISCV_SUB8;
-  case FK_Data_Sub_2:
-    return ELF::R_RISCV_SUB16;
-  case FK_Data_Sub_4:
-    return ELF::R_RISCV_SUB32;
-  case FK_Data_Sub_8:
-    return ELF::R_RISCV_SUB64;
-  case FK_Data_Sub_6b:
-    return ELF::R_RISCV_SUB6;
   case RISCV::fixup_riscv_hi20:
     return ELF::R_RISCV_HI20;
   case RISCV::fixup_riscv_lo12_i:
@@ -144,6 +140,32 @@
     return ELF::R_RISCV_RELAX;
   case RISCV::fixup_riscv_align:
     return ELF::R_RISCV_ALIGN;
+  case RISCV::fixup_riscv_set_6b:
+    return ELF::R_RISCV_SET6;
+  case RISCV::fixup_riscv_sub_6b:
+    return ELF::R_RISCV_SUB6;
+  case RISCV::fixup_riscv_add_8:
+    return ELF::R_RISCV_ADD8;
+  case RISCV::fixup_riscv_set_8:
+    return ELF::R_RISCV_SET8;
+  case RISCV::fixup_riscv_sub_8:
+    return ELF::R_RISCV_SUB8;
+  case RISCV::fixup_riscv_set_16:
+    return ELF::R_RISCV_SET16;
+  case RISCV::fixup_riscv_add_16:
+    return ELF::R_RISCV_ADD16;
+  case RISCV::fixup_riscv_sub_16:
+    return ELF::R_RISCV_SUB16;
+  case RISCV::fixup_riscv_set_32:
+    return ELF::R_RISCV_SET32;
+  case RISCV::fixup_riscv_add_32:
+    return ELF::R_RISCV_ADD32;
+  case RISCV::fixup_riscv_sub_32:
+    return ELF::R_RISCV_SUB32;
+  case RISCV::fixup_riscv_add_64:
+    return ELF::R_RISCV_ADD64;
+  case RISCV::fixup_riscv_sub_64:
+    return ELF::R_RISCV_SUB64;
   }
 }
 
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h
@@ -104,5 +104,11 @@
   void emitDirectiveOptionRelax() override;
   void emitDirectiveOptionNoRelax() override;
 };
+
+MCELFStreamer *createRISCVELFStreamer(MCContext &C,
+                                      std::unique_ptr<MCAsmBackend> MAB,
+                                      std::unique_ptr<MCObjectWriter> MOW,
+                                      std::unique_ptr<MCCodeEmitter> MCE,
+                                      bool RelaxAll);
 }
 #endif
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
@@ -15,9 +15,13 @@
 #include "RISCVBaseInfo.h"
 #include "RISCVMCTargetDesc.h"
 #include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCCodeEmitter.h"
 #include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCObjectWriter.h"
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCValue.h"
 #include "llvm/Support/LEB128.h"
 #include "llvm/Support/RISCVAttributes.h"
 
@@ -167,3 +171,93 @@
   }
   return Result;
 }
+
+namespace {
+class RISCVELFStreamer : public MCELFStreamer {
+  static std::pair<unsigned, unsigned> getRelocPairForSize(unsigned Size) {
+    switch (Size) {
+    default:
+      llvm_unreachable("unsupported fixup size");
+    case 1:
+      return std::make_pair(RISCV::fixup_riscv_add_8, RISCV::fixup_riscv_sub_8);
+    case 2:
+      return std::make_pair(RISCV::fixup_riscv_add_16,
+                            RISCV::fixup_riscv_sub_16);
+    case 4:
+      return std::make_pair(RISCV::fixup_riscv_add_32,
+                            RISCV::fixup_riscv_sub_32);
+    case 8:
+      return std::make_pair(RISCV::fixup_riscv_add_64,
+                            RISCV::fixup_riscv_sub_64);
+    }
+  }
+
+  static bool useLinkerRelaxation(MCContext &C, const MCExpr *Value,
+                                  const MCExpr *&LHS, const MCExpr *&RHS) {
+    const auto *MBE = dyn_cast<MCBinaryExpr>(Value);
+    if (MBE == nullptr)
+      return false;
+
+    MCValue E;
+    if (!Value->evaluateAsRelocatable(E, nullptr, nullptr))
+      return false;
+    if (E.getSymA() == nullptr || E.getSymB() == nullptr)
+      return false;
+
+    const auto &A = E.getSymA()->getSymbol();
+    const auto &B = E.getSymA()->getSymbol();
+
+    LHS = MCBinaryExpr::create(MCBinaryExpr::Add,
+                               MCSymbolRefExpr::create(&A, C),
+                               MCConstantExpr::create(E.getConstant(), C),
+                               C);
+    RHS = E.getSymB();
+
+    return (A.isInSection() ? A.getSection().hasInstructions()
+                            : !A.getName().empty()) ||
+           (B.isInSection() ? B.getSection().hasInstructions()
+                            : !B.getName().empty());
+  }
+
+public:
+  RISCVELFStreamer(MCContext &C, std::unique_ptr<MCAsmBackend> MAB,
+                   std::unique_ptr<MCObjectWriter> MOW,
+                   std::unique_ptr<MCCodeEmitter> MCE)
+      : MCELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)) {}
+
+  void emitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) override {
+    const MCExpr *A, *B;
+    if (!useLinkerRelaxation(getContext(), Value, A, B))
+      return MCELFStreamer::emitValueImpl(Value, Size, Loc);
+
+    MCStreamer::emitValueImpl(Value, Size, Loc);
+
+    MCDataFragment *DF = getOrCreateDataFragment();
+    flushPendingLabels(DF, DF->getContents().size());
+    MCDwarfLineEntry::make(this, getCurrentSectionOnly());
+
+    unsigned Add, Sub;
+    std::tie(Add, Sub) = getRelocPairForSize(Size);
+
+    DF->getFixups().push_back(MCFixup::create(
+        DF->getContents().size(), A, static_cast<MCFixupKind>(Add), Loc));
+    DF->getFixups().push_back(MCFixup::create(
+        DF->getContents().size(), B, static_cast<MCFixupKind>(Sub), Loc));
+
+    DF->getContents().resize(DF->getContents().size() + Size, 0);
+  }
+};
+} // namespace
+
+namespace llvm {
+MCELFStreamer *createRISCVELFStreamer(MCContext &C,
+                                      std::unique_ptr<MCAsmBackend> MAB,
+                                      std::unique_ptr<MCObjectWriter> MOW,
+                                      std::unique_ptr<MCCodeEmitter> MCE,
+                                      bool RelaxAll) {
+  RISCVELFStreamer *S =
+      new RISCVELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE));
+  S->getAssembler().setRelaxAll(RelaxAll);
+  return S;
+}
+} // namespace llvm
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
@@ -81,6 +81,45 @@
   // which indicates the linker should fixup the alignment after linker
   // relaxation.
   fixup_riscv_align,
+  // fixup_riscv_set_8 - 8-bit fixup corresponding to R_RISCV_SET8 for local
+  // label assignment.
+  fixup_riscv_set_8,
+  // fixup_riscv_add_8 - 8-bit fixup corresponding to R_RISCV_ADD8 for 8-bit
+  // symbolic difference paired relocations.
+  fixup_riscv_add_8,
+  // fixup_riscv_sub_8 - 8-bit fixup corresponding to R_RISCV_SUB8 for 8-bit
+  // symbolic difference paired relocations.
+  fixup_riscv_sub_8,
+  // fixup_riscv_set_16 - 16-bit fixup corresponding to R_RISCV_SET16 for local
+  // label assignment.
+  fixup_riscv_set_16,
+  // fixup_riscv_add_16 - 16-bit fixup corresponding to R_RISCV_ADD16 for
+  // 16-bit symbolic difference paired reloctions.
+  fixup_riscv_add_16,
+  // fixup_riscv_sub_16 - 16-bit fixup corresponding to R_RISCV_SUB16 for
+  // 16-bit symbolic difference paired reloctions.
+  fixup_riscv_sub_16,
+  // fixup_riscv_set_32 - 32-bit fixup corresponding to R_RISCV_SET32 for local
+  // label assignment.
+  fixup_riscv_set_32,
+  // fixup_riscv_add_32 - 32-bit fixup corresponding to R_RIRSCV_ADD32 for
+  // 32-bit symbolic difference paired relocations.
+  fixup_riscv_add_32,
+  // fixup_riscv_sub_32 - 32-bit fixup corresponding to R_RIRSCV_SUB32 for
+  // 32-bit symbolic difference paired relocations.
+  fixup_riscv_sub_32,
+  // fixup_riscv_add_64 - 64-bit fixup corresponding to R_RIRSCV_ADD64 for
+  // 64-bit symbolic difference paired relocations.
+  fixup_riscv_add_64,
+  // fixup_riscv_sub_64 - 64-bit fixup corresponding to R_RIRSCV_SUB64 for
+  // 64-bit symbolic difference paired relocations.
+  fixup_riscv_sub_64,
+  // fixup_riscv_set_6b - 6-bit fixup corresponding to R_RISCV_SET6 for local
+  // label assignment in DWARF CFA.
+  fixup_riscv_set_6b,
+  // fixup_riscv_sub_6b - 6-bit fixup corresponding to R_RIRSCV_SUB6 for local
+  // label assignment in DWARF CFA.
+  fixup_riscv_sub_6b,
 
   // fixup_riscv_invalid - used as a sentinel and a marker, must be last fixup
   fixup_riscv_invalid,
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
@@ -92,14 +92,19 @@
 bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
                                             const MCAsmLayout *Layout,
                                             const MCFixup *Fixup) const {
-  if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup))
-    return false;
+  bool IsSymbolicDifference = false;
+  if (const auto *MBE = dyn_cast<MCBinaryExpr>(getSubExpr())) {
+    if (isa<MCBinaryExpr>(MBE->getLHS()) && isa<MCConstantExpr>(MBE->getRHS()))
+      MBE = cast<MCBinaryExpr>(MBE->getLHS());
+    IsSymbolicDifference = isa<MCSymbolRefExpr>(MBE->getLHS()) &&
+                           isa<MCSymbolRefExpr>(MBE->getRHS());
+  }
 
   // Some custom fixup types are not valid with symbol difference expressions
-  if (Res.getSymA() && Res.getSymB()) {
+  if (IsSymbolicDifference) {
     switch (getKind()) {
     default:
-      return true;
+      break;
     case VK_RISCV_LO:
     case VK_RISCV_HI:
     case VK_RISCV_PCREL_LO:
@@ -113,8 +118,7 @@
       return false;
     }
   }
-
-  return true;
+  return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup);
 }
 
 void RISCVMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
@@ -18,9 +18,12 @@
 #include "RISCVTargetStreamer.h"
 #include "TargetInfo/RISCVTargetInfo.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/MC/MCAsmBackend.h"
 #include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeEmitter.h"
 #include "llvm/MC/MCInstrAnalysis.h"
 #include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
 #include "llvm/MC/MCRegisterInfo.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
@@ -138,6 +141,17 @@
   return new RISCVMCInstrAnalysis(Info);
 }
 
+namespace {
+MCStreamer *createRISCVELFStreamer(const Triple &T, MCContext &Context,
+                                   std::unique_ptr<MCAsmBackend> &&MAB,
+                                   std::unique_ptr<MCObjectWriter> &&MOW,
+                                   std::unique_ptr<MCCodeEmitter> &&MCE,
+                                   bool RelaxAll) {
+  return createRISCVELFStreamer(Context, std::move(MAB), std::move(MOW),
+                                std::move(MCE), RelaxAll);
+}
+} // end anonymous namespace
+
 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTargetMC() {
   for (Target *T : {&getTheRISCV32Target(), &getTheRISCV64Target()}) {
     TargetRegistry::RegisterMCAsmInfo(*T, createRISCVMCAsmInfo);
@@ -147,6 +161,7 @@
     TargetRegistry::RegisterMCCodeEmitter(*T, createRISCVMCCodeEmitter);
     TargetRegistry::RegisterMCInstPrinter(*T, createRISCVMCInstPrinter);
     TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfo);
+    TargetRegistry::RegisterELFStreamer(*T, createRISCVELFStreamer);
     TargetRegistry::RegisterObjectTargetStreamer(
         *T, createRISCVObjectTargetStreamer);
     TargetRegistry::RegisterMCInstrAnalysis(*T, createRISCVInstrAnalysis);
diff --git a/llvm/test/CodeGen/RISCV/fixups-diff.ll b/llvm/test/CodeGen/RISCV/fixups-diff.ll
--- a/llvm/test/CodeGen/RISCV/fixups-diff.ll
+++ b/llvm/test/CodeGen/RISCV/fixups-diff.ll
@@ -1,10 +1,10 @@
 ; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=+relax %s -o - \
-; RUN:     | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s
+; RUN:     | llvm-readobj -r - | FileCheck %s
 ; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=-relax %s -o - \
-; RUN:     | llvm-readobj -r - | FileCheck -check-prefix=NORELAX %s
+; RUN:     | llvm-readobj -r - | FileCheck %s
 
 ; Check that a difference between two symbols in the same fragment
-; causes relocations to be emitted if and only if relaxation is enabled.
+; causes relocations to be emitted.
 ;
 ; This specific test is checking that the size of the function in
 ; the debug information is represented by a relocation. This isn't
@@ -22,11 +22,18 @@
   ret i32 0
 }
 
-; RELAX: 0x22 R_RISCV_ADD32 - 0x0
-; RELAX: 0x22 R_RISCV_SUB32 - 0x0
-; RELAX: 0x2B R_RISCV_ADD32 - 0x0
-; RELAX: 0x2B R_RISCV_SUB32 - 0x0
-; NORELAX-NOT: R_RISCV_ADD32
+; CHECK: Section {{.*}} .rela.debug_info {
+; CHECK: 0x22 R_RISCV_ADD32 - 0x0
+; CHECK: 0x22 R_RISCV_SUB32 - 0x0
+; CHECK: 0x2B R_RISCV_ADD32 - 0x0
+; CHECK: 0x2B R_RISCV_SUB32 - 0x0
+; CHECK: }
+
+; CHECK: Section {{.*}} .rela.eh_frame {
+; CHECK: 0x1C R_RISCV_32_PCREL - 0x0
+; CHECK: 0x20 R_RISCV_ADD32 - 0x0
+; CHECK: 0x20 R_RISCV_SUB32 - 0x0
+; CHECK: }
 
 !llvm.dbg.cu = !{!0}
 !llvm.module.flags = !{!3, !4, !5}
diff --git a/llvm/test/CodeGen/RISCV/fixups-relax-diff.ll b/llvm/test/CodeGen/RISCV/fixups-relax-diff.ll
--- a/llvm/test/CodeGen/RISCV/fixups-relax-diff.ll
+++ b/llvm/test/CodeGen/RISCV/fixups-relax-diff.ll
@@ -1,12 +1,11 @@
 ; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=+relax %s -o - \
 ; RUN:     | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s
 ; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=-relax %s -o - \
-; RUN:     | llvm-readobj -r - | FileCheck -check-prefix=NORELAX %s
+; RUN:     | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s
 
-; This test checks that a diff inserted via inline assembly only causes
-; relocations when relaxation is enabled. This isn't an assembly test
-; as the assembler takes a different path through LLVM, which is
-; already covered by the fixups-expr.s test.
+; This test checks that a diff inserted via inline assembly always causes
+; relocations. This isn't an assembly test as the assembler takes a different
+; path through LLVM, which is already covered by the fixups-expr.s test.
 
 define i32 @main() nounwind {
 entry:
@@ -14,7 +13,6 @@
   store i32 0, i32* %retval, align 4
   ; RELAX: R_RISCV_ADD64 b
   ; RELAX: R_RISCV_SUB64 a
-  ; NORELAX-NOT: R_RISCV_ADD
   call void asm sideeffect "a:\0Ab:\0A.dword b-a", ""()
   ret i32 0
 }
diff --git a/llvm/test/MC/RISCV/fde-reloc.s b/llvm/test/MC/RISCV/fde-reloc.s
--- a/llvm/test/MC/RISCV/fde-reloc.s
+++ b/llvm/test/MC/RISCV/fde-reloc.s
@@ -1,19 +1,18 @@
 # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=+relax < %s \
-# RUN:     | llvm-readobj -r - | FileCheck -check-prefix=RELAX-RELOC %s
+# RUN:     | llvm-readobj -r - | FileCheck %s
 # RUN: llvm-mc -filetype=obj -triple riscv32 -mattr=-relax < %s \
-# RUN:     | llvm-readobj -r - | FileCheck -check-prefix=NORELAX-RELOC %s
+# RUN:     | llvm-readobj -r - | FileCheck %s
+
+# Ensure that the eh_frame records the symbolic difference with the paired
+# relocations always.
 
 func:
 	.cfi_startproc
   ret
 	.cfi_endproc
 
-# RELAX-RELOC:   Section (4) .rela.eh_frame {
-# RELAX-RELOC-NEXT:   0x1C R_RISCV_32_PCREL - 0x0
-# RELAX-RELOC-NEXT:   0x20 R_RISCV_ADD32 - 0x0
-# RELAX-RELOC-NEXT:   0x20 R_RISCV_SUB32 - 0x0
-# RELAX-RELOC-NEXT: }
-
-# NORELAX-RELOC:        Section (4) .rela.eh_frame {
-# NORELAX-RELOC-NEXT:    0x1C R_RISCV_32_PCREL - 0x0
-# NORELAX-RELOC-NEXT:  }
+# CHECK:   Section (4) .rela.eh_frame {
+# CHECK-NEXT:   0x1C R_RISCV_32_PCREL - 0x0
+# CHECK-NEXT:   0x20 R_RISCV_ADD32 - 0x0
+# CHECK-NEXT:   0x20 R_RISCV_SUB32 - 0x0
+# CHECK-NEXT: }
diff --git a/llvm/test/MC/RISCV/fixups-expr.s b/llvm/test/MC/RISCV/fixups-expr.s
--- a/llvm/test/MC/RISCV/fixups-expr.s
+++ b/llvm/test/MC/RISCV/fixups-expr.s
@@ -1,15 +1,14 @@
 # RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s \
-# RUN:     | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s
+# RUN:     | llvm-readobj -r - | FileCheck -check-prefix RELAX %s
 # RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s \
-# RUN:     | llvm-readobj -r - | FileCheck -check-prefix=NORELAX %s
+# RUN:     | llvm-readobj -r - | FileCheck -check-prefix RELAX %s
 
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax %s \
-# RUN:     | llvm-readobj -r - | FileCheck -check-prefix=RELAX %s
+# RUN:     | llvm-readobj -r - | FileCheck -check-prefix RELAX %s
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=-relax %s \
-# RUN:     | llvm-readobj -r - | FileCheck -check-prefix=NORELAX %s
+# RUN:     | llvm-readobj -r - | FileCheck -check-prefix RELAX %s
 
-# Check that subtraction expressions are emitted as two relocations
-# only when relaxation is enabled
+# Check that subtraction expressions are emitted as two relocations always.
 
 .globl G1
 .globl G2
@@ -44,4 +43,3 @@
 # RELAX: 0x1C R_RISCV_SUB8 .L1 0x0
 # RELAX: 0x1D R_RISCV_ADD8 G2 0x0
 # RELAX: 0x1D R_RISCV_SUB8 G1 0x0
-# NORELAX-NOT: R_RISCV
diff --git a/llvm/test/MC/RISCV/hilo-constaddr-expr.s b/llvm/test/MC/RISCV/hilo-constaddr-expr.s
--- a/llvm/test/MC/RISCV/hilo-constaddr-expr.s
+++ b/llvm/test/MC/RISCV/hilo-constaddr-expr.s
@@ -1,9 +1,5 @@
-# RUN: not llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s 2>&1 \
-# RUN:     | FileCheck %s -check-prefix=CHECK-RELAX
-# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s 2>&1 \
-# RUN:     | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-INSTR
-# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s 2>&1 \
-# RUN:     | llvm-objdump -r - | FileCheck %s --check-prefix=CHECK-REL
+# RUN: not llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax %s 2>&1 | FileCheck %s
+# RUN: not llvm-mc -filetype=obj -triple=riscv32 -mattr=-relax %s 2>&1 | FileCheck %s
 
 # Check the assembler rejects hi and lo expressions with constant expressions
 # involving labels when diff expressions are emitted as relocation pairs.
@@ -13,19 +9,13 @@
   # Emit zeros so that difference between tmp1 and tmp3 is 0x30124 bytes.
   .fill 0x30124-8
 tmp2:
-# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression
   lui t0, %hi(tmp3-tmp1)
-# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression
   lw ra, %lo(tmp3-tmp1)(t0)
-# CHECK-INSTR: lui t0, 48
-# CHECK-INSTR: lw ra, 292(t0)
 
 tmp3:
-# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression
   lui t1, %hi(tmp2-tmp3)
-# CHECK-RELAX: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression
+# CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected relocatable expression
   lw sp, %lo(tmp2-tmp3)(t1)
-# CHECK-INSTR: lui t1, 0
-# CHECK-INSTR: lw sp, -8(t1)
-
-# CHECK-REL-NOT: R_RISCV
\ No newline at end of file
diff --git a/llvm/test/MC/RISCV/reloc-addend.s b/llvm/test/MC/RISCV/reloc-addend.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/RISCV/reloc-addend.s
@@ -0,0 +1,11 @@
+# RUN: llvm-mc -triple riscv64 -filetype obj -o - %s | llvm-readobj -r - | FileCheck %s
+
+	.section __jump_table,"aw",@progbits
+	.p2align 3
+.Ltmp0:
+	.quad	(function+128)-.Ltmp0
+
+# CHECK: .rela__jump_table {
+# CHECK:   0x0 R_RISCV_ADD64 function 0x80
+# CHECK:   0x0 R_RISCV_SUB64 .Ltmp0 0x0
+# CHECK: }
diff --git a/llvm/test/MC/RISCV/scoped-relaxation.s b/llvm/test/MC/RISCV/scoped-relaxation.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/MC/RISCV/scoped-relaxation.s
@@ -0,0 +1,30 @@
+# RUN: llvm-mc -mattr -relax -triple riscv64-unknown-none-elf -filetype obj %s -o - | llvm-readobj -d -r - | FileCheck %s
+
+.global function
+
+# Unrelaxed reference, this would normally fail, but the subsequent scoped
+# relaxation forces relaxation on the file.
+.dword function - .
+
+# CHECK: 0x0 R_RISCV_ADD64 function 0x0
+# CHECK: 0x0 R_RISCV_SUB64 - 0x0
+
+# Relaxed reference, this will resolve to a pair of `RISCV_ADD64` and
+# `RISCV_SUB64` relocation.
+.option push
+.option relax
+.dword function - .
+.option pop
+
+# CHECK: 0x8 R_RISCV_ADD64 function 0x0
+# CHECK: 0x8 R_RISCV_SUB64 - 0x0
+
+# Unrelaxed reference, this will resolve to a pair of `RISCV_ADD64` and
+# `RISCV_SUB64` relocation due to relaxation being sticky to the file.
+.option push
+.option norelax
+.dword function - .
+.option pop
+
+# CHECK: 0x10 R_RISCV_ADD64 function 0x0
+# CHECK: 0x10 R_RISCV_SUB64 - 0x0