Skip to content

Commit 82f370a

Browse files
committed
[ELF] Support R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 in non-SHF_ALLOC sections
For a label difference like `.uleb128 A-B`, MC generates a pair of R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 if A-B cannot be folded as a constant. GNU assembler generates a pair of relocations in more cases (when A or B is in a code section with linker relaxation). `.uleb128 A-B` is primarily used by DWARF v5 .debug_loclists/.debug_rnglists (DW_LLE_offset_pair/DW_RLE_offset_pair entry kinds) implemented in Clang and GCC. `.uleb128 A-B` can be used in SHF_ALLOC sections as well (e.g. `.gcc_except_table`). This patch does not handle SHF_ALLOC. `-z dead-reloc-in-nonalloc=` can be used to change the relocated value, if the R_RISCV_SET_ULEB128 symbol is in a discarded section. We don't check the R_RISCV_SUB_ULEB128 symbol since for the expected cases A and B should be defined in the same input section.
1 parent ae7fb21 commit 82f370a

File tree

4 files changed

+170
-3
lines changed

4 files changed

+170
-3
lines changed

lld/ELF/Arch/RISCV.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
306306
case R_RISCV_TPREL_ADD:
307307
case R_RISCV_RELAX:
308308
return config->relax ? R_RELAX_HINT : R_NONE;
309+
case R_RISCV_SET_ULEB128:
310+
return R_RISCV_LEB128;
309311
default:
310312
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
311313
") against symbol " + toString(s));

lld/ELF/InputSection.cpp

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,16 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
874874
}
875875
}
876876

877+
// Overwrite a ULEB128 value and keep the original length.
878+
static uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) {
879+
while (*bufLoc & 0x80) {
880+
*bufLoc++ = 0x80 | (val & 0x7f);
881+
val >>= 7;
882+
}
883+
*bufLoc = val;
884+
return val;
885+
}
886+
877887
// This function applies relocations to sections without SHF_ALLOC bit.
878888
// Such sections are never mapped to memory at runtime. Debug sections are
879889
// an example. Relocations in non-alloc sections are much easier to
@@ -885,6 +895,7 @@ template <class ELFT, class RelTy>
885895
void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
886896
const unsigned bits = sizeof(typename ELFT::uint) * 8;
887897
const TargetInfo &target = *elf::target;
898+
const auto emachine = config->emachine;
888899
const bool isDebug = isDebugSection(*this);
889900
const bool isDebugLocOrRanges =
890901
isDebug && (name == ".debug_loc" || name == ".debug_ranges");
@@ -896,14 +907,15 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
896907
break;
897908
}
898909

899-
for (const RelTy &rel : rels) {
910+
for (size_t i = 0, relsSize = rels.size(); i != relsSize; ++i) {
911+
const RelTy &rel = rels[i];
900912
RelType type = rel.getType(config->isMips64EL);
901913

902914
// GCC 8.0 or earlier have a bug that they emit R_386_GOTPC relocations
903915
// against _GLOBAL_OFFSET_TABLE_ for .debug_info. The bug has been fixed
904916
// in 2017 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630), but we
905917
// need to keep this bug-compatible code for a while.
906-
if (config->emachine == EM_386 && type == R_386_GOTPC)
918+
if (emachine == EM_386 && type == R_386_GOTPC)
907919
continue;
908920

909921
uint64_t offset = rel.r_offset;
@@ -916,6 +928,30 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
916928
RelExpr expr = target.getRelExpr(type, sym, bufLoc);
917929
if (expr == R_NONE)
918930
continue;
931+
auto *ds = dyn_cast<Defined>(&sym);
932+
933+
if (emachine == EM_RISCV && type == R_RISCV_SET_ULEB128) {
934+
if (++i < relsSize &&
935+
rels[i].getType(/*isMips64EL=*/false) == R_RISCV_SUB_ULEB128 &&
936+
rels[i].r_offset == offset) {
937+
uint64_t val;
938+
if (!ds && tombstone) {
939+
val = *tombstone;
940+
} else {
941+
val = sym.getVA(addend) -
942+
(getFile<ELFT>()->getRelocTargetSym(rels[i]).getVA(0) +
943+
getAddend<ELFT>(rels[i]));
944+
}
945+
if (overwriteULEB128(bufLoc, val) >= 0x80)
946+
errorOrWarn(getLocation(offset) + ": ULEB128 value " + Twine(val) +
947+
" exceeds available space; references '" +
948+
lld::toString(sym) + "'");
949+
continue;
950+
}
951+
errorOrWarn(getLocation(offset) +
952+
": R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128");
953+
return;
954+
}
919955

920956
if (tombstone ||
921957
(isDebug && (type == target.symbolicRel || expr == R_DTPREL))) {
@@ -947,7 +983,6 @@ void InputSection::relocateNonAlloc(uint8_t *buf, ArrayRef<RelTy> rels) {
947983
//
948984
// TODO To reduce disruption, we use 0 instead of -1 as the tombstone
949985
// value. Enable -1 in a future release.
950-
auto *ds = dyn_cast<Defined>(&sym);
951986
if (!sym.getOutputSection() || (ds && ds->folded && !isDebugLine)) {
952987
// If -z dead-reloc-in-nonalloc= is specified, respect it.
953988
const uint64_t value = tombstone ? SignExtend64<bits>(*tombstone)

lld/ELF/Relocations.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ enum RelExpr {
101101
R_PPC64_TOCBASE,
102102
R_PPC64_RELAX_GOT_PC,
103103
R_RISCV_ADD,
104+
R_RISCV_LEB128,
104105
R_RISCV_PC_INDIRECT,
105106
// Same as R_PC but with page-aligned semantics.
106107
R_LOONGARCH_PAGE_PC,

lld/test/ELF/riscv-reloc-leb128.s

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# REQUIRES: riscv
2+
# RUN: rm -rf %t && split-file %s %t && cd %t
3+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax a.s -o a.o
4+
# RUN: llvm-readobj -r -x .debug_rnglists -x .debug_loclists a.o | FileCheck %s --check-prefix=REL
5+
# RUN: ld.lld -shared --gc-sections a.o -o a.so
6+
# RUN: llvm-readelf -x .debug_rnglists -x .debug_loclists a.so | FileCheck %s
7+
8+
# REL: .rela.debug_rnglists {
9+
# REL-NEXT: 0x0 R_RISCV_SET_ULEB128 w1 0x83
10+
# REL-NEXT: 0x0 R_RISCV_SUB_ULEB128 w2 0x0
11+
# REL-NEXT: 0x1 R_RISCV_SET_ULEB128 w2 0x78
12+
# REL-NEXT: 0x1 R_RISCV_SUB_ULEB128 w1 0x0
13+
# REL-NEXT: 0x3 R_RISCV_SET_ULEB128 w1 0x89
14+
# REL-NEXT: 0x3 R_RISCV_SUB_ULEB128 w2 0x0
15+
# REL-NEXT: 0x5 R_RISCV_SET_ULEB128 w2 0x3FF8
16+
# REL-NEXT: 0x5 R_RISCV_SUB_ULEB128 w1 0x0
17+
# REL-NEXT: 0x8 R_RISCV_SET_ULEB128 w1 0x4009
18+
# REL-NEXT: 0x8 R_RISCV_SUB_ULEB128 w2 0x0
19+
# REL-NEXT: 0xB R_RISCV_SET_ULEB128 w2 0x1FFFF8
20+
# REL-NEXT: 0xB R_RISCV_SUB_ULEB128 w1 0x0
21+
# REL-NEXT: 0xF R_RISCV_SET_ULEB128 w1 0x200009
22+
# REL-NEXT: 0xF R_RISCV_SUB_ULEB128 w2 0x0
23+
# REL-NEXT: }
24+
# REL: .rela.debug_loclists {
25+
# REL-NEXT: 0x0 R_RISCV_SET_ULEB128 w2 0x3
26+
# REL-NEXT: 0x0 R_RISCV_SUB_ULEB128 w1 0x4
27+
# REL-NEXT: 0x1 R_RISCV_SET_ULEB128 x2 0x0
28+
# REL-NEXT: 0x1 R_RISCV_SUB_ULEB128 x1 0x0
29+
# REL-NEXT: }
30+
31+
# REL: Hex dump of section '.debug_rnglists':
32+
# REL-NEXT: 0x00000000 7b800181 01808001 81800180 80800181 {
33+
# REL-NEXT: 0x00000010 808001 .
34+
# REL: Hex dump of section '.debug_loclists':
35+
# REL-NEXT: 0x00000000 0008 .
36+
37+
# CHECK: Hex dump of section '.debug_rnglists':
38+
# CHECK-NEXT: 0x00000000 7ffc0085 01fcff00 858001fc ffff0085 .
39+
# CHECK-NEXT: 0x00000010 808001 .
40+
# CHECK: Hex dump of section '.debug_loclists':
41+
# CHECK-NEXT: 0x00000000 0300 .
42+
43+
# RUN: ld.lld -shared --gc-sections -z dead-reloc-in-nonalloc=.debug_loclists=0x7f a.o -o a127.so
44+
# RUN: llvm-readelf -x .debug_loclists a127.so | FileCheck %s --check-prefix=CHECK127
45+
# CHECK127: Hex dump of section '.debug_loclists':
46+
# CHECK127-NEXT: 0x00000000 037f .
47+
48+
# RUN: not ld.lld -shared --gc-sections -z dead-reloc-in-nonalloc=.debug_loclists=0x80 a.o 2>&1 | FileCheck %s --check-prefix=CHECK128
49+
# CHECK128: error: a.o:(.debug_loclists+0x1): ULEB128 value 128 exceeds available space; references 'x2'
50+
51+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax sub.s -o sub.o
52+
# RUN: not ld.lld -shared sub.o 2>&1 | FileCheck %s --check-prefix=SUB
53+
# SUB: error: sub.o:(.debug_rnglists+0x8): unknown relocation (61) against symbol w2
54+
55+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax unpaired1.s -o unpaired1.o
56+
# RUN: not ld.lld -shared unpaired1.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
57+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax unpaired2.s -o unpaired2.o
58+
# RUN: not ld.lld -shared unpaired2.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
59+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax unpaired3.s -o unpaired3.o
60+
# RUN: not ld.lld -shared unpaired3.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
61+
# UNPAIRED: error: {{.*}}.o:(.debug_rnglists+0x8): R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128
62+
63+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax overflow.s -o overflow.o
64+
# RUN: not ld.lld -shared overflow.o 2>&1 | FileCheck %s --check-prefix=OVERFLOW
65+
# OVERFLOW: error: overflow.o:(.debug_rnglists+0x8): ULEB128 value 128 exceeds available space; references 'w2'
66+
67+
#--- a.s
68+
.section .text.w,"axR"
69+
w1:
70+
call foo # 4 bytes after relaxation
71+
w2:
72+
73+
.section .text.x,"ax"
74+
x1:
75+
call foo # 4 bytes after relaxation
76+
x2:
77+
78+
.section .debug_rnglists
79+
.uleb128 w1-w2+131 # initial value: 0x7b
80+
.uleb128 w2-w1+120 # initial value: 0x0180
81+
.uleb128 w1-w2+137 # initial value: 0x0181
82+
.uleb128 w2-w1+16376 # initial value: 0x018080
83+
.uleb128 w1-w2+16393 # initial value: 0x018081
84+
.uleb128 w2-w1+2097144 # initial value: 0x01808080
85+
.uleb128 w1-w2+2097161 # initial value: 0x01808081
86+
87+
.section .debug_loclists
88+
.reloc ., R_RISCV_SET_ULEB128, w2+3
89+
.reloc ., R_RISCV_SUB_ULEB128, w1+4 # SUB with a non-zero addend
90+
.byte 0
91+
.uleb128 x2-x1 # references discarded symbols
92+
93+
#--- sub.s
94+
w1: call foo; w2:
95+
.section .debug_rnglists
96+
.quad 0;
97+
.reloc ., R_RISCV_SUB_ULEB128, w2+120
98+
.byte 0x7f
99+
100+
#--- unpaired1.s
101+
w1: call foo; w2:
102+
.section .debug_rnglists
103+
.quad 0;
104+
.reloc ., R_RISCV_SET_ULEB128, w2+120
105+
.byte 0x7f
106+
107+
#--- unpaired2.s
108+
w1: call foo; w2:
109+
.section .debug_rnglists
110+
.quad 0
111+
.reloc ., R_RISCV_SET_ULEB128, w2+120
112+
.reloc .+1, R_RISCV_SUB_ULEB128, w1
113+
.byte 0x7f
114+
115+
#--- unpaired3.s
116+
w1: call foo; w2:
117+
.section .debug_rnglists
118+
.quad 0
119+
.reloc ., R_RISCV_SET_ULEB128, w2+120
120+
.reloc ., R_RISCV_SUB64, w1
121+
.byte 0x7f
122+
123+
#--- overflow.s
124+
w1: call foo; w2:
125+
.section .debug_rnglists
126+
.quad 0
127+
.reloc ., R_RISCV_SET_ULEB128, w2+124
128+
.reloc ., R_RISCV_SUB_ULEB128, w1
129+
.byte 0x7f

0 commit comments

Comments
 (0)