diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -43,6 +43,8 @@
                      const uint8_t *loc) const override;
   void relocate(uint8_t *loc, const Relocation &rel,
                 uint64_t val) const override;
+  void relocatePair(uint8_t *loc, const Relocation &relA, uint64_t valA,
+                    const Relocation &relB, uint64_t valB) const override;
   bool relaxOnce(int pass) const override;
 };
 
@@ -101,6 +103,16 @@
          (extractBits(imm, 4, 0) << 7);
 }
 
+static void reportULEB128LengthExtend(uint8_t *loc, const RelType type,
+                                      Symbol &setSymbol, Symbol &subSymbol,
+                                      unsigned oldLength, unsigned newLength) {
+  ErrorPlace errPlace = getErrorPlace(loc);
+  error(errPlace.loc + "ULEB128 difference relocation pair overflow: " +
+        Twine(newLength) + " bytes needed but only " + Twine(oldLength) +
+        " bytes allocated; references '" + toString(setSymbol) + "' - '" +
+        toString(subSymbol) + "'");
+}
+
 RISCV::RISCV() {
   copyRel = R_RISCV_COPY;
   pltRel = R_RISCV_JUMP_SLOT;
@@ -277,6 +289,10 @@
   case R_RISCV_SUB32:
   case R_RISCV_SUB64:
     return R_RISCV_ADD;
+  case R_RISCV_SET_ULEB128:
+    return R_RELOCATE_PAIR_FIRST;
+  case R_RISCV_SUB_ULEB128:
+    return R_RELOCATE_PAIR_SECOND;
   case R_RISCV_JAL:
   case R_RISCV_BRANCH:
   case R_RISCV_PCREL_HI20:
@@ -313,6 +329,18 @@
   }
 }
 
+void RISCV::relocatePair(uint8_t *loc, const Relocation &relA, uint64_t valA,
+                         const Relocation &relB, uint64_t valB) const {
+  unsigned oldLength;
+  decodeULEB128(loc, &oldLength);
+  uint64_t newVal = valA - valB;
+  unsigned newLength = getULEB128Size(newVal);
+  if (newLength <= oldLength)
+    encodeULEB128(newVal, loc, /*PadTo*/ oldLength);
+  else
+    reportULEB128LengthExtend(loc, relA.type, *relA.sym, *relB.sym, oldLength,
+                              newLength);
+}
 void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
   const unsigned bits = config->wordsize * 8;
 
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -635,6 +635,8 @@
   case R_RELAX_TLS_LD_TO_LE_ABS:
   case R_RELAX_GOT_PC_NOPIC:
   case R_RISCV_ADD:
+  case R_RELOCATE_PAIR_FIRST:
+  case R_RELOCATE_PAIR_SECOND:
     return sym.getVA(a);
   case R_ADDEND:
     return a;
@@ -861,7 +863,7 @@
       break;
     }
 
-  for (const RelTy &rel : rels) {
+  for (auto [i, rel] : llvm::enumerate(rels)) {
     RelType type = rel.getType(config->isMips64EL);
 
     // GCC 8.0 or earlier have a bug that they emit R_386_GOTPC relocations
@@ -940,6 +942,57 @@
       continue;
     }
 
+    // Relocation pairs should appear together; we always handle them at the
+    // later one.
+    if (expr == R_RELOCATE_PAIR_FIRST || expr == R_RELOCATE_PAIR_SECOND) {
+      RelExpr expectedOther = expr == R_RELOCATE_PAIR_FIRST
+                                  ? R_RELOCATE_PAIR_SECOND
+                                  : R_RELOCATE_PAIR_FIRST;
+      bool foundPair = false;
+      const RelTy *otherRel = nullptr;
+      RelExpr otherExpr = R_NONE;
+      RelType otherType = R_NONE;
+      Symbol *otherSym = nullptr;
+      bool isSecondOne = false;
+
+      auto getRelInfo = [&](size_t idx) {
+        otherRel = &rels[idx];
+        otherType = otherRel->getType(config->isMips64EL);
+        otherSym = &getFile<ELFT>()->getRelocTargetSym(*otherRel);
+        otherExpr = target.getRelExpr(otherType, *otherSym, bufLoc);
+      };
+
+      // Try to look towards the front.
+      if (i + 1 < rels.size()) {
+        getRelInfo(i + 1);
+        if (expectedOther == otherExpr)
+          foundPair = true;
+      }
+      // Try to look towards the back.
+      if (!foundPair && i >= 1) {
+        getRelInfo(i - 1);
+        if (expectedOther == otherExpr) {
+          foundPair = true;
+          isSecondOne = true;
+        }
+      }
+      if (!foundPair) {
+        std::string msg = getLocation(offset) +
+                          ": found orphan paired relocation " + toString(type) +
+                          " against symbol '" + toString(sym) + "'";
+        error(msg);
+        continue;
+      }
+      if (isSecondOne)
+        target.relocatePair(
+            bufLoc, Relocation{R_NONE, otherType, 0, 0, otherSym},
+            SignExtend64<bits>(otherSym->getVA(addend)),
+            Relocation{R_NONE, type, 0, 0,
+                       &getFile<ELFT>()->getRelocTargetSym(rel)},
+            SignExtend64<bits>(sym.getVA(addend)));
+      continue;
+    }
+
     std::string msg = getLocation(offset) + ": has non-ABS relocation " +
                       toString(type) + " against symbol '" + toString(sym) +
                       "'";
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -57,6 +57,8 @@
   R_RELAX_TLS_IE_TO_LE,
   R_RELAX_TLS_LD_TO_LE,
   R_RELAX_TLS_LD_TO_LE_ABS,
+  R_RELOCATE_PAIR_FIRST,
+  R_RELOCATE_PAIR_SECOND,
   R_SIZE,
   R_TPREL,
   R_TPREL_NEG,
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -92,6 +92,9 @@
     relocate(loc, Relocation{R_NONE, type, 0, 0, nullptr}, val);
   }
   virtual void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const;
+  void reportOrphanRelocationPair(uint8_t *loc, const Relocation &rel) const;
+  virtual void relocatePair(uint8_t *loc, const Relocation &relA, uint64_t valA,
+                            const Relocation &relB, uint64_t valB) const;
 
   // Do a linker relaxation pass and return true if we changed something.
   virtual bool relaxOnce(int pass) const { return false; }
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -159,17 +159,57 @@
   uint64_t secAddr = sec.getOutputSection()->addr;
   if (auto *s = dyn_cast<InputSection>(&sec))
     secAddr += s->outSecOff;
-  for (const Relocation &rel : sec.relocs()) {
+  for (auto [i, rel] : llvm::enumerate(sec.relocs())) {
     uint8_t *loc = buf + rel.offset;
     const uint64_t val = SignExtend64(
         sec.getRelocTargetVA(sec.file, rel.type, rel.addend,
                              secAddr + rel.offset, *rel.sym, rel.expr),
         bits);
-    if (rel.expr != R_RELAX_HINT)
+    switch (rel.expr) {
+    case R_RELAX_HINT:
+      break;
+    case R_RELOCATE_PAIR_FIRST: {
+      if (i + 1 >= sec.relocs().size()) {
+        reportOrphanRelocationPair(loc, rel);
+        break;
+      }
+
+      auto nextRel = sec.relocs()[i + 1];
+      uint64_t nextVal = SignExtend64(
+          sec.getRelocTargetVA(sec.file, nextRel.type, nextRel.addend,
+                               secAddr + nextRel.offset, *nextRel.sym,
+                               nextRel.expr),
+          bits);
+      relocatePair(loc, rel, val, nextRel, nextVal);
+    } break;
+    case R_RELOCATE_PAIR_SECOND:
+      if (i < 1 ||
+          (i > 1 && sec.relocs()[i - 1].expr != R_RELOCATE_PAIR_FIRST)) {
+        reportOrphanRelocationPair(loc, rel);
+      }
+      break;
+    default:
       relocate(loc, rel, val);
+      break;
+    }
   }
 }
 
+void TargetInfo::reportOrphanRelocationPair(uint8_t *loc,
+                                            const Relocation &rel) const {
+  ErrorPlace errPlace = getErrorPlace(loc);
+  std::string msg = errPlace.loc + ": found orphan paired relocation " +
+                    toString(rel.type) + " against symbol '" +
+                    toString(*rel.sym) + "'";
+  error(msg);
+}
+
+void TargetInfo::relocatePair(uint8_t *loc, const Relocation &relA,
+                              uint64_t valA, const Relocation &relB,
+                              uint64_t valB) const {
+  llvm_unreachable("Target doesn't support relocatePair.");
+}
+
 uint64_t TargetInfo::getImageBase() const {
   // Use --image-base if set. Fall back to the target default if not.
   if (config->imageBase)
diff --git a/lld/test/ELF/riscv-bad-uleb128-ext-len-noalloc.s b/lld/test/ELF/riscv-bad-uleb128-ext-len-noalloc.s
new file mode 100644
--- /dev/null
+++ b/lld/test/ELF/riscv-bad-uleb128-ext-len-noalloc.s
@@ -0,0 +1,83 @@
+# REQUIRES: riscv
+## Relax R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+## RELAX
+# RUN: yaml2obj a.yml -o a.o
+# RUN: not ld.lld -T lds a.o -o 32c 2>&1 | FileCheck %s
+
+# CHECK: ULEB128 difference relocation pair overflow: 2 bytes needed but only 1 bytes allocated; references '.Lend_start' - '_start' 
+
+#--- a.yml
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_RISCV
+  Flags:           [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ]
+  SectionHeaderStringTable: .strtab
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x2
+    Content:         '01000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010097000000E78000008280'
+  - Name:            .debug_info
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x1
+    Content:         '0000000000'
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x4
+    Info:            .text
+    Relocations:
+      - Offset:          0x1FE
+        Symbol:          a
+        Type:            R_RISCV_CALL_PLT
+      - Offset:          0x1FE
+        Type:            R_RISCV_RELAX
+  - Name:            .rela.debug_info
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x4
+    Info:            .debug_info
+    Relocations:
+      - Symbol:          .Lend_start
+        Type:            R_RISCV_SET_ULEB128
+      - Symbol:          _start
+        Type:            R_RISCV_SUB_ULEB128
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .strtab
+      - Name:            .text
+      - Name:            .rela.text
+      - Name:            .debug_info
+      - Name:            .rela.debug_info
+      - Name:            .symtab
+Symbols:
+  - Name:            '$x.0'
+    Section:         .text
+  - Name:            a
+    Section:         .text
+    Value:           0x206
+  - Name:            .Lend_start
+    Section:         .text
+    Value:           0x206
+  - Name:            _start
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Size:            0x206
+...
+
+
+#--- lds
+SECTIONS {
+  .text 0x10000 : { *(.text) }
+  .data 0x20000 : { *(.data) }
+}
diff --git a/lld/test/ELF/riscv-bad-uleb128-ext-len.s b/lld/test/ELF/riscv-bad-uleb128-ext-len.s
new file mode 100644
--- /dev/null
+++ b/lld/test/ELF/riscv-bad-uleb128-ext-len.s
@@ -0,0 +1,86 @@
+# REQUIRES: riscv
+## Relax R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+## RELAX
+# RUN: yaml2obj a.yml -o a.o
+# RUN: not ld.lld -T lds a.o -o 32c 2>&1 | FileCheck %s
+
+# CHECK: ULEB128 difference relocation pair overflow: 2 bytes needed but only 1 bytes allocated; references '.Lend_start' - '_start' 
+
+#--- a.yml
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_RISCV
+  Flags:           [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ]
+  SectionHeaderStringTable: .strtab
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x2
+    Content:         '01000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010097000000E78000008280'
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x1
+    Content:         '0000000000'
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x4
+    Info:            .text
+    Relocations:
+      - Offset:          0x1FE
+        Symbol:          a
+        Type:            R_RISCV_CALL_PLT
+      - Offset:          0x1FE
+        Type:            R_RISCV_RELAX
+  - Name:            .rela.data
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x4
+    Info:            .data
+    Relocations:
+      - Symbol:          .Lend_start
+        Type:            R_RISCV_SET_ULEB128
+      - Symbol:          _start
+        Type:            R_RISCV_SUB_ULEB128
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .strtab
+      - Name:            .text
+      - Name:            .rela.text
+      - Name:            .data
+      - Name:            .rela.data
+      - Name:            .symtab
+Symbols:
+  - Name:            '$x.0'
+    Section:         .text
+  - Name:            a
+    Section:         .text
+    Value:           0x206
+  - Name:            .Lend_start
+    Section:         .text
+    Value:           0x206
+  - Name:            '$d.1'
+    Section:         .data
+  - Name:            _start
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Size:            0x206
+...
+
+
+#--- lds
+SECTIONS {
+  .text 0x10000 : { *(.text) }
+  .data 0x20000 : { *(.data) }
+}
diff --git a/lld/test/ELF/riscv-bad-uleb128-no-pair-1.s b/lld/test/ELF/riscv-bad-uleb128-no-pair-1.s
new file mode 100644
--- /dev/null
+++ b/lld/test/ELF/riscv-bad-uleb128-no-pair-1.s
@@ -0,0 +1,84 @@
+# REQUIRES: riscv
+## Relax R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+## RELAX
+# RUN: yaml2obj a.yml -o a.o
+# RUN: not ld.lld -T lds a.o -o 32c 2>&1 | FileCheck %s
+
+# CHECK: found orphan paired relocation R_RISCV_SET_ULEB128 against symbol '.Lend_start'
+
+#--- a.yml
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_RISCV
+  Flags:           [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ]
+  SectionHeaderStringTable: .strtab
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x2
+    Content:         '01000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010097000000E78000008280'
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x1
+    Content:         '0000000000'
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x4
+    Info:            .text
+    Relocations:
+      - Offset:          0x1FE
+        Symbol:          a
+        Type:            R_RISCV_CALL_PLT
+      - Offset:          0x1FE
+        Type:            R_RISCV_RELAX
+  - Name:            .rela.data
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x4
+    Info:            .data
+    Relocations:
+      - Symbol:          .Lend_start
+        Type:            R_RISCV_SET_ULEB128
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .strtab
+      - Name:            .text
+      - Name:            .rela.text
+      - Name:            .data
+      - Name:            .rela.data
+      - Name:            .symtab
+Symbols:
+  - Name:            '$x.0'
+    Section:         .text
+  - Name:            a
+    Section:         .text
+    Value:           0x206
+  - Name:            .Lend_start
+    Section:         .text
+    Value:           0x206
+  - Name:            '$d.1'
+    Section:         .data
+  - Name:            _start
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Size:            0x206
+...
+
+
+#--- lds
+SECTIONS {
+  .text 0x10000 : { *(.text) }
+  .data 0x20000 : { *(.data) }
+}
diff --git a/lld/test/ELF/riscv-bad-uleb128-no-pair-2.s b/lld/test/ELF/riscv-bad-uleb128-no-pair-2.s
new file mode 100644
--- /dev/null
+++ b/lld/test/ELF/riscv-bad-uleb128-no-pair-2.s
@@ -0,0 +1,84 @@
+# REQUIRES: riscv
+## Relax R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+## RELAX
+# RUN: yaml2obj a.yml -o a.o
+# RUN: not ld.lld -T lds a.o -o 32c 2>&1 | FileCheck %s
+
+# CHECK: found orphan paired relocation R_RISCV_SUB_ULEB128 against symbol '_start'
+
+#--- a.yml
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_RISCV
+  Flags:           [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ]
+  SectionHeaderStringTable: .strtab
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x2
+    Content:         '01000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010097000000E78000008280'
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x1
+    Content:         '0000000000'
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x4
+    Info:            .text
+    Relocations:
+      - Offset:          0x1FE
+        Symbol:          a
+        Type:            R_RISCV_CALL_PLT
+      - Offset:          0x1FE
+        Type:            R_RISCV_RELAX
+  - Name:            .rela.data
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x4
+    Info:            .data
+    Relocations:
+      - Symbol:          _start
+        Type:            R_RISCV_SUB_ULEB128
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .strtab
+      - Name:            .text
+      - Name:            .rela.text
+      - Name:            .data
+      - Name:            .rela.data
+      - Name:            .symtab
+Symbols:
+  - Name:            '$x.0'
+    Section:         .text
+  - Name:            a
+    Section:         .text
+    Value:           0x206
+  - Name:            .Lend_start
+    Section:         .text
+    Value:           0x206
+  - Name:            '$d.1'
+    Section:         .data
+  - Name:            _start
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Size:            0x206
+...
+
+
+#--- lds
+SECTIONS {
+  .text 0x10000 : { *(.text) }
+  .data 0x20000 : { *(.data) }
+}
diff --git a/lld/test/ELF/riscv-bad-uleb128-no-pair-3.s b/lld/test/ELF/riscv-bad-uleb128-no-pair-3.s
new file mode 100644
--- /dev/null
+++ b/lld/test/ELF/riscv-bad-uleb128-no-pair-3.s
@@ -0,0 +1,81 @@
+# REQUIRES: riscv
+## Relax R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+## RELAX
+# RUN: yaml2obj a.yml -o a.o
+# RUN: not ld.lld -T lds a.o -o 32c 2>&1 | FileCheck %s
+
+# CHECK: found orphan paired relocation R_RISCV_SET_ULEB128 against symbol '.Lend_start'
+
+#--- a.yml
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_RISCV
+  Flags:           [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ]
+  SectionHeaderStringTable: .strtab
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x2
+    Content:         '01000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010097000000E78000008280'
+  - Name:            .debug_info
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x1
+    Content:         '0000000000'
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x4
+    Info:            .text
+    Relocations:
+      - Offset:          0x1FE
+        Symbol:          a
+        Type:            R_RISCV_CALL_PLT
+      - Offset:          0x1FE
+        Type:            R_RISCV_RELAX
+  - Name:            .rela.debug_info
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x4
+    Info:            .debug_info
+    Relocations:
+      - Symbol:          .Lend_start
+        Type:            R_RISCV_SET_ULEB128
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .strtab
+      - Name:            .text
+      - Name:            .rela.text
+      - Name:            .debug_info
+      - Name:            .rela.debug_info
+      - Name:            .symtab
+Symbols:
+  - Name:            '$x.0'
+    Section:         .text
+  - Name:            a
+    Section:         .text
+    Value:           0x206
+  - Name:            .Lend_start
+    Section:         .text
+    Value:           0x206
+  - Name:            _start
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Size:            0x206
+...
+
+
+#--- lds
+SECTIONS {
+  .text 0x10000 : { *(.text) }
+  .data 0x20000 : { *(.data) }
+}
diff --git a/lld/test/ELF/riscv-bad-uleb128-no-pair-4.s b/lld/test/ELF/riscv-bad-uleb128-no-pair-4.s
new file mode 100644
--- /dev/null
+++ b/lld/test/ELF/riscv-bad-uleb128-no-pair-4.s
@@ -0,0 +1,81 @@
+# REQUIRES: riscv
+## Relax R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+## RELAX
+# RUN: yaml2obj a.yml -o a.o
+# RUN: not ld.lld -T lds a.o -o 32c 2>&1 | FileCheck %s
+
+# CHECK: found orphan paired relocation R_RISCV_SUB_ULEB128 against symbol '_start'
+
+#--- a.yml
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS32
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_RISCV
+  Flags:           [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ]
+  SectionHeaderStringTable: .strtab
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x2
+    Content:         '01000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100010097000000E78000008280'
+  - Name:            .debug_info
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x1
+    Content:         '0000000000'
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x4
+    Info:            .text
+    Relocations:
+      - Offset:          0x1FE
+        Symbol:          a
+        Type:            R_RISCV_CALL_PLT
+      - Offset:          0x1FE
+        Type:            R_RISCV_RELAX
+  - Name:            .rela.debug_info
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x4
+    Info:            .debug_info
+    Relocations:
+      - Symbol:          _start
+        Type:            R_RISCV_SUB_ULEB128
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .strtab
+      - Name:            .text
+      - Name:            .rela.text
+      - Name:            .debug_info
+      - Name:            .rela.debug_info
+      - Name:            .symtab
+Symbols:
+  - Name:            '$x.0'
+    Section:         .text
+  - Name:            a
+    Section:         .text
+    Value:           0x206
+  - Name:            .Lend_start
+    Section:         .text
+    Value:           0x206
+  - Name:            _start
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Size:            0x206
+...
+
+
+#--- lds
+SECTIONS {
+  .text 0x10000 : { *(.text) }
+  .data 0x20000 : { *(.data) }
+}
diff --git a/lld/test/ELF/riscv-relax-uleb128.s b/lld/test/ELF/riscv-relax-uleb128.s
new file mode 100644
--- /dev/null
+++ b/lld/test/ELF/riscv-relax-uleb128.s
@@ -0,0 +1,77 @@
+# REQUIRES: riscv
+## Relax R_RISCV_SET_ULEB128 and R_RISCV_SUB_ULEB128.
+
+# RUN: rm -rf %t && split-file %s %t && cd %t
+
+## RELAX
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -riscv-enable-uleb128 -mattr=+c,+relax a.s -o a.32c.o
+# RUN: ld.lld -T lds a.32c.o -o 32c
+# RUN: llvm-objdump -td -j .text -j .data -M no-aliases 32c | FileCheck %s --check-prefixes=RELAX,RELAX32
+
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -riscv-enable-uleb128 -mattr=+c,+relax a.s -o a.64c.o
+# RUN: ld.lld -T lds a.64c.o -o 64c
+# RUN: llvm-objdump -td -j .text -j .data -M no-aliases 64c | FileCheck %s --check-prefixes=RELAX,RELAX64
+
+## --no-relax disables relaxation.
+# RUN: ld.lld -T lds a.64c.o --no-relax -o 64c.norelax
+# RUN: llvm-objdump -td -j .text -j .data -M no-aliases 64c.norelax | FileCheck %s --check-prefixes=NORELAX
+
+# RELAX32:       00010002 l       .text  00000000 a
+# RELAX32:       00010002 l       .text  00000000 .Lend_start
+# RELAX32:       00010000 g       .text  00000002 _start
+
+# RELAX64:       0000000000010004 l       .text  0000000000000000 a
+# RELAX64:       0000000000010004 l       .text  0000000000000000 .Lend_start
+# RELAX64:       0000000000010000 g       .text  0000000000000004 _start
+
+# RELAX-LABEL:   <_start>:
+# RELAX32-NEXT:    10000: 09 20         c.jal   0x10002 <a>
+# RELAX64-NEXT:    10000: ef 00 40 00   jal     ra, 0x10004 <a>
+# RELAX-EMPTY:
+# RELAX-NEXT:    <a>:
+# RELAX32-NEXT:      10002: 82 80         c.jr    ra
+# RELAX64-NEXT:      10004: 82 80         c.jr    ra
+# RELAX-EMPTY:
+
+# RELAX-LABEL:   <.data>:
+# RELAX32:        20000: 82 80
+# RELAX32-NEXT:   20002: 80 80
+# RELAX32-NEXT:   20004: 00
+# RELAX64:        20000: 84 80
+# RELAX64-NEXT:   20002: 80 80
+# RELAX64-NEXT:   20004: 80 80
+# RELAX64-NEXT:   20006: 80 80
+# RELAX64-NEXT:   20008: 80 00
+# RELAX-EMPTY:
+
+# NORELAX-LABEL: <_start>:
+# NORELAX:           10000:  97 00 00 00   auipc   ra, 0
+# NORELAX-NEXT:              e7 80 80 00   jalr    ra, 8(ra)
+# NORELAX-EMPTY:
+
+# NORELAX-LABEL:   <.data>:
+# NORELAX:           20000: 88 80
+# NORELAX-NEXT:      20002: 80 80
+# NORELAX-NEXT:      20004: 80 80
+# NORELAX-NEXT:      20006: 80 80
+# NORELAX-NEXT:      20008: 80 00
+# NORELAX-EMPTY:
+
+
+#--- a.s
+.global _start
+_start:
+  call a          # rv32c: c.jal; rv64c: jal
+.Lend_start:
+.size _start, . - _start
+
+a:
+  ret
+.data
+.uleb128 .Lend_start-_start
+
+#--- lds
+SECTIONS {
+  .text 0x10000 : { *(.text) }
+  .data 0x20000 : { *(.data) }
+}