Skip to content

Conversation

MaskRay
Copy link
Member

@MaskRay MaskRay commented Jan 8, 2024

Complement #72610 (non-SHF_ALLOC sections). GCC-generated
.gcc_exception_table has the SHF_ALLOC flag and may contain
R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.

Created using spr 1.3.4
@MaskRay MaskRay requested review from kito-cheng and arichardson and removed request for kito-cheng January 8, 2024 00:12
@llvmbot
Copy link
Member

llvmbot commented Jan 8, 2024

@llvm/pr-subscribers-lld

Author: Fangrui Song (MaskRay)

Changes

Complement #72610 (non-SHF_ALLOC sections). GCC-generated
.gcc_exception_table has the SHF_ALLOC flag and may contain
R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.


Full diff: https://github.com/llvm/llvm-project/pull/77261.diff

5 Files Affected:

  • (modified) lld/ELF/Arch/RISCV.cpp (+42)
  • (modified) lld/ELF/InputSection.cpp (+1-10)
  • (modified) lld/ELF/Relocations.cpp (+2-2)
  • (modified) lld/ELF/Target.h (+10)
  • (modified) lld/test/ELF/riscv-reloc-leb128.s (+69-11)
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 898e3e45b9e724..1d3d179e5d6fb5 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -43,6 +43,7 @@ class RISCV final : public TargetInfo {
                      const uint8_t *loc) const override;
   void relocate(uint8_t *loc, const Relocation &rel,
                 uint64_t val) const override;
+  void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
   bool relaxOnce(int pass) const override;
 };
 
@@ -307,6 +308,7 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
   case R_RISCV_RELAX:
     return config->relax ? R_RELAX_HINT : R_NONE;
   case R_RISCV_SET_ULEB128:
+  case R_RISCV_SUB_ULEB128:
     return R_RISCV_LEB128;
   default:
     error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
@@ -515,6 +517,46 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
   }
 }
 
+void RISCV::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
+  uint64_t secAddr = sec.getOutputSection()->addr;
+  if (auto *s = dyn_cast<InputSection>(&sec))
+    secAddr += s->outSecOff;
+  else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
+    secAddr += ehIn->getParent()->outSecOff;
+  for (size_t i = 0, size = sec.relocs().size(); i != size; ++i) {
+    const Relocation &rel = sec.relocs()[i];
+    uint8_t *loc = buf + rel.offset;
+    const uint64_t val =
+        sec.getRelocTargetVA(sec.file, rel.type, rel.addend,
+                             secAddr + rel.offset, *rel.sym, rel.expr);
+
+    switch (rel.expr) {
+    case R_RELAX_HINT:
+      break;
+    case R_RISCV_LEB128:
+      if (i + 1 < size) {
+        const Relocation &rel1 = sec.relocs()[i + 1];
+        if (rel.type == R_RISCV_SET_ULEB128 &&
+            rel1.type == R_RISCV_SUB_ULEB128 && rel.offset == rel1.offset) {
+          auto val = rel.sym->getVA(rel.addend) - rel1.sym->getVA(rel1.addend);
+          if (overwriteULEB128(loc, val) >= 0x80)
+            errorOrWarn(sec.getLocation(rel.offset) + ": ULEB128 value " +
+                        Twine(val) + " exceeds available space; references '" +
+                        lld::toString(*rel.sym) + "'");
+          ++i;
+          continue;
+        }
+      }
+      errorOrWarn(sec.getLocation(rel.offset) +
+                  ": R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128");
+      return;
+    default:
+      relocate(loc, rel, val);
+      break;
+    }
+  }
+}
+
 namespace {
 struct SymbolAnchor {
   uint64_t offset;
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 5dfb57fda432e0..53b496bd084258 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -671,6 +671,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
   case R_RELAX_TLS_LD_TO_LE_ABS:
   case R_RELAX_GOT_PC_NOPIC:
   case R_RISCV_ADD:
+  case R_RISCV_LEB128:
     return sym.getVA(a);
   case R_ADDEND:
     return a;
@@ -875,16 +876,6 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
   }
 }
 
-// Overwrite a ULEB128 value and keep the original length.
-static uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) {
-  while (*bufLoc & 0x80) {
-    *bufLoc++ = 0x80 | (val & 0x7f);
-    val >>= 7;
-  }
-  *bufLoc = val;
-  return val;
-}
-
 // This function applies relocations to sections without SHF_ALLOC bit.
 // Such sections are never mapped to memory at runtime. Debug sections are
 // an example. Relocations in non-alloc sections are much easier to
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 210b4d1eb1a7a6..9eb2e82542d3d4 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -988,8 +988,8 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
   if (!config->isPic)
     return true;
 
-  // The size of a non preemptible symbol is a constant.
-  if (e == R_SIZE)
+  // Constant when referencing a non-preemptible symbol.
+  if (e == R_SIZE || e == R_RISCV_LEB128)
     return true;
 
   // For the target and the relocation, we want to know if they are
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 6264ab1a3da74a..af7aaff8a4c03b 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -301,6 +301,16 @@ inline void write32(void *p, uint32_t v) {
 inline void write64(void *p, uint64_t v) {
   llvm::support::endian::write64(p, v, config->endianness);
 }
+
+// Overwrite a ULEB128 value and keep the original length.
+inline uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) {
+  while (*bufLoc & 0x80) {
+    *bufLoc++ = 0x80 | (val & 0x7f);
+    val >>= 7;
+  }
+  *bufLoc = val;
+  return val;
+}
 } // namespace elf
 } // namespace lld
 
diff --git a/lld/test/ELF/riscv-reloc-leb128.s b/lld/test/ELF/riscv-reloc-leb128.s
index 8198819686c3c8..0bdc1eb18269dd 100644
--- a/lld/test/ELF/riscv-reloc-leb128.s
+++ b/lld/test/ELF/riscv-reloc-leb128.s
@@ -1,13 +1,13 @@
 # REQUIRES: riscv
 # RUN: rm -rf %t && split-file %s %t && cd %t
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax a.s -o a.o
-# RUN: llvm-readobj -r -x .debug_rnglists -x .debug_loclists a.o | FileCheck %s --check-prefix=REL
-# RUN: ld.lld -shared --gc-sections a.o -o a.so
-# RUN: llvm-readelf -x .debug_rnglists -x .debug_loclists a.so | FileCheck %s
+# RUN: llvm-readobj -r -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a.o | FileCheck %s --check-prefix=REL
+# RUN: ld.lld -shared --gc-sections --noinhibit-exec a.o -o a.so
+# RUN: llvm-readelf -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a.so | FileCheck %s
 
 # REL:      .rela.debug_rnglists {
-# REL-NEXT:   0x0 R_RISCV_SET_ULEB128 w1 0x83
-# REL-NEXT:   0x0 R_RISCV_SUB_ULEB128 w2 0x0
+# REL-NEXT:   0x0 R_RISCV_SET_ULEB128 w1 0x82
+# REL-NEXT:   0x0 R_RISCV_SUB_ULEB128 w2 0xFFFFFFFFFFFFFFFF
 # REL-NEXT:   0x1 R_RISCV_SET_ULEB128 w2 0x78
 # REL-NEXT:   0x1 R_RISCV_SUB_ULEB128 w1 0x0
 # REL-NEXT:   0x3 R_RISCV_SET_ULEB128 w1 0x89
@@ -28,12 +28,18 @@
 # REL-NEXT:   0x1 R_RISCV_SUB_ULEB128 x1 0x0
 # REL-NEXT: }
 
+# REL:        Hex dump of section '.gcc_except_table':
+# REL-NEXT:   0x00000000 7b800181 01808001 81800180 80800181 {
+# REL-NEXT:   0x00000010 808001                              .
 # REL:        Hex dump of section '.debug_rnglists':
 # REL-NEXT:   0x00000000 7b800181 01808001 81800180 80800181 {
 # REL-NEXT:   0x00000010 808001                              .
 # REL:        Hex dump of section '.debug_loclists':
 # REL-NEXT:   0x00000000 0008                                  .
 
+# CHECK:      Hex dump of section '.gcc_except_table':
+# CHECK-NEXT: 0x[[#%x,]] 7ffc0085 01fcff00 858001fc ffff0085 .
+# CHECK-NEXT: 0x[[#%x,]] 808001                              .
 # CHECK:      Hex dump of section '.debug_rnglists':
 # CHECK-NEXT: 0x00000000 7ffc0085 01fcff00 858001fc ffff0085 .
 # CHECK-NEXT: 0x00000010 808001                              .
@@ -50,21 +56,32 @@
 
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax sub.s -o sub.o
 # RUN: not ld.lld -shared sub.o 2>&1 | FileCheck %s --check-prefix=SUB
-# SUB: error: sub.o:(.debug_rnglists+0x8): unknown relocation (61) against symbol w2
+# SUB: error: sub.o:(.debug_rnglists+0x8): has non-ABS relocation R_RISCV_SUB_ULEB128 against symbol 'w2'
 
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax unpaired1.s -o unpaired1.o
-# RUN: not ld.lld -shared unpaired1.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
+# RUN: not ld.lld -shared --threads=1 unpaired1.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax unpaired2.s -o unpaired2.o
-# RUN: not ld.lld -shared unpaired2.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
+# RUN: not ld.lld -shared --threads=1 unpaired2.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax unpaired3.s -o unpaired3.o
-# RUN: not ld.lld -shared unpaired3.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
+# RUN: not ld.lld -shared --threads=1 unpaired3.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
+# UNPAIRED: error: {{.*}}.o:(.alloc+0x8): R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128
 # UNPAIRED: error: {{.*}}.o:(.debug_rnglists+0x8): R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128
 
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax overflow.s -o overflow.o
-# RUN: not ld.lld -shared overflow.o 2>&1 | FileCheck %s --check-prefix=OVERFLOW
+# RUN: not ld.lld -shared --threads=1 overflow.o 2>&1 | FileCheck %s --check-prefix=OVERFLOW
+# OVERFLOW: error: overflow.o:(.alloc+0x8): ULEB128 value 128 exceeds available space; references 'w2'
 # OVERFLOW: error: overflow.o:(.debug_rnglists+0x8): ULEB128 value 128 exceeds available space; references 'w2'
 
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax preemptable.s -o preemptable.o
+# RUN: not ld.lld -shared --threads=1 preemptable.o 2>&1 | FileCheck %s --check-prefix=PREEMPTABLE --implicit-check-not=error:
+# PREEMPTABLE: error: relocation R_RISCV_SET_ULEB128 cannot be used against symbol 'w2'; recompile with -fPIC
+# PREEMPTABLE: error: relocation R_RISCV_SUB_ULEB128 cannot be used against symbol 'w1'; recompile with -fPIC
+
 #--- a.s
+.cfi_startproc
+.cfi_lsda 0x1b,.LLSDA0
+.cfi_endproc
+
 .section .text.w,"axR"
 w1:
   call foo    # 4 bytes after relaxation
@@ -75,8 +92,22 @@ x1:
   call foo    # 4 bytes after relaxation
 x2:
 
+.section .gcc_except_table,"a"
+.LLSDA0:
+.reloc ., R_RISCV_SET_ULEB128, w1+130
+.reloc ., R_RISCV_SUB_ULEB128, w2-1  # non-zero addend for SUB
+.byte 0x7b
+.uleb128 w2-w1+120                   # initial value: 0x0180
+.uleb128 w1-w2+137                   # initial value: 0x0181
+.uleb128 w2-w1+16376                 # initial value: 0x018080
+.uleb128 w1-w2+16393                 # initial value: 0x018081
+.uleb128 w2-w1+2097144               # initial value: 0x01808080
+.uleb128 w1-w2+2097161               # initial value: 0x01808081
+
 .section .debug_rnglists
-.uleb128 w1-w2+131                   # initial value: 0x7b
+.reloc ., R_RISCV_SET_ULEB128, w1+130
+.reloc ., R_RISCV_SUB_ULEB128, w2-1  # non-zero addend for SUB
+.byte 0x7b
 .uleb128 w2-w1+120                   # initial value: 0x0180
 .uleb128 w1-w2+137                   # initial value: 0x0181
 .uleb128 w2-w1+16376                 # initial value: 0x018080
@@ -99,6 +130,10 @@ w1: call foo; w2:
 
 #--- unpaired1.s
 w1: call foo; w2:
+.section .alloc,"a"
+.quad 0
+.reloc ., R_RISCV_SET_ULEB128, w2+120
+.byte 0x7f
 .section .debug_rnglists
 .quad 0;
 .reloc ., R_RISCV_SET_ULEB128, w2+120
@@ -106,6 +141,11 @@ w1: call foo; w2:
 
 #--- unpaired2.s
 w1: call foo; w2:
+.section .alloc,"a"
+.quad 0
+.reloc ., R_RISCV_SET_ULEB128, w2+120
+.reloc .+1, R_RISCV_SUB_ULEB128, w1
+.byte 0x7f
 .section .debug_rnglists
 .quad 0
 .reloc ., R_RISCV_SET_ULEB128, w2+120
@@ -114,6 +154,11 @@ w1: call foo; w2:
 
 #--- unpaired3.s
 w1: call foo; w2:
+.section .alloc,"a"
+.quad 0
+.reloc ., R_RISCV_SET_ULEB128, w2+120
+.reloc ., R_RISCV_SUB64, w1
+.byte 0x7f
 .section .debug_rnglists
 .quad 0
 .reloc ., R_RISCV_SET_ULEB128, w2+120
@@ -122,8 +167,21 @@ w1: call foo; w2:
 
 #--- overflow.s
 w1: call foo; w2:
+.section .alloc,"a"
+.quad 0
+.reloc ., R_RISCV_SET_ULEB128, w2+124
+.reloc ., R_RISCV_SUB_ULEB128, w1
+.byte 0x7f
 .section .debug_rnglists
 .quad 0
 .reloc ., R_RISCV_SET_ULEB128, w2+124
 .reloc ., R_RISCV_SUB_ULEB128, w1
 .byte 0x7f
+
+#--- preemptable.s
+.globl w1, w2
+w1: call foo; w2:
+.section .alloc,"a"
+.uleb128 w2-w1
+.section .debug_rnglists
+.uleb128 w2-w1

@llvmbot
Copy link
Member

llvmbot commented Jan 8, 2024

@llvm/pr-subscribers-lld-elf

Author: Fangrui Song (MaskRay)

Changes

Complement #72610 (non-SHF_ALLOC sections). GCC-generated
.gcc_exception_table has the SHF_ALLOC flag and may contain
R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.


Full diff: https://github.com/llvm/llvm-project/pull/77261.diff

5 Files Affected:

  • (modified) lld/ELF/Arch/RISCV.cpp (+42)
  • (modified) lld/ELF/InputSection.cpp (+1-10)
  • (modified) lld/ELF/Relocations.cpp (+2-2)
  • (modified) lld/ELF/Target.h (+10)
  • (modified) lld/test/ELF/riscv-reloc-leb128.s (+69-11)
diff --git a/lld/ELF/Arch/RISCV.cpp b/lld/ELF/Arch/RISCV.cpp
index 898e3e45b9e724..1d3d179e5d6fb5 100644
--- a/lld/ELF/Arch/RISCV.cpp
+++ b/lld/ELF/Arch/RISCV.cpp
@@ -43,6 +43,7 @@ class RISCV final : public TargetInfo {
                      const uint8_t *loc) const override;
   void relocate(uint8_t *loc, const Relocation &rel,
                 uint64_t val) const override;
+  void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
   bool relaxOnce(int pass) const override;
 };
 
@@ -307,6 +308,7 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
   case R_RISCV_RELAX:
     return config->relax ? R_RELAX_HINT : R_NONE;
   case R_RISCV_SET_ULEB128:
+  case R_RISCV_SUB_ULEB128:
     return R_RISCV_LEB128;
   default:
     error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
@@ -515,6 +517,46 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
   }
 }
 
+void RISCV::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
+  uint64_t secAddr = sec.getOutputSection()->addr;
+  if (auto *s = dyn_cast<InputSection>(&sec))
+    secAddr += s->outSecOff;
+  else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
+    secAddr += ehIn->getParent()->outSecOff;
+  for (size_t i = 0, size = sec.relocs().size(); i != size; ++i) {
+    const Relocation &rel = sec.relocs()[i];
+    uint8_t *loc = buf + rel.offset;
+    const uint64_t val =
+        sec.getRelocTargetVA(sec.file, rel.type, rel.addend,
+                             secAddr + rel.offset, *rel.sym, rel.expr);
+
+    switch (rel.expr) {
+    case R_RELAX_HINT:
+      break;
+    case R_RISCV_LEB128:
+      if (i + 1 < size) {
+        const Relocation &rel1 = sec.relocs()[i + 1];
+        if (rel.type == R_RISCV_SET_ULEB128 &&
+            rel1.type == R_RISCV_SUB_ULEB128 && rel.offset == rel1.offset) {
+          auto val = rel.sym->getVA(rel.addend) - rel1.sym->getVA(rel1.addend);
+          if (overwriteULEB128(loc, val) >= 0x80)
+            errorOrWarn(sec.getLocation(rel.offset) + ": ULEB128 value " +
+                        Twine(val) + " exceeds available space; references '" +
+                        lld::toString(*rel.sym) + "'");
+          ++i;
+          continue;
+        }
+      }
+      errorOrWarn(sec.getLocation(rel.offset) +
+                  ": R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128");
+      return;
+    default:
+      relocate(loc, rel, val);
+      break;
+    }
+  }
+}
+
 namespace {
 struct SymbolAnchor {
   uint64_t offset;
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 5dfb57fda432e0..53b496bd084258 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -671,6 +671,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
   case R_RELAX_TLS_LD_TO_LE_ABS:
   case R_RELAX_GOT_PC_NOPIC:
   case R_RISCV_ADD:
+  case R_RISCV_LEB128:
     return sym.getVA(a);
   case R_ADDEND:
     return a;
@@ -875,16 +876,6 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
   }
 }
 
-// Overwrite a ULEB128 value and keep the original length.
-static uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) {
-  while (*bufLoc & 0x80) {
-    *bufLoc++ = 0x80 | (val & 0x7f);
-    val >>= 7;
-  }
-  *bufLoc = val;
-  return val;
-}
-
 // This function applies relocations to sections without SHF_ALLOC bit.
 // Such sections are never mapped to memory at runtime. Debug sections are
 // an example. Relocations in non-alloc sections are much easier to
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 210b4d1eb1a7a6..9eb2e82542d3d4 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -988,8 +988,8 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
   if (!config->isPic)
     return true;
 
-  // The size of a non preemptible symbol is a constant.
-  if (e == R_SIZE)
+  // Constant when referencing a non-preemptible symbol.
+  if (e == R_SIZE || e == R_RISCV_LEB128)
     return true;
 
   // For the target and the relocation, we want to know if they are
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 6264ab1a3da74a..af7aaff8a4c03b 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -301,6 +301,16 @@ inline void write32(void *p, uint32_t v) {
 inline void write64(void *p, uint64_t v) {
   llvm::support::endian::write64(p, v, config->endianness);
 }
+
+// Overwrite a ULEB128 value and keep the original length.
+inline uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) {
+  while (*bufLoc & 0x80) {
+    *bufLoc++ = 0x80 | (val & 0x7f);
+    val >>= 7;
+  }
+  *bufLoc = val;
+  return val;
+}
 } // namespace elf
 } // namespace lld
 
diff --git a/lld/test/ELF/riscv-reloc-leb128.s b/lld/test/ELF/riscv-reloc-leb128.s
index 8198819686c3c8..0bdc1eb18269dd 100644
--- a/lld/test/ELF/riscv-reloc-leb128.s
+++ b/lld/test/ELF/riscv-reloc-leb128.s
@@ -1,13 +1,13 @@
 # REQUIRES: riscv
 # RUN: rm -rf %t && split-file %s %t && cd %t
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax a.s -o a.o
-# RUN: llvm-readobj -r -x .debug_rnglists -x .debug_loclists a.o | FileCheck %s --check-prefix=REL
-# RUN: ld.lld -shared --gc-sections a.o -o a.so
-# RUN: llvm-readelf -x .debug_rnglists -x .debug_loclists a.so | FileCheck %s
+# RUN: llvm-readobj -r -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a.o | FileCheck %s --check-prefix=REL
+# RUN: ld.lld -shared --gc-sections --noinhibit-exec a.o -o a.so
+# RUN: llvm-readelf -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a.so | FileCheck %s
 
 # REL:      .rela.debug_rnglists {
-# REL-NEXT:   0x0 R_RISCV_SET_ULEB128 w1 0x83
-# REL-NEXT:   0x0 R_RISCV_SUB_ULEB128 w2 0x0
+# REL-NEXT:   0x0 R_RISCV_SET_ULEB128 w1 0x82
+# REL-NEXT:   0x0 R_RISCV_SUB_ULEB128 w2 0xFFFFFFFFFFFFFFFF
 # REL-NEXT:   0x1 R_RISCV_SET_ULEB128 w2 0x78
 # REL-NEXT:   0x1 R_RISCV_SUB_ULEB128 w1 0x0
 # REL-NEXT:   0x3 R_RISCV_SET_ULEB128 w1 0x89
@@ -28,12 +28,18 @@
 # REL-NEXT:   0x1 R_RISCV_SUB_ULEB128 x1 0x0
 # REL-NEXT: }
 
+# REL:        Hex dump of section '.gcc_except_table':
+# REL-NEXT:   0x00000000 7b800181 01808001 81800180 80800181 {
+# REL-NEXT:   0x00000010 808001                              .
 # REL:        Hex dump of section '.debug_rnglists':
 # REL-NEXT:   0x00000000 7b800181 01808001 81800180 80800181 {
 # REL-NEXT:   0x00000010 808001                              .
 # REL:        Hex dump of section '.debug_loclists':
 # REL-NEXT:   0x00000000 0008                                  .
 
+# CHECK:      Hex dump of section '.gcc_except_table':
+# CHECK-NEXT: 0x[[#%x,]] 7ffc0085 01fcff00 858001fc ffff0085 .
+# CHECK-NEXT: 0x[[#%x,]] 808001                              .
 # CHECK:      Hex dump of section '.debug_rnglists':
 # CHECK-NEXT: 0x00000000 7ffc0085 01fcff00 858001fc ffff0085 .
 # CHECK-NEXT: 0x00000010 808001                              .
@@ -50,21 +56,32 @@
 
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax sub.s -o sub.o
 # RUN: not ld.lld -shared sub.o 2>&1 | FileCheck %s --check-prefix=SUB
-# SUB: error: sub.o:(.debug_rnglists+0x8): unknown relocation (61) against symbol w2
+# SUB: error: sub.o:(.debug_rnglists+0x8): has non-ABS relocation R_RISCV_SUB_ULEB128 against symbol 'w2'
 
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax unpaired1.s -o unpaired1.o
-# RUN: not ld.lld -shared unpaired1.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
+# RUN: not ld.lld -shared --threads=1 unpaired1.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax unpaired2.s -o unpaired2.o
-# RUN: not ld.lld -shared unpaired2.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
+# RUN: not ld.lld -shared --threads=1 unpaired2.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax unpaired3.s -o unpaired3.o
-# RUN: not ld.lld -shared unpaired3.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
+# RUN: not ld.lld -shared --threads=1 unpaired3.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
+# UNPAIRED: error: {{.*}}.o:(.alloc+0x8): R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128
 # UNPAIRED: error: {{.*}}.o:(.debug_rnglists+0x8): R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128
 
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax overflow.s -o overflow.o
-# RUN: not ld.lld -shared overflow.o 2>&1 | FileCheck %s --check-prefix=OVERFLOW
+# RUN: not ld.lld -shared --threads=1 overflow.o 2>&1 | FileCheck %s --check-prefix=OVERFLOW
+# OVERFLOW: error: overflow.o:(.alloc+0x8): ULEB128 value 128 exceeds available space; references 'w2'
 # OVERFLOW: error: overflow.o:(.debug_rnglists+0x8): ULEB128 value 128 exceeds available space; references 'w2'
 
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax preemptable.s -o preemptable.o
+# RUN: not ld.lld -shared --threads=1 preemptable.o 2>&1 | FileCheck %s --check-prefix=PREEMPTABLE --implicit-check-not=error:
+# PREEMPTABLE: error: relocation R_RISCV_SET_ULEB128 cannot be used against symbol 'w2'; recompile with -fPIC
+# PREEMPTABLE: error: relocation R_RISCV_SUB_ULEB128 cannot be used against symbol 'w1'; recompile with -fPIC
+
 #--- a.s
+.cfi_startproc
+.cfi_lsda 0x1b,.LLSDA0
+.cfi_endproc
+
 .section .text.w,"axR"
 w1:
   call foo    # 4 bytes after relaxation
@@ -75,8 +92,22 @@ x1:
   call foo    # 4 bytes after relaxation
 x2:
 
+.section .gcc_except_table,"a"
+.LLSDA0:
+.reloc ., R_RISCV_SET_ULEB128, w1+130
+.reloc ., R_RISCV_SUB_ULEB128, w2-1  # non-zero addend for SUB
+.byte 0x7b
+.uleb128 w2-w1+120                   # initial value: 0x0180
+.uleb128 w1-w2+137                   # initial value: 0x0181
+.uleb128 w2-w1+16376                 # initial value: 0x018080
+.uleb128 w1-w2+16393                 # initial value: 0x018081
+.uleb128 w2-w1+2097144               # initial value: 0x01808080
+.uleb128 w1-w2+2097161               # initial value: 0x01808081
+
 .section .debug_rnglists
-.uleb128 w1-w2+131                   # initial value: 0x7b
+.reloc ., R_RISCV_SET_ULEB128, w1+130
+.reloc ., R_RISCV_SUB_ULEB128, w2-1  # non-zero addend for SUB
+.byte 0x7b
 .uleb128 w2-w1+120                   # initial value: 0x0180
 .uleb128 w1-w2+137                   # initial value: 0x0181
 .uleb128 w2-w1+16376                 # initial value: 0x018080
@@ -99,6 +130,10 @@ w1: call foo; w2:
 
 #--- unpaired1.s
 w1: call foo; w2:
+.section .alloc,"a"
+.quad 0
+.reloc ., R_RISCV_SET_ULEB128, w2+120
+.byte 0x7f
 .section .debug_rnglists
 .quad 0;
 .reloc ., R_RISCV_SET_ULEB128, w2+120
@@ -106,6 +141,11 @@ w1: call foo; w2:
 
 #--- unpaired2.s
 w1: call foo; w2:
+.section .alloc,"a"
+.quad 0
+.reloc ., R_RISCV_SET_ULEB128, w2+120
+.reloc .+1, R_RISCV_SUB_ULEB128, w1
+.byte 0x7f
 .section .debug_rnglists
 .quad 0
 .reloc ., R_RISCV_SET_ULEB128, w2+120
@@ -114,6 +154,11 @@ w1: call foo; w2:
 
 #--- unpaired3.s
 w1: call foo; w2:
+.section .alloc,"a"
+.quad 0
+.reloc ., R_RISCV_SET_ULEB128, w2+120
+.reloc ., R_RISCV_SUB64, w1
+.byte 0x7f
 .section .debug_rnglists
 .quad 0
 .reloc ., R_RISCV_SET_ULEB128, w2+120
@@ -122,8 +167,21 @@ w1: call foo; w2:
 
 #--- overflow.s
 w1: call foo; w2:
+.section .alloc,"a"
+.quad 0
+.reloc ., R_RISCV_SET_ULEB128, w2+124
+.reloc ., R_RISCV_SUB_ULEB128, w1
+.byte 0x7f
 .section .debug_rnglists
 .quad 0
 .reloc ., R_RISCV_SET_ULEB128, w2+124
 .reloc ., R_RISCV_SUB_ULEB128, w1
 .byte 0x7f
+
+#--- preemptable.s
+.globl w1, w2
+w1: call foo; w2:
+.section .alloc,"a"
+.uleb128 w2-w1
+.section .debug_rnglists
+.uleb128 w2-w1

.byte 0x7f

#--- preemptable.s
.globl w1, w2
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, I'll consider making R_RISCV_ADD a constant only if !isPreemptible like R_RISCV_LEB128

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@kito-cheng kito-cheng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, LGTM :)

switch (rel.expr) {
case R_RELAX_HINT:
break;
case R_RISCV_LEB128:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll merge this soon. relocateAlloc is needed for TLSDESC relaxation as well.

@MaskRay MaskRay merged commit 3fa1795 into main Jan 9, 2024
@MaskRay MaskRay deleted the users/MaskRay/spr/elf-support-r_riscv_set_uleb128r_riscv_sub_uleb128-in-shf_alloc-sections branch January 9, 2024 04:24
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
…ctions (llvm#77261)

Complement llvm#72610 (non-SHF_ALLOC sections). GCC-generated
.gcc_exception_table has the SHF_ALLOC flag and may contain
R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.
jiegec pushed a commit to AOSC-Tracking/llvm-project that referenced this pull request Feb 13, 2024
…ctions (llvm#77261)

Complement llvm#72610 (non-SHF_ALLOC sections). GCC-generated
.gcc_exception_table has the SHF_ALLOC flag and may contain
R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.
hack3ric pushed a commit to hack3ric/llvm-project-rocm that referenced this pull request Feb 20, 2024
…ctions (llvm#77261)

Complement llvm#72610 (non-SHF_ALLOC sections). GCC-generated
.gcc_exception_table has the SHF_ALLOC flag and may contain
R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.
MingcongBai pushed a commit to AOSC-Tracking/llvm-project that referenced this pull request Mar 26, 2024
…ctions (llvm#77261)

Complement llvm#72610 (non-SHF_ALLOC sections). GCC-generated
.gcc_exception_table has the SHF_ALLOC flag and may contain
R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 relocations.
MaskRay added a commit to MaskRay/llvm-project that referenced this pull request Sep 25, 2024
…able

Call site records in .gcc_except_table reference text sections.
https://reviews.llvm.org/D63415 switched the encoding to DW_EH_PE_udata4 so that
`.uleb128 A-B`, which requires relocations in the generic case in
presence of linker relaxation, can be avoided.

binutils 2.41 and latest lld (llvm#77261) support
R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128. This patch restores
DW_EH_PE_uleb128 to make .gcc_except_table smaller. Sparc is restored as
well, which was incorrectly changed by https://reviews.llvm.org/D63415 .

emitCallSiteOffset/emitCallSiteValue should be preserved as now AIX uses
the DW_EH_PE_udata4 code path.

Pull Request: llvm#77276
tclin914 pushed a commit to tclin914/llvm-project that referenced this pull request Sep 5, 2025
Backported from:

commit 7ffabb6
Author: Fangrui Song <i@maskray.me>
Date:   Tue Nov 21 07:43:29 2023 -0800

    [ELF] Support R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 in
    non-SHF_ALLOC sections (llvm#72610)

commit 3fa1795
Author: Fangrui Song <i@maskray.me>
Date:   Mon Jan 8 20:24:00 2024 -0800

    [ELF] Support R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 in SHF_ALLOC
    sections (llvm#77261)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants