[lld] [ELF] Support R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 in SHF_ALLOC sections (PR #77261)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 7 16:12:19 PST 2024


https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/77261

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.


>From 5c8e3c7f5cfc76fcd329147bbb335d9809e7460a Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Sun, 7 Jan 2024 16:12:10 -0800
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
 =?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.4
---
 lld/ELF/Arch/RISCV.cpp            | 42 ++++++++++++++++
 lld/ELF/InputSection.cpp          | 11 +----
 lld/ELF/Relocations.cpp           |  4 +-
 lld/ELF/Target.h                  | 10 ++++
 lld/test/ELF/riscv-reloc-leb128.s | 80 ++++++++++++++++++++++++++-----
 5 files changed, 124 insertions(+), 23 deletions(-)

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



More information about the llvm-commits mailing list