[lld] [ELF] Support R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 in SHF_ALLOC sections (PR #77261)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jan 7 16:12:49 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld
Author: Fangrui Song (MaskRay)
<details>
<summary>Changes</summary>
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
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/77261
More information about the llvm-commits
mailing list