Skip to content

Commit 62213be

Browse files
authored
[LLD][RISCV] Fix incorrect call relaxation when mixing +c and -c objects (#73977)
This fixes a mis-link when mixing compressed and non-compressed input to LLD. When relaxing calls, we must respect the source file that the section came from when deciding whether it's legal to use compressed instructions. If the call in question comes from a non-rvc source, then it will not expect 2-byte alignments and cascading failures may result. This fixes #63964. The symptom seen there is that a latter RISCV_ALIGN can't be satisfied and we either fail an assert or produce a totally bogus link result. (It can be easily reproduced by putting .p2align 5 right before the nop in the reduced test case and running check-lld on an assertions enabled build.) However, it's important to note this is just one possible symptom of the problem. If the resulting binary has a runtime switch between rvc and non-rvc routines (via e.g. ifuncs), then even if we manage to link we may execute invalid instructions on a machine which doesn't implement compressed instructions.
1 parent e817966 commit 62213be

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

lld/ELF/Arch/RISCV.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,7 @@ static void initSymbolAnchors() {
591591
// Relax R_RISCV_CALL/R_RISCV_CALL_PLT auipc+jalr to c.j, c.jal, or jal.
592592
static void relaxCall(const InputSection &sec, size_t i, uint64_t loc,
593593
Relocation &r, uint32_t &remove) {
594-
const bool rvc = config->eflags & EF_RISCV_RVC;
594+
const bool rvc = getEFlags(sec.file) & EF_RISCV_RVC;
595595
const Symbol &sym = *r.sym;
596596
const uint64_t insnPair = read64le(sec.content().data() + r.offset);
597597
const uint32_t rd = extractBits(insnPair, 32 + 11, 32 + 7);
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# REQUIRES: riscv
2+
# RUN: rm -rf %t && split-file %s %t && cd %t
3+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+c,+relax a.s -o a.o
4+
# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=-c,+relax b.s -o b.o
5+
6+
# RUN: ld.lld a.o b.o --shared -o a -Ttext=0x10000
7+
# RUN: llvm-objdump -d --no-show-raw-insn -M no-aliases a | FileCheck %s
8+
9+
## This needs to be a *uncompressed* jal instruction since it came from the
10+
## source file which does not enable C
11+
# CHECK-LABEL: <foo>:
12+
# CHECK-NEXT: 10000: jal zero, {{.*}} <foo>
13+
# CHECK-NEXT: 10004: sub zero, zero, zero
14+
15+
# w/ C
16+
#--- a.s
17+
.text
18+
.attribute 4, 16
19+
.attribute 5, "rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0"
20+
21+
# w/o C
22+
#--- b.s
23+
.text
24+
.attribute 4, 16
25+
.attribute 5, "rv64i2p1_m2p0_a2p1_f2p2_d2p2_zicsr2p0_zifencei2p0"
26+
.p2align 5
27+
.type foo,@function
28+
foo:
29+
tail foo
30+
# Pick a non-canonical nop to ensure test output can't be confused
31+
# with riscv_align padding
32+
sub zero, zero, zero

0 commit comments

Comments
 (0)