Skip to content

Commit 081bc7e

Browse files
MaskRayMingcongBai
authored andcommitted
[ELF] Support R_RISCV_SET_ULEB128/R_RISCV_SUB_ULEB128 in SHF_ALLOC sections (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.
1 parent 40a7340 commit 081bc7e

File tree

5 files changed

+124
-23
lines changed

5 files changed

+124
-23
lines changed

lld/ELF/Arch/RISCV.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class RISCV final : public TargetInfo {
4343
const uint8_t *loc) const override;
4444
void relocate(uint8_t *loc, const Relocation &rel,
4545
uint64_t val) const override;
46+
void relocateAlloc(InputSectionBase &sec, uint8_t *buf) const override;
4647
bool relaxOnce(int pass) const override;
4748
};
4849

@@ -307,6 +308,7 @@ RelExpr RISCV::getRelExpr(const RelType type, const Symbol &s,
307308
case R_RISCV_RELAX:
308309
return config->relax ? R_RELAX_HINT : R_NONE;
309310
case R_RISCV_SET_ULEB128:
311+
case R_RISCV_SUB_ULEB128:
310312
return R_RISCV_LEB128;
311313
default:
312314
error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
@@ -515,6 +517,46 @@ void RISCV::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
515517
}
516518
}
517519

520+
void RISCV::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const {
521+
uint64_t secAddr = sec.getOutputSection()->addr;
522+
if (auto *s = dyn_cast<InputSection>(&sec))
523+
secAddr += s->outSecOff;
524+
else if (auto *ehIn = dyn_cast<EhInputSection>(&sec))
525+
secAddr += ehIn->getParent()->outSecOff;
526+
for (size_t i = 0, size = sec.relocs().size(); i != size; ++i) {
527+
const Relocation &rel = sec.relocs()[i];
528+
uint8_t *loc = buf + rel.offset;
529+
const uint64_t val =
530+
sec.getRelocTargetVA(sec.file, rel.type, rel.addend,
531+
secAddr + rel.offset, *rel.sym, rel.expr);
532+
533+
switch (rel.expr) {
534+
case R_RELAX_HINT:
535+
break;
536+
case R_RISCV_LEB128:
537+
if (i + 1 < size) {
538+
const Relocation &rel1 = sec.relocs()[i + 1];
539+
if (rel.type == R_RISCV_SET_ULEB128 &&
540+
rel1.type == R_RISCV_SUB_ULEB128 && rel.offset == rel1.offset) {
541+
auto val = rel.sym->getVA(rel.addend) - rel1.sym->getVA(rel1.addend);
542+
if (overwriteULEB128(loc, val) >= 0x80)
543+
errorOrWarn(sec.getLocation(rel.offset) + ": ULEB128 value " +
544+
Twine(val) + " exceeds available space; references '" +
545+
lld::toString(*rel.sym) + "'");
546+
++i;
547+
continue;
548+
}
549+
}
550+
errorOrWarn(sec.getLocation(rel.offset) +
551+
": R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128");
552+
return;
553+
default:
554+
relocate(loc, rel, val);
555+
break;
556+
}
557+
}
558+
}
559+
518560
namespace {
519561
struct SymbolAnchor {
520562
uint64_t offset;

lld/ELF/InputSection.cpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
635635
case R_RELAX_TLS_LD_TO_LE_ABS:
636636
case R_RELAX_GOT_PC_NOPIC:
637637
case R_RISCV_ADD:
638+
case R_RISCV_LEB128:
638639
return sym.getVA(a);
639640
case R_ADDEND:
640641
return a;
@@ -839,16 +840,6 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
839840
}
840841
}
841842

842-
// Overwrite a ULEB128 value and keep the original length.
843-
static uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) {
844-
while (*bufLoc & 0x80) {
845-
*bufLoc++ = 0x80 | (val & 0x7f);
846-
val >>= 7;
847-
}
848-
*bufLoc = val;
849-
return val;
850-
}
851-
852843
// This function applies relocations to sections without SHF_ALLOC bit.
853844
// Such sections are never mapped to memory at runtime. Debug sections are
854845
// an example. Relocations in non-alloc sections are much easier to

lld/ELF/Relocations.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -971,8 +971,8 @@ bool RelocationScanner::isStaticLinkTimeConstant(RelExpr e, RelType type,
971971
if (!config->isPic)
972972
return true;
973973

974-
// The size of a non preemptible symbol is a constant.
975-
if (e == R_SIZE)
974+
// Constant when referencing a non-preemptible symbol.
975+
if (e == R_SIZE || e == R_RISCV_LEB128)
976976
return true;
977977

978978
// For the target and the relocation, we want to know if they are

lld/ELF/Target.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,16 @@ inline void write32(void *p, uint32_t v) {
299299
inline void write64(void *p, uint64_t v) {
300300
llvm::support::endian::write64(p, v, config->endianness);
301301
}
302+
303+
// Overwrite a ULEB128 value and keep the original length.
304+
inline uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) {
305+
while (*bufLoc & 0x80) {
306+
*bufLoc++ = 0x80 | (val & 0x7f);
307+
val >>= 7;
308+
}
309+
*bufLoc = val;
310+
return val;
311+
}
302312
} // namespace elf
303313
} // namespace lld
304314

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

Lines changed: 69 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# REQUIRES: riscv
22
# RUN: rm -rf %t && split-file %s %t && cd %t
33
# 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
4+
# RUN: llvm-readobj -r -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a.o | FileCheck %s --check-prefix=REL
5+
# RUN: ld.lld -shared --gc-sections --noinhibit-exec a.o -o a.so
6+
# RUN: llvm-readelf -x .gcc_except_table -x .debug_rnglists -x .debug_loclists a.so | FileCheck %s
77

88
# REL: .rela.debug_rnglists {
9-
# REL-NEXT: 0x0 R_RISCV_SET_ULEB128 w1 0x83
10-
# REL-NEXT: 0x0 R_RISCV_SUB_ULEB128 w2 0x0
9+
# REL-NEXT: 0x0 R_RISCV_SET_ULEB128 w1 0x82
10+
# REL-NEXT: 0x0 R_RISCV_SUB_ULEB128 w2 0xFFFFFFFFFFFFFFFF
1111
# REL-NEXT: 0x1 R_RISCV_SET_ULEB128 w2 0x78
1212
# REL-NEXT: 0x1 R_RISCV_SUB_ULEB128 w1 0x0
1313
# REL-NEXT: 0x3 R_RISCV_SET_ULEB128 w1 0x89
@@ -28,12 +28,18 @@
2828
# REL-NEXT: 0x1 R_RISCV_SUB_ULEB128 x1 0x0
2929
# REL-NEXT: }
3030

31+
# REL: Hex dump of section '.gcc_except_table':
32+
# REL-NEXT: 0x00000000 7b800181 01808001 81800180 80800181 {
33+
# REL-NEXT: 0x00000010 808001 .
3134
# REL: Hex dump of section '.debug_rnglists':
3235
# REL-NEXT: 0x00000000 7b800181 01808001 81800180 80800181 {
3336
# REL-NEXT: 0x00000010 808001 .
3437
# REL: Hex dump of section '.debug_loclists':
3538
# REL-NEXT: 0x00000000 0008 .
3639

40+
# CHECK: Hex dump of section '.gcc_except_table':
41+
# CHECK-NEXT: 0x[[#%x,]] 7ffc0085 01fcff00 858001fc ffff0085 .
42+
# CHECK-NEXT: 0x[[#%x,]] 808001 .
3743
# CHECK: Hex dump of section '.debug_rnglists':
3844
# CHECK-NEXT: 0x00000000 7ffc0085 01fcff00 858001fc ffff0085 .
3945
# CHECK-NEXT: 0x00000010 808001 .
@@ -50,21 +56,32 @@
5056

5157
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax sub.s -o sub.o
5258
# 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
59+
# SUB: error: sub.o:(.debug_rnglists+0x8): has non-ABS relocation R_RISCV_SUB_ULEB128 against symbol 'w2'
5460

5561
# 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
62+
# RUN: not ld.lld -shared --threads=1 unpaired1.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
5763
# 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
64+
# RUN: not ld.lld -shared --threads=1 unpaired2.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
5965
# 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
66+
# RUN: not ld.lld -shared --threads=1 unpaired3.o 2>&1 | FileCheck %s --check-prefix=UNPAIRED
67+
# UNPAIRED: error: {{.*}}.o:(.alloc+0x8): R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128
6168
# UNPAIRED: error: {{.*}}.o:(.debug_rnglists+0x8): R_RISCV_SET_ULEB128 not paired with R_RISCV_SUB_SET128
6269

6370
# 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
71+
# RUN: not ld.lld -shared --threads=1 overflow.o 2>&1 | FileCheck %s --check-prefix=OVERFLOW
72+
# OVERFLOW: error: overflow.o:(.alloc+0x8): ULEB128 value 128 exceeds available space; references 'w2'
6573
# OVERFLOW: error: overflow.o:(.debug_rnglists+0x8): ULEB128 value 128 exceeds available space; references 'w2'
6674

75+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax preemptable.s -o preemptable.o
76+
# RUN: not ld.lld -shared --threads=1 preemptable.o 2>&1 | FileCheck %s --check-prefix=PREEMPTABLE --implicit-check-not=error:
77+
# PREEMPTABLE: error: relocation R_RISCV_SET_ULEB128 cannot be used against symbol 'w2'; recompile with -fPIC
78+
# PREEMPTABLE: error: relocation R_RISCV_SUB_ULEB128 cannot be used against symbol 'w1'; recompile with -fPIC
79+
6780
#--- a.s
81+
.cfi_startproc
82+
.cfi_lsda 0x1b,.LLSDA0
83+
.cfi_endproc
84+
6885
.section .text.w,"axR"
6986
w1:
7087
call foo # 4 bytes after relaxation
@@ -75,8 +92,22 @@ x1:
7592
call foo # 4 bytes after relaxation
7693
x2:
7794

95+
.section .gcc_except_table,"a"
96+
.LLSDA0:
97+
.reloc ., R_RISCV_SET_ULEB128, w1+130
98+
.reloc ., R_RISCV_SUB_ULEB128, w2-1 # non-zero addend for SUB
99+
.byte 0x7b
100+
.uleb128 w2-w1+120 # initial value: 0x0180
101+
.uleb128 w1-w2+137 # initial value: 0x0181
102+
.uleb128 w2-w1+16376 # initial value: 0x018080
103+
.uleb128 w1-w2+16393 # initial value: 0x018081
104+
.uleb128 w2-w1+2097144 # initial value: 0x01808080
105+
.uleb128 w1-w2+2097161 # initial value: 0x01808081
106+
78107
.section .debug_rnglists
79-
.uleb128 w1-w2+131 # initial value: 0x7b
108+
.reloc ., R_RISCV_SET_ULEB128, w1+130
109+
.reloc ., R_RISCV_SUB_ULEB128, w2-1 # non-zero addend for SUB
110+
.byte 0x7b
80111
.uleb128 w2-w1+120 # initial value: 0x0180
81112
.uleb128 w1-w2+137 # initial value: 0x0181
82113
.uleb128 w2-w1+16376 # initial value: 0x018080
@@ -99,13 +130,22 @@ w1: call foo; w2:
99130

100131
#--- unpaired1.s
101132
w1: call foo; w2:
133+
.section .alloc,"a"
134+
.quad 0
135+
.reloc ., R_RISCV_SET_ULEB128, w2+120
136+
.byte 0x7f
102137
.section .debug_rnglists
103138
.quad 0;
104139
.reloc ., R_RISCV_SET_ULEB128, w2+120
105140
.byte 0x7f
106141

107142
#--- unpaired2.s
108143
w1: call foo; w2:
144+
.section .alloc,"a"
145+
.quad 0
146+
.reloc ., R_RISCV_SET_ULEB128, w2+120
147+
.reloc .+1, R_RISCV_SUB_ULEB128, w1
148+
.byte 0x7f
109149
.section .debug_rnglists
110150
.quad 0
111151
.reloc ., R_RISCV_SET_ULEB128, w2+120
@@ -114,6 +154,11 @@ w1: call foo; w2:
114154

115155
#--- unpaired3.s
116156
w1: call foo; w2:
157+
.section .alloc,"a"
158+
.quad 0
159+
.reloc ., R_RISCV_SET_ULEB128, w2+120
160+
.reloc ., R_RISCV_SUB64, w1
161+
.byte 0x7f
117162
.section .debug_rnglists
118163
.quad 0
119164
.reloc ., R_RISCV_SET_ULEB128, w2+120
@@ -122,8 +167,21 @@ w1: call foo; w2:
122167

123168
#--- overflow.s
124169
w1: call foo; w2:
170+
.section .alloc,"a"
171+
.quad 0
172+
.reloc ., R_RISCV_SET_ULEB128, w2+124
173+
.reloc ., R_RISCV_SUB_ULEB128, w1
174+
.byte 0x7f
125175
.section .debug_rnglists
126176
.quad 0
127177
.reloc ., R_RISCV_SET_ULEB128, w2+124
128178
.reloc ., R_RISCV_SUB_ULEB128, w1
129179
.byte 0x7f
180+
181+
#--- preemptable.s
182+
.globl w1, w2
183+
w1: call foo; w2:
184+
.section .alloc,"a"
185+
.uleb128 w2-w1
186+
.section .debug_rnglists
187+
.uleb128 w2-w1

0 commit comments

Comments
 (0)